16 KiB
Runbook: BMAD Phase 4 Automation in Paperclip aufsetzen
End-to-End-Anleitung, um von einer leeren Paperclip-Instanz zu einem laufenden BMAD-Phase-4-Autopilot mit drei Agents zu kommen. Arbeite sie in dieser Reihenfolge ab – jeder Schritt hat einen Verifikations-Check am Ende.
Zeit-Abschätzung: 45-90 Min, wenn OpenCode und Paperclip schon installiert sind. Plus die Zeit, die BMAD für Phase 1-3 und manuelles Sprint Planning gebraucht hat.
Voraussetzungen
- BMAD V6 Phase 1-3 abgeschlossen:
_bmad-output/planning-artifacts/PRD.md_bmad-output/planning-artifacts/architecture.md- Eine Epic-Quelle (siehe README für unterstützte Varianten)
- Sprint Planning manuell durchgeführt: Du hast
bmad-sprint-planningselbst ausgeführt, und_bmad-output/implementation-artifacts/sprint-status.yamlexistiert. Der Supervisor erwartet diese Datei und weigert sich zu starten, wenn sie fehlt. - OpenCode CLI installiert,
opencode auth logindurchgeführt, Zugriff auf die gewünschten Modelle (das starke Code-Modell für Dev UND ein anderes Modell für QA) bestätigt. - Paperclip installiert und laufend (
paperclipailokal oder remote). PAPERCLIP_API_URLundPAPERCLIP_API_KEYals Env-Variablen gesetzt.- Git-Worktree des Projekts ist clean.
Schritt 1: Paperclip-Adapter-Schema live abfragen
Das Schema für opencode_local variiert leicht zwischen Paperclip-
Versionen. Hol dir die kanonische Form für deine Installation:
curl -sS "$PAPERCLIP_API_URL/llms/agent-configuration.txt" \
-H "Authorization: Bearer $PAPERCLIP_API_KEY" | less
curl -sS "$PAPERCLIP_API_URL/llms/agent-configuration/opencode_local.txt" \
-H "Authorization: Bearer $PAPERCLIP_API_KEY"
Vergleich die Felder mit config/agents.jsonc. Besonders relevant:
- Wie heißt das Modell-Pinning-Feld? (
env.OPENCODE_MODEL,model,runtimeModel, …) – beide Worker brauchen ein explizites Pinning. - Wird
sessionBehavior: "new"unterstützt oder heißt es anders (fresh-always,no-resume, …)?
Verifikation: Du hast Klarheit über die Pflicht- und Optional-Felder.
Schritt 2: Skills in Paperclips Skill-Library einspielen
Drei SKILL.md-Dateien müssen in deine Company-Skill-Library:
skills/monitor-bmad-progress/SKILL.mdskills/execute-bmad-dev-tasks/SKILL.mdskills/execute-bmad-qa-tasks/SKILL.md
Variante A – via Paperclip-UI: Company → Skills → Create New Skill,
Inhalt hineinkopieren. Der Skill-Name muss exakt zum name: im
YAML-Frontmatter passen.
Variante B – via API: Endpoint aus deiner Installation abfragen:
curl -sS "$PAPERCLIP_API_URL/llms/skills-api.txt" \
-H "Authorization: Bearer $PAPERCLIP_API_KEY"
Verifikation:
curl -sS "$PAPERCLIP_API_URL/api/skills" \
-H "Authorization: Bearer $PAPERCLIP_API_KEY" \
| jq '.[] | select(.name | startswith("monitor-bmad") or
startswith("execute-bmad-dev") or
startswith("execute-bmad-qa")) | .name'
Drei Namen müssen zurückkommen.
Schritt 3: Company anlegen
Im Paperclip-UI: + Company.
- Name: "BMAD Phase 4 – "
- Mission: "Automatisierte Ausführung der BMAD-V6-Implementation- Phase mit Dev/QA-Rollen-Trennung."
- Projekt-Pfad (cwd / project_root): Dein BMAD-Projektverzeichnis.
curl -sS "$PAPERCLIP_API_URL/api/companies" \
-H "Authorization: Bearer $PAPERCLIP_API_KEY" \
| jq '.[] | select(.name | contains("BMAD Phase 4"))'
Notiere companyId – brauchst du für alle folgenden Calls.
Schritt 4: Supervisor hiren
export COMPANY_ID="<aus Schritt 3>"
export PROJECT_ROOT="/srv/projects/<dein-projektname>"
curl -sS -X POST "$PAPERCLIP_API_URL/api/agents" \
-H "Authorization: Bearer $PAPERCLIP_API_KEY" \
-H "Content-Type: application/json" \
-d @- <<EOF
{
"companyId": "$COMPANY_ID",
"name": "PM Supervisor",
"role": "supervisor",
"icon": "📋",
"adapterType": "process",
"adapterConfig": {
"adapter": "opencode_local",
"cwd": "$PROJECT_ROOT",
"sessionBehavior": "resume-or-new",
"heartbeat": {"enabled": false}
},
"runtimeConfig": {"maxTurns": 80, "timeoutMs": 900000},
"desiredSkills": ["monitor-bmad-progress"],
"prompt": "<siehe agents.jsonc für den vollen Prompt>",
"budget": {"monthlyUsd": 20}
}
EOF
Notiere die agentId – Dev und QA referenzieren sie als reportsTo.
Schritt 5: Dev-Worker hiren
curl -sS -X POST "$PAPERCLIP_API_URL/api/agents" \
-H "Authorization: Bearer $PAPERCLIP_API_KEY" \
-H "Content-Type: application/json" \
-d @- <<EOF
{
"companyId": "$COMPANY_ID",
"name": "Dev Worker",
"role": "developer",
"icon": "💻",
"reportsTo": "<supervisor-agentId>",
"adapterType": "process",
"adapterConfig": {
"adapter": "opencode_local",
"cwd": "$PROJECT_ROOT",
"sessionBehavior": "new",
"env": {"OPENCODE_MODEL": "<starkes-code-modell>"},
"heartbeat": {"enabled": false}
},
"runtimeConfig": {"maxTurns": 300, "timeoutMs": 2700000},
"desiredSkills": ["execute-bmad-dev-tasks"],
"prompt": "<siehe agents.jsonc>",
"budget": {"monthlyUsd": 300, "perTaskUsdMax": 10}
}
EOF
Schritt 6: QA-Engineer hiren
Wichtig: Das Modell MUSS sich nachweislich vom Dev-Modell unterscheiden. Sonst verliert das adversariale Review seinen Wert.
curl -sS -X POST "$PAPERCLIP_API_URL/api/agents" \
-H "Authorization: Bearer $PAPERCLIP_API_KEY" \
-H "Content-Type: application/json" \
-d @- <<EOF
{
"companyId": "$COMPANY_ID",
"name": "QA Engineer",
"role": "qa",
"icon": "🔍",
"reportsTo": "<supervisor-agentId>",
"adapterType": "process",
"adapterConfig": {
"adapter": "opencode_local",
"cwd": "$PROJECT_ROOT",
"sessionBehavior": "new",
"env": {"OPENCODE_MODEL": "<anderes-modell-als-dev>"},
"heartbeat": {"enabled": false}
},
"runtimeConfig": {"maxTurns": 200, "timeoutMs": 1800000},
"desiredSkills": ["execute-bmad-qa-tasks"],
"prompt": "<siehe agents.jsonc>",
"budget": {"monthlyUsd": 150, "perTaskUsdMax": 5}
}
EOF
Verifikation Schritt 4-6:
curl -sS "$PAPERCLIP_API_URL/api/companies/$COMPANY_ID/agents" \
-H "Authorization: Bearer $PAPERCLIP_API_KEY" \
| jq '[.[] | {name, role, reportsTo, model: .adapterConfig.env.OPENCODE_MODEL}]'
Drei Agents, Supervisor top-level, Dev und QA beide unter Supervisor, mit unterschiedlichen Modellen bei Dev/QA.
Schritt 7: Smoke-Test der beiden Worker
Bevor echte Arbeit reinkommt: je ein Dummy-Task an Dev und QA.
Dev-Smoke:
curl -sS -X POST "$PAPERCLIP_API_URL/api/issues" \
-H "Authorization: Bearer $PAPERCLIP_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"companyId": "'$COMPANY_ID'",
"title": "Smoke test Dev: write hello-dev.txt",
"description": "Erzeuge hello-dev.txt im Projekt-Root mit Inhalt \"dev online\". Dann status=success melden.",
"assignedAgentId": "<dev-worker-agentId>"
}'
QA-Smoke:
curl -sS -X POST "$PAPERCLIP_API_URL/api/issues" \
-H "Authorization: Bearer $PAPERCLIP_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"companyId": "'$COMPANY_ID'",
"title": "Smoke test QA: read hello-dev.txt",
"description": "Lies hello-dev.txt, bestätige Inhalt, KEINE Änderungen. status=success mit dem gelesenen Text melden.",
"assignedAgentId": "<qa-engineer-agentId>"
}'
Beide Runs mit exitCode: 0. Räume hello-dev.txt danach auf.
NICHT weitermachen, bevor beide Smoke-Tests grün sind.
Schritt 8: Bootstrap-Task einspielen
Jetzt der eigentliche Start: Supervisor baut die Task-Hierarchie aus den BMAD-Planning-Artefakten.
curl -sS -X POST "$PAPERCLIP_API_URL/api/issues" \
-H "Authorization: Bearer $PAPERCLIP_API_KEY" \
-H "Content-Type: application/json" \
-d @bootstrap/initial-task.json
(Vorher in initial-task.json die companyId und assignedAgentId
eintragen – letzteres ist die Supervisor-ID aus Schritt 4.)
Erwartung (im Paperclip-UI):
- Bootstrap-Task:
ready→in-progress→completed - Child-Issues entstehen pro Story:
create-story (X.Y)— Dev-Workerdev-story (X.Y)— Dev-Workercode-review (X.Y)— QA-Engineer
- Pro Epic zusätzlich
retrospective (Epic N)— QA-Engineer - Supervisor postet Comment: Epics, Stories,
epic_source_layout - Nur der erste
create-story-Task ist aufready, alle anderenblockedmit Dependencies
Mögliche Abbrüche beim Bootstrap:
sprint_status_missing→ Sprint Planning nicht vorab ausgeführt. Laufbmad-sprint-planningmanuell, starte neu.no_epic_source_found→ keine der vier Epic-Layouts gefunden. Prüfe_bmad-output/planning-artifacts/.sprint_status_inconsistent→ Stories im sprint-status.yaml passen nicht zur Epic-Quelle.planning_incomplete→ PRD.md oder architecture.md fehlt.
Schritt 9: Erste Story durchlaufen lassen
Der Supervisor setzt automatisch den ersten create-story-Task auf
ready, sobald Bootstrap fertig ist. Der Dev-Worker sollte ihn binnen
Sekunden aufgreifen.
Happy Path für Story 1.1 → 1.2 → …:
- Dev:
create-story (1.1)→ Story-Datei existiert → completed - Dev:
dev-story (1.1)→ Implementierung, Commits, Tests → completed - QA:
code-review (1.1)→ verdict=approved → completed - ERST JETZT: Dev:
create-story (1.2)→ ...
Keine Parallelität über Story-Grenzen hinweg. Policy C (Strikte
Story-Ordnung) verhindert, dass create-story (1.2) startet, solange
Story 1.1 nicht approved ist. Die einzige Gleichzeitigkeit: während
Dev dev-story (1.2) macht, kann QA theoretisch code-review (1.1)
noch am Laufen haben – aber das passiert in der Praxis nicht, weil
Policy C auch das verhindert (Story 1.2 rührt sich ja erst, wenn Story
1.1 approved, d.h. code-review completed ist).
In der Praxis läuft also zu jedem Zeitpunkt EIN Task. Beide Agents sind selten gleichzeitig beschäftigt. Das ist bewusste Verlangsamung zugunsten sauberer Sequenzierung.
Bei needs-rework:
- QA:
code-review (1.1)→ verdict=needs-rework → completed - Supervisor legt an:
dev-story (1.1) retry 1(Dev) — mit Findings als Metadatacode-review (1.1) retry 1(QA) — blockiert auf den Retry-Dev
- Benachrichtigung an Operator: "Story 1.1 Retry 1/3 — N HIGH, M MEDIUM"
Bei Retry-Limit (3) erreicht → Eskalation mit vier Handlungsoptionen.
Epic-Übergang:
Nach code-review der letzten Story im Epic:
- QA:
retrospective (Epic 1)→ completed - Erst jetzt wird der erste
create-story-Task des nächsten Epics ready gesetzt. Davor: blocked durch Single-Epic-Policy.
Schritt 10: Häufige Fehler
BMAD-Skill fragt interaktiv zurück:
Prompt in Dev- oder QA-Skill präzisieren oder --non-interactive
an den BMAD-Skill-Aufruf anhängen.
OpenCode-Session hängt > Timeout:
Task-Timeout → SIGTERM. Supervisor markiert als failed, reason=timeout und versucht Re-Schedule. Nach 3 Timeouts am gleichen
Task: Eskalation. Bei wiederholten Timeouts an einer Story: Story zu
groß, manuell splitten.
Dev und QA nutzen versehentlich dasselbe Modell:
Supervisor merkt das am model_used-Feld in den Agent-Reports und
informiert einmalig im Status-Report. Kein Abbruch – aber das Review
ist dadurch schwächer. Korrigiere die env.OPENCODE_MODEL-Werte in
den Agent-Configs.
concurrent_task-Fehler:
Ein Agent hat zwei Tasks gleichzeitig. Sollte durch Policy B nie
passieren. Wenn doch: Sofort-Stopp, Paperclip-Audit-Log prüfen, dann
neu starten. Möglicherweise Supervisor-Bug oder Paperclip-Atomicity-
Issue.
sessionBehavior: "new" wird ignoriert:
Schema-Name in deiner Paperclip-Version abweichend. In agents.jsonc
anpassen basierend auf Schritt 1.
Operator ändert sprint-status.yaml mid-run: Supervisor erkennt das am Timestamp, eskaliert. Besser: Workflow stoppen, anpassen, neu bootstrappen.
QA findet NIE etwas: Entweder QA-Modell ist zu permissiv (Modell-Upgrade) oder die Stories sind tatsächlich trivial (akzeptabel, dann warning_zero_findings regelmäßig). Nach 3-5 approved-ohne-Findings: Stichprobe auf die Implementierung werfen.
Schritt 11: Patrol verstehen
Der Supervisor läuft nicht nur bei Events (task_completed), sondern
patrouilliert alle 15 Minuten (konfigurierbar in agents.jsonc
heartbeat.intervalSec). Das sorgt für maximale Autonomie: wenn ein
Agent hängt oder ein Ready-Setting verloren geht, bemerkt und behebt
der Supervisor das, ohne dass du eingreifen musst.
Was du in Paperclip sehen wirst:
- Patrol ohne Funde: Keine Comments. Stille Einträge im Audit-Trail ("Patrol OK"). Das ist der Normalfall bei gesundem Lauf.
- Patrol mit autonomer Aktion: Ein Comment am Parent-Issue im
Format:
### Patrol-Report – <zeitstempel> Graph-Status: 5/20 completed, 1 in-progress, 0 ready, 14 blocked Aktuelle Story: Epic 1 Story 1.3, Task dev-story Gefundene Blocker: stuck_in_progress_task (story 1.3, 47 min) Autonome Aktionen: reset-to-ready für task dev-story (1.3) Offene Eskalationen: keine - Patrol mit Eskalation: Comment mit
attention_required=true– das heißt, du musst ran. Z.B. bei dirty worktree oder Retry-Limit.
Was Patrol autonom auflöst:
| Blocker | Aktion |
|---|---|
| Task hängt in-progress ohne Heartbeat | als failed markieren, ready reset, normaler Retry-Pfad |
| Task ready, aber kein Agent zugewiesen | manuelles Re-Assignment an zuständigen Agent |
| Vorgänger completed, Folge blocked | Ready-Check nachholen, falls passt → ready setzen |
| Zwei Tasks mit identischem Kompositschlüssel | jüngeren cancellen, älteren behalten |
| Goal offen, aber kein aktiver Task | nächsten korrekten Task identifizieren und ready setzen |
| Dirty worktree (uncommitted changes) | WIP-Commit mit erkennbarer Message, Flow weiter (kein Code-Verlust) |
Was Patrol NICHT autonom macht (immer Eskalation):
- Retry-Limit erreicht (inhaltliche Entscheidung nötig)
- Fehlender Agent (Governance-Entscheidung)
- Meta-Stall > 1 h trotz Patrol-Aktionen (autonome Mittel erschöpft)
Besonderheit Dirty Worktree:
Wenn der Supervisor uncommittete Changes im Projekt findet (typisch
nach einem abgebrochenen Dev-Task), macht er einen automatischen
WIP-Commit mit Message wip: patrol-auto-commit from {task_type} (story {story_id}). Damit ist der Worktree wieder clean, der
Workflow läuft weiter, und du behältst die Änderungen vollständig
im Git-History. Du solltest solche WIP-Commits später manuell
prüfen – entweder revertst du sie und lässt den Dev-Agent sauber
neu arbeiten, oder du behältst sie, falls der Inhalt sinnvoll ist.
Diese landen als Info-Notiz mit attention_required=false. Du wirst
sie im Log sehen, aber sie stören deinen Schlaf nicht.
Wenn du Patrol vorübergehend abschalten willst:
In agents.jsonc beim Supervisor heartbeat.enabled: false setzen.
Dann läuft er wieder nur event-basiert – aber rechne damit, dass Hänger
dann liegen bleiben, bis du sie manuell lösst.
Schritt 12: Reporting einrichten (optional)
Der Supervisor postet Status-Reports als Comments auf das Parent-Issue. Für Push-Notifications:
- Paperclip-UI → Company → Integrations → Webhook auf
issue_comment_createdfür das Phase-4-Parent-Issue. - Alternativ: Im Supervisor-Prompt Hook einbauen, der bei
attention_required=trueeinen connected MCP (Slack, Email) triggert.
Was danach?
Sobald Story 1.1 einmal sauber durchgelaufen ist, ist die Schleife bewiesen.
- Cost-Dashboard täglich prüfen: Retry-Spiralen sind der teuerste Failure-Mode. 3-Retry-Limit deckelt, aber früh eingreifen lohnt sich.
- Nach 3 Stories manuelle Stichprobe: Qualität auf deinem Level?
- QA-Findings-Muster beobachten: Wenn eine Finding-Klasse
immer wiederkehrt →
project-context.mderweitern, damit der Dev die Konvention von Anfang an einhält.
Zweites BMAD-Projekt automatisieren
Paperclip unterstützt mehrere Companies pro Installation:
- Neue Company anlegen
- Die drei Skills sind instance-weit verfügbar, kein Re-Upload
- Drei neue Agents hiren mit neuem
cwd - Bootstrap wie in Schritt 8
Die SKILL.md-Dateien sind projekt-agnostisch. Nur cwd der Agents
ändert sich.