Files
bmad_agent/docs/RUNBOOK.md
T
2026-04-23 13:35:33 +02:00

16 KiB
Raw Blame History

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-planning selbst ausgeführt, und _bmad-output/implementation-artifacts/sprint-status.yaml existiert. Der Supervisor erwartet diese Datei und weigert sich zu starten, wenn sie fehlt.
  • OpenCode CLI installiert, opencode auth login durchgefü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 (paperclipai lokal oder remote).
  • PAPERCLIP_API_URL und PAPERCLIP_API_KEY als 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:

  1. skills/monitor-bmad-progress/SKILL.md
  2. skills/execute-bmad-dev-tasks/SKILL.md
  3. skills/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: readyin-progresscompleted
  • Child-Issues entstehen pro Story:
    • create-story (X.Y) — Dev-Worker
    • dev-story (X.Y) — Dev-Worker
    • code-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 auf ready, alle anderen blocked mit Dependencies

Mögliche Abbrüche beim Bootstrap:

  • sprint_status_missing → Sprint Planning nicht vorab ausgeführt. Lauf bmad-sprint-planning manuell, 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 → …:

  1. Dev: create-story (1.1) → Story-Datei existiert → completed
  2. Dev: dev-story (1.1) → Implementierung, Commits, Tests → completed
  3. QA: code-review (1.1) → verdict=approved → completed
  4. 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:

  1. QA: code-review (1.1) → verdict=needs-rework → completed
  2. Supervisor legt an:
    • dev-story (1.1) retry 1 (Dev) — mit Findings als Metadata
    • code-review (1.1) retry 1 (QA) — blockiert auf den Retry-Dev
  3. 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:

  1. QA: retrospective (Epic 1) → completed
  2. 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_created für das Phase-4-Parent-Issue.
  • Alternativ: Im Supervisor-Prompt Hook einbauen, der bei attention_required=true einen 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.md erweitern, damit der Dev die Konvention von Anfang an einhält.

Zweites BMAD-Projekt automatisieren

Paperclip unterstützt mehrere Companies pro Installation:

  1. Neue Company anlegen
  2. Die drei Skills sind instance-weit verfügbar, kein Re-Upload
  3. Drei neue Agents hiren mit neuem cwd
  4. Bootstrap wie in Schritt 8

Die SKILL.md-Dateien sind projekt-agnostisch. Nur cwd der Agents ändert sich.