routine-anlegen
Der Klon-Skill fuer agents-platform. Eine neue Cron-Lambda-Routine ist ein Beleg-Pipeline-Klon mit anderen Permissions und anderem Handler-Body — der Rest ist Boilerplate. Dieser Skill macht den Boilerplate-Teil und laesst Marvin sich auf den eigentlichen Logik-Code konzentrieren.
Reference-Implementierung: _index (Beleg-Pipeline, Session 1 abgeschlossen 2026-05-12). Code-Layout, IAM-Pattern, CDK-Construct, Layer-Imports — alles dort live und durchgemartert.
Geltungsbereich: Cron-getriggerte Lambdas, Python 3.12 ARM_64, in av-production eu-central-1, mit Layer agentic-common. Kein HTTP-API. Kein Multi-Region. Kein eigenes Stack-Pattern erfinden — der AgenticVenturesAgent-Construct in infra/lib/agent-construct.ts wird wiederverwendet.
Wann nutze ich diesen Skill
- „Bau mir eine Routine die jeden Morgen X macht.”
- „Ich brauch einen Cron-Agent fuer Y.”
- „Lambda fuer Z anlegen.”
- „Wie Beleg-Pipeline aber fuer ABC.”
Wenn der Anwendungsfall kein Cron ist (interaktiver Chat-Agent, Multi-Turn-Memory, HTTP-API) → dieser Skill ist falsch, statt dessen mcp-eigenbau oder eine eigene Plattform-Entscheidung.
Ablauf
Phase 1: Brief sammeln (6 Rueckfragen, eine nach der anderen)
Phase 2: Generierung (Lambda + Stack + Vault-Doku)
Phase 3: Deploy + Smoke (Local + Lambda + Telegram-Push)
Marvin kann jederzeit „stop” sagen — der Skill bricht ab, ohne Halbfertiges zu deployen.
Phase 1: Brief sammeln
Wichtig: eine Frage nach der anderen. Nicht alle 6 auf einmal stellen. Marvin hat ADHS-Setup — kleine Schritte, jede Antwort kurz, naechste Frage kommt nach Bestaetigung. Antworten in Scratchpad oder TodoWrite-Notes halten.
Frage 1 — Identitaet
Wie soll die Routine heissen (Slug in kebab-case, z.B.
email-summary,kalender-check,papierkram-sync)? Und in einem Satz: was macht sie?
Validieren:
- Slug ist kebab-case, keine Umlaute, keine Sonderzeichen ausser
- - Slug ist nicht bereits in
~/source/agents-platform/lambdas/als Ordner vorhanden - Slug ist nicht bereits in
infra/bin/app.tsals Stack-Instanzierung referenziert
Frage 2 — Trigger
Welcher Schedule? Beispiele:
alle 15 Min,taeglich 7:00 Berlin,Mo-Fr 9:00,1. jeden Monats 8:00, odermanuell-only(kein Cron, nur on-demand-Invoke)?
In EventBridge-Cron-Syntax umsetzen (Berlin → UTC! AWS Cron ist UTC). Beispiele:
alle 15 Min→events.Schedule.cron({ minute: '0/15' })taeglich 7:00 Berlin→ im Sommercron({ hour: '5', minute: '0' }), im Wintercron({ hour: '6', minute: '0' })— Hinweis: AWS Cron kennt keine Timezone, ggf. zwei Schedules oder fixe UTC-ZeitMo-Fr 9:00 Berlin→cron({ minute: '0', hour: '7', weekDay: 'MON-FRI' })(Sommerzeit angenommen)manuell-only→ keine EventBridge-Rule, nur Lambda + manueller Invoke
Frage 3 — Datenquellen
Welche externen Tools / APIs ruft die Routine? Beispiele:
- gsuite: Gmail-Pull, Calendar-Read, Drive-Read
- papierkram: Voucher/Invoice anlegen, lesen
- m365: SharePoint-Files, Excel, Outlook
- ticketpay: Order-Listen
- Bedrock: LLM-Calls (Klassifikation, Summary)
- AWS-S3: Files lesen/schreiben
- Externes (z.B. GitHub, OpenWeather, custom API)
Wichtig zu klaeren:
- gsuite: welches Konto? hello@ oder marvinkuehlmann@? (siehe Gmail-OAuth-Secret-Bundle)
- papierkram/ticketpay/m365: ueber den hosted
mcp-vfEndpoint (PAPIERKRAM_MCP_URLEnv-Var) oder direkt API? - S3: welcher Bucket? Lesen / Schreiben / beides?
Mapping zu IAM-Permissions im Stack:
- gsuite →
secretsmanager:GetSecretValueaufagent-platform/gmail-oauth-refresh-* - Bedrock → schon im AgenticVenturesAgent-Construct vorhanden (Haiku-4.5 Default), bei anderem Modell selber adden
- S3-Read →
s3:GetObject+s3:ListBucket - S3-Write →
s3:PutObject+s3:PutObjectTagging+ KMS-Key (wenn Bucket verschluesselt) - MCP-Hosted → keine extra Permissions, nur HTTP-Call (Token kommt aus Scalekit, das laeuft eh ueber den hosted Endpoint)
Frage 4 — Verarbeitung
Was muss die Routine intern tun? Konkret:
- Bedrock-LLM-Call? Ja/Nein. Falls ja: kurz beschreiben — Klassifikation, Summary, Extraktion? Welches Schema kommt raus?
- PDF/HTML-Parsing? Ja/Nein.
- Cross-Account-Schreibzugriff (nach
mk-privatper AssumeRole)?- State zwischen Runs (z.B. „seen IDs” in S3/DynamoDB) oder stateless?
Wenn PDF: pypdfium2 als Dependency, Layer-Build muss pip install -r requirements.txt -t /asset-output/python im CDK adden — derzeit ist der Layer Plain-Python. Skill warnt: „Layer-Build-Erweiterung erstmalig noetig — alternativ Dependency im Lambda-Bundle statt Layer.” → Marvin entscheidet.
Wenn State: schlag S3 + JSON-File vor (einfach, kein extra Service). DynamoDB nur wenn high-frequency reads.
Frage 5 — Outputs
Was passiert am Run-Ende? Default ist Telegram-Push immer. Plus zusaetzlich:
- S3-Upload (welcher Bucket / Prefix)?
- Email an dich (welcher Account, welches Format)?
- Vault-Stub ueber GitHub-API (welcher Pfad im
agentic-ventures-Repo)?- Calendar-Event ueber gsuite-MCP?
- Papierkram-Voucher ueber
mcp-vf?- Nichts ausser Telegram = ok, oft reicht das.
Telegram-Push-Format ist standardisiert (siehe telegram-push-konvention): TelegramReport mit successes, pendings, errors, deep_links. Skill packt diese Pattern im Handler-Skeleton automatisch.
Frage 6 — Neue Secrets
Brauchen wir neue Secrets in AWS Secrets Manager (zusaetzlich zu Telegram-Bot-Token, Gmail-OAuth-Refresh, GitHub-PAT die schon angelegt sind)? Beispiele:
- API-Keys fuer externe APIs (OpenAI, Replicate, GitHub-App-Private-Key, etc.)
- Service-Tokens (Stripe, Sendgrid, etc.)
Wenn ja: pro Secret den Namen abfragen (agent-platform/<name> Schema). Skill legt aws secretsmanager create-secret mit Placeholder-Wert an, Marvin tippt echte Werte separat.
Keine Geheimnisse in der Frage tippen lassen! Marvin kriegt nach create-secret den put-secret-value-Befehl als Copy-Paste mit <token> Platzhalter.
Phase 2: Generierung
Vorab: TodoWrite-Liste mit 8 Items anlegen (Files + Smoke + Deploy + Commit). Status laufend aktualisieren.
2.1 Lambda-Handler
lambdas/<slug>/main.py schreiben. Template:
"""
<slug> — <1-Satz-Zweck>.
Trigger: <Schedule oder manuell>
Outputs: <Liste>
"""
import os
import time
import traceback
from agentic_common.logging import get_logger, new_run_id
from agentic_common import secrets
from agentic_common.telegram import TelegramReport, push
# from agentic_common.bedrock import BedrockClassifier # nur wenn Bedrock genutzt
AGENT_NAME = os.environ.get("AGENT_NAME", "<slug>")
def handler(event: dict, context) -> dict:
run_id = new_run_id()
logger = get_logger(AGENT_NAME, run_id=run_id)
logger.info("invocation_start", "Cron getriggert", data={
"trigger": event.get("source", "manual"),
"request_id": getattr(context, "aws_request_id", "unknown"),
})
report = TelegramReport(agent_name=AGENT_NAME)
try:
# === PIPELINE-LOGIK HIER ===
# Beispiele:
# - secrets.get("agent-platform/...") fuer Token
# - Bedrock-Call via BedrockClassifier
# - HTTP-Call zu mcp-vf.agenticventures.de/mcp
# - S3-Upload via boto3
# - report.successes.append(...) / report.errors.append(...)
pass
except Exception as exc:
logger.error("pipeline", "Pipeline-Fehler", data={"error": str(exc), "trace": traceback.format_exc()[:500]})
report.errors.append(f"Pipeline-Fehler: {exc}")
# Telegram-Push
push_status = {"sent": False}
try:
bot_token = secrets.get(os.environ["TELEGRAM_SECRET_NAME"])
chat_id = os.environ["TELEGRAM_CHAT_ID"]
api_response = push(report, bot_token, chat_id)
push_status = {"sent": True, "message_id": api_response["result"]["message_id"]}
logger.info("telegram_push", "Push raus", data=push_status)
except Exception as exc:
push_status = {"sent": False, "error": str(exc)}
logger.error("telegram_push", "Push fehlgeschlagen", data=push_status)
result = {
"agent": AGENT_NAME,
"run_id": run_id,
"status": "ok" if (push_status["sent"] and not report.errors) else "degraded",
"telegram_sent": push_status["sent"],
"errors_count": len(report.errors),
}
logger.info("invocation_end", "Run beendet", data=result)
return resultlambdas/<slug>/requirements.txt mit Kommentar-Liste — Inhalt nur wenn Lambda-Build pip-Install macht. Aktuell laeuft alles ueber stdlib + boto3 + urllib3 (im Runtime preinstalled).
2.2 Stack
infra/lib/<slug>-stack.ts — kopiere beleg-pipeline-stack.ts als Template, passe an:
- Props-Interface: nur die Secrets/Buckets/Roles die diese Routine braucht
AgenticVenturesAgent-Aufruf mit eigenemname,schedule,codePathenvironment-Vars: pro Output/Datenquelle die passenden Namenpermissions-Array: pro Output/Datenquelle die passendeniam.PolicyStatements
Hardcoded Defaults (Fallstrick-Schutz, KEIN re-debug noetig):
- Bedrock-Permissions sind schon im
AgenticVenturesAgent-Construct (alle Agents duerfen Haiku-4.5 invoken) - Secrets-Manager-ARN-Pattern: mit
-*Suffix (zufaelliges 6-char-Suffix pro Secret) - Inference-Profile-ARN:
arn:aws:bedrock:eu-*:<account>:inference-profile/eu.anthropic.claude-haiku-4-5-*(mit Account-ID-Slot, weil Cross-Region-Profiles per-Account materialisiert sind) - BEDROCK_MODEL_ID:
eu.anthropic.claude-haiku-4-5-20251001-v1:0(mit Date-Tag!) - Memory-Default: 512 MB (1024 nur wenn PDF-Parsing)
- Timeout-Default: 5 Min (10 Min wenn Bedrock + grosse Pipelines)
2.3 App-Entry
infra/bin/app.ts — neue Stack-Instanzierung adden, analog zu BelegPipelineStack. Account/Region wiederverwenden (avProductionEnv-Konstante).
2.4 Vault-Doku
intern/projekte/<slug>/_index.md als Projekt-Stub:
---
id: project-<slug>
type: project
name: "<Routine-Name>"
status: skeleton-deployed
description: "<1-Satz-Zweck>"
last_reviewed: <heute>
visibility: internal
schedule: "<Schedule>"
stack: "<slug>Stack in av-production"
---
# <Routine-Name>
## Was sie macht
<Brief-Antworten zusammenfassen>
## Architektur
<Datenquellen → Verarbeitung → Outputs als Diagramm oder Liste>
## Stand <heute>
| Komponente | Status |
|---|---|
| Stack deployed | ✅ |
| Smoke-Test gruen | ✅ |
| Pipeline-Logik | <Status> |
## Related
- [[../../capabilities/agents-platform]]2.5 Capabilities-Update
intern/capabilities/agents-platform.md — Tabellen-Eintrag in „Aktive Agents”:
| `agent-<slug>` | `<Schedule>` | <1-Satz-Zweck> | <Stand> |2.6 Secrets (falls Phase 1 Frage 6 = ja)
Pro neuem Secret:
aws --profile av-production --region eu-central-1 secretsmanager create-secret \
--name "agent-platform/<name>" \
--description "<Zweck>" \
--secret-string "<placeholder-replace-via-put-secret-value>"Danach Marvin den put-secret-value-Befehl als Copy-Paste mit Token-Platzhalter geben — er tippt selber.
Phase 3: Deploy + Smoke
3.1 Local-Smoke
Wenn moeglich, Handler lokal aufrufen:
cd ~/source/agents-platform/lambdas/<slug>
PYTHONPATH=~/source/agents-platform/layers/agentic-common/python \
AWS_PROFILE=av-production AWS_REGION=eu-central-1 \
TELEGRAM_CHAT_ID=8257793678 \
TELEGRAM_SECRET_NAME=agent-platform/telegram-bot-token \
AGENT_NAME=<slug>-localsmoke \
python3 -c "
import main
class FakeContext: aws_request_id = 'local-smoke'
print(main.handler({'source': 'local'}, FakeContext()))
"Wenn Smoke fehlschlaegt: stoppen, fixen, Marvin informieren. Nicht deployen.
3.2 cdk synth
cd ~/source/agents-platform/infra && \
AWS_PROFILE=av-production npx cdk synth <slug>StackCompile-Errors → fixen. Nie deployen wenn synth nicht durchlaeuft.
3.3 cdk deploy
cd ~/source/agents-platform/infra && \
AWS_PROFILE=av-production AWS_REGION=eu-central-1 \
npx cdk deploy <slug>Stack --require-approval never--require-approval never ist sicher solange der Stack nur die Standard-Pattern nutzt (keine neue Role mit AssumeRole-Trust nach fremden Accounts). Wenn der Stack so was hat: erst cdk diff zeigen, Marvin bestaetigt.
3.4 Lambda-Invoke + CloudWatch
aws --profile av-production --region eu-central-1 lambda invoke \
--function-name agent-<slug> \
--cli-binary-format raw-in-base64-out \
--payload '{"source":"manual-smoke"}' \
/tmp/<slug>-invoke.json
cat /tmp/<slug>-invoke.json | python3 -m json.tool
sleep 5
aws --profile av-production --region eu-central-1 logs tail \
/aws/lambda/agent-<slug> --since 2m --format shortPruefen:
StatusCode: 200- Result
status: "ok" - CloudWatch zeigt strukturierte JSON-Logs mit
run_id,step,level - Telegram-Push ist im Marvin’s Chat angekommen (er guckt aufs Phone)
3.5 Commit
cd ~/source/agents-platform && \
git add lambdas/<slug>/ infra/lib/<slug>-stack.ts infra/bin/app.ts && \
git commit -m "feat: <slug> Cron-Routine
<1-Satz-Zweck>. Schedule: <Schedule>. Deploy + Smoke gruen."Push: Sandbox blockt direkten Push auf main. Skill gibt Marvin den exakten Befehl als Copy-Paste:
cd ~/source/agents-platform && git push origin main3.6 Run-Log
intern/runs/<jahr>-<monat>.md ergaenzen — eine Zeile:
- **<datum>** routine-anlegen: `<slug>` deployed. Schedule `<Schedule>`. Brief-Phase X Min, Generierung Y Min, Deploy + Smoke Z Min.Hardcoded Defaults (Session-1-Lessons-Learned)
Diese Werte sind nicht verhandelbar, weil sie auf Bugs basieren die wir schon einmal live entdeckt haben:
| Setting | Wert | Grund |
|---|---|---|
BEDROCK_MODEL_ID | eu.anthropic.claude-haiku-4-5-20251001-v1:0 | Date-Tag im ID, sonst Invalid Model Identifier |
| Inference-Profile-ARN | arn:aws:bedrock:eu-*:<account>:inference-profile/eu.anthropic.claude-haiku-4-5-* | Cross-Region-Profiles sind per-Account, Account-Slot Pflicht |
| Foundation-Model-ARN | arn:aws:bedrock:eu-*::foundation-model/anthropic.claude-haiku-4-5-* | Foundation-Models sind service-owned, kein Account-Slot |
| Secrets-Manager-ARN | arn:aws:secretsmanager:eu-central-1:<account>:secret:agent-platform/<name>-* | -* Pflicht — zufaelliges 6-char-Suffix pro Secret |
| Lambda-Runtime | Python 3.12 ARM_64 | Graviton 20% billiger, Layer ist auf ARM_64 gepackt |
| HTTP-Library | urllib3 (preinstalled mit boto3) | Spart Layer-pip-Bundling, httpx erst wenn echtes Bedarf da |
| Telegram-Format | parse_mode=None (plain text) | Vermeidet Markdown-V2-Escape-Hoelle, URLs sind eh clickable |
Was der Skill NICHT macht
- Keine Multi-Region-Stacks. Alles in
eu-central-1. Wenn US-Region noetig: separater Skill. - Keine Multi-Account-Stacks. Alles in
av-production. Cross-Account-Schreibzugriff per AssumeRole (z.B. nachmk-privat). - Keine HTTP-API-Endpoints / API-Gateway. Routinen sind Cron-getriggert oder manuell.
- Keine neuen Layer-Module bauen. Wenn die Routine was Neues braucht (z.B.
gmail.py,pdf.py,mcp_client.py): erstmal als lokales Modul inlambdas/<slug>/. Wenn drei Routinen dasselbe Modul brauchen, manuell inagentic-commonextrahieren — nicht automatisch. - Kein automatischer
git push. Sandbox blockt. Skill gibt Marvin Copy-Paste-Befehl. - Keine Phase-1-Frage-Abkuerzung. Marvin muss alle 6 Antworten geben — sonst fehlt das Skeleton-Material. Wenn er „weiss-nicht” sagt: Default vorschlagen, dann er nickt.
Trigger-Phrasen
- „neue Routine fuer X”
- „Cron-Agent anlegen”
- „Lambda anlegen”
- „Routine fuer X”
- „Agent bauen wie Beleg-Pipeline aber X”
- „bau mir einen Agent der Y macht”
- „Cron-Job in AWS fuer X”
- explizit:
/routine-anlegen(wenn Marvin den Slash-Command nutzt)
Run-Log
Eintraege chronologisch:
- 2026-05-12 Skill angelegt. Basiert auf Erfahrungen aus Beleg-Pipeline Session 1 (Layer-Code + IAM-Bugfixes + Deploy + Smoke). Erstanwendung:
<naechste Routine>.
Related
- agents-platform — Plattform die der Skill bedient (Konstrukt, Konventionen, Telegram-Format)
- _index — Beleg-Pipeline, Reference-Implementierung
- _index — MCPs die als Datenquellen dienen
- _index — AWS-Account-Map (Profile, Regionen, Berechtigungen)
- buckets — S3-Bucket-Map (falls Routine S3 braucht)
~/source/agents-platform/README.md— Repo-Doku