18 KiB
| stepsCompleted | inputDocuments | bmadSkill | bmadWorkflow | |||||||
|---|---|---|---|---|---|---|---|---|---|---|
|
|
PM Agent (John) — /bmad-agent-bmm-pm → [CE] Create Epics and Stories | _bmad/bmm/workflows/3-solutioning/create-epics-and-stories/workflow.md |
CouncilOS — Epic & Story Breakdown
Autor: John (📋 BMAD PM Agent) Datum: 2026-03-12 Version: 1.0.0
Anforderungs-Inventar
Funktionale Anforderungen
| ID | Anforderung |
|---|---|
| FR-01.1 | Agent-Nodes per Drag & Drop auf den Canvas |
| FR-01.2 | Node-Einstellungs-Panel (Name, System-Prompt, Modell, Tools) |
| FR-01.3 | Lineare Edges zwischen Nodes |
| FR-01.4 | Bedingte Edges mit Routing-Label |
| FR-01.5 | Council unter Namen speichern |
| FR-01.6 | Gespeicherten Council laden und bearbeiten |
| FR-01.7 | Blueprint-JSON-Export |
| FR-02.1 | Prompt-Eingabe als Council-Input |
| FR-02.2 | PDF-Upload als Council-Input |
| FR-02.3 | Auto-Pilot / God Mode Toggle |
| FR-02.4 | Auto-Pilot läuft autonom |
| FR-02.5 | God Mode pausiert vor jedem Agent |
| FR-02.6 | Finales Dokument anzeigen |
| FR-02.7 | Run-Verlauf einsehen |
| FR-03.1 | Aktiver Node pulsiert im Canvas |
| FR-03.2 | WebSocket-Events mit node_name + status |
| FR-03.3 | done-Event nach Run-Abschluss |
| FR-04.1 | God Mode Approval-Popup |
| FR-04.2 | Approve → nächster Node |
| FR-04.3 | Reject → Run abbrechen |
| FR-04.4 | Modify → Draft bearbeiten vor Fortsetzung |
| FR-05.1 | LLM-Modell pro Agent konfigurierbar |
| FR-05.2 | Web-Suche optional aktivierbar |
| FR-05.3 | PDF-Reader optional aktivierbar |
| FR-06.1 | Blueprint-CRUD REST-API |
| FR-06.2 | Blueprints in PostgreSQL JSONB |
| FR-06.3 | version-Feld im Blueprint |
Nicht-Funktionale Anforderungen
| ID | Anforderung |
|---|---|
| NFR-01.1 | WebSocket < 500 ms |
| NFR-01.2 | Blueprint-CRUD < 200 ms P95 |
| NFR-01.3 | ≥ 10 parallele Runs |
| NFR-02.1 | API-Keys nur in Umgebungsvariablen |
| NFR-03.1 | Test-Coverage ≥ 80 % agents/, ≥ 90 % state.py |
| NFR-03.2 | Alembic für Migrationen |
| NFR-03.3 | Dynamischer Graph ab Phase 3 |
FR-Abdeckungskarte
| Epic | Abgedeckte FRs |
|---|---|
| Epic 1 | NFR-01–03, Infrastruktur |
| Epic 2 | FR-02.1–02.4, FR-02.6, FR-03.1–03.3 (Phase 1 Backend) |
| Epic 3 | FR-01.1–01.7, FR-06.1–06.3 (Phase 2 Frontend) |
| Epic 4 | FR-02.1–02.7, FR-03.1–03.3 (Phase 3 Integration) |
| Epic 5 | FR-02.2, FR-04.1–04.4, FR-05.2–05.3 (Phase 4 Tools & God Mode) |
Epic-Liste
- Epic 1: Projekt-Setup & Infrastruktur
- Epic 2: LangGraph Engine Backend (Phase 1)
- Epic 3: Visueller Baukasten Frontend (Phase 2)
- Epic 4: Frontend-Backend-Integration (Phase 3)
- Epic 5: Tools & God Mode (Phase 4)
Epic 1: Projekt-Setup & Infrastruktur
Ziel: Vollständig konfiguriertes, lauffähiges Entwicklungsumfeld mit Docker Compose, PostgreSQL, FastAPI-Skeleton und Next.js-Skeleton.
Story 1.1: Docker-Compose-Umgebung aufsetzen
Als Entwickler möchte ich eine vollständige lokale Docker-Compose-Umgebung, damit ich ohne lokale Python/Node-Installation entwickeln kann.
Akzeptanzkriterien:
Gegeben ein frisch geclontes Repository
Wenn ich docker compose up -d ausführe
Dann starten drei Services: db (PostgreSQL 16), api (FastAPI Port 8000), frontend (Next.js Port 3000)
Und GET /api/health gibt {"status": "ok"} zurück
Und das Frontend ist unter http://localhost:3000 erreichbar
Gegeben der db-Service läuft
Wenn ich pg_isready im Container ausführe
Dann antwortet PostgreSQL mit accepting connections
Story 1.2: Backend-Python-Umgebung & Requirements
Als Backend-Entwickler
möchte ich eine vollständige requirements.txt mit allen Abhängigkeiten,
damit ich reproduzierbar installieren kann.
Akzeptanzkriterien:
Gegeben ein Python 3.11+ Environment
Wenn ich pip install -r requirements.txt ausführe
Dann sind FastAPI, LangGraph, langchain-anthropic, langchain-openai, SQLAlchemy, alembic, chromadb, tavily-python, pypdf, pytest und alle Transitivabhängigkeiten installiert
Gegeben die Abhängigkeiten sind installiert
Wenn ich pytest backend/tests/ ausführe
Dann laufen alle Tests durch (auch wenn noch keine Testfälle existieren: 0 passed, 0 failed)
Story 1.3: Datenbank-Migrationen mit Alembic
Als Backend-Entwickler
möchte ich Alembic-Migrationen für blueprints und council_runs,
damit ich das Schema versioniert verwalten kann.
Akzeptanzkriterien:
Gegeben eine laufende PostgreSQL-Instanz
Wenn ich alembic upgrade head ausführe
Dann werden die Tabellen blueprints und council_runs erstellt
Und alembic current zeigt die aktuelle Revision
Gegeben die Tabellen existieren
Wenn ich ein Blueprint via REST-API erstelle
Dann wird es in blueprints mit UUID, JSONB-Daten und Timestamps gespeichert
Epic 2: LangGraph Engine Backend (Phase 1)
Ziel: Funktionierender, hartcodierter LangGraph-Graph (Master→Critic→Writer) mit CouncilState, Routing-Logik und FastAPI-Endpunkten. Verifikation via Terminal/Postman.
Story 2.1: CouncilState TypedDict implementieren
Als Backend-Entwickler
möchte ich den CouncilState TypedDict mit allen Feldern und Reducern,
damit er das einzige State-Objekt für alle Agents ist.
Akzeptanzkriterien:
Gegeben state.py ist implementiert
Wenn ich feedback_history mit operator.add als Reducer definiere
Dann werden neue Feedback-Einträge angehängt — niemals überschrieben
Wenn ich messages mit operator.add als Reducer definiere
Dann akkumuliert der LLM-Nachrichtenverlauf korrekt über mehrere Nodes
Wenn APPROVAL_THRESHOLD = 8.0 und MAX_ITERATIONS = 5 definiert sind
Dann sind diese Konstanten importierbar und in Tests verwendbar
Story 2.2: Master-Agent-Node implementieren
Als Backend-Entwickler
möchte ich den master_agent_node,
damit er auf Basis von input_topic und feedback_history einen Draft erstellt.
Akzeptanzkriterien:
Gegeben ein CouncilState ohne feedback_history
Wenn master_agent_node(state) aufgerufen wird (LLM gemockt)
Dann enthält der Rückgabe-Dict current_draft mit einem nicht-leeren String
Und messages enthält genau 3 Elemente (SystemMessage, HumanMessage, AIMessage)
Und iteration_count ist um 1 erhöht
Gegeben ein State mit feedback_history = ["Too short"]
Wenn master_agent_node(state) aufgerufen wird
Dann enthält der User-Prompt den Text „feedback" oder die Feedback-Einträge
Story 2.3: Critic-Agent-Node implementieren
Als Backend-Entwickler
möchte ich den critic_agent_node mit Score-Parsing und Routing,
damit er Drafts bewertet und route_decision setzt.
Akzeptanzkriterien:
Gegeben ein Score < 8 in der LLM-Antwort
Wenn critic_agent_node(state) aufgerufen wird
Dann ist route_decision = "rework"
Und feedback_history enthält einen neuen Eintrag
Gegeben ein Score ≥ 8
Dann ist route_decision = "approve"
Und feedback_history bleibt unverändert
Gegeben iteration_count >= MAX_ITERATIONS
Dann ist route_decision = "approve" ohne LLM-Aufruf (Safety Valve)
Gegeben eine nicht-parsbare LLM-Antwort
Dann fällt route_decision auf "rework" zurück — kein Crash
Story 2.4: Writer-Agent-Node implementieren
Als Backend-Entwickler
möchte ich den writer_agent_node,
damit er den finalen Draft für die Ausgabe formatiert.
Akzeptanzkriterien:
Gegeben ein CouncilState mit current_draft
Wenn writer_agent_node(state) aufgerufen wird (LLM gemockt)
Dann enthält der Rückgabe-Dict current_draft (finaler Output)
Und active_node = "writer_agent"
Story 2.5: LangGraph-Graph bauen und ausführen
Als Backend-Entwickler
möchte ich einen kompilierten LangGraph-Graphen (build_council_graph),
damit er Master→Critic→(conditional)→Writer ausführt.
Akzeptanzkriterien:
Gegeben build_council_graph() wird aufgerufen
Dann ist der zurückgegebene Graph kompiliert und invoke-fähig
Gegeben ein hartcodierter Test-Input (LLMs gemockt, Score 9 bei 2. Iteration)
Wenn graph.invoke(initial_state) aufgerufen wird
Dann durchläuft der Graph: master→critic→(rework)→master→critic→(approve)→writer→END
Und der finale State hat route_decision = "approve" und iteration_count = 2
Story 2.6: FastAPI-Run-Endpunkte implementieren
Als API-Nutzer
möchte ich POST /api/councils/run und GET /api/councils/run/{run_id},
damit ich einen Council-Run starten und sein Ergebnis abrufen kann.
Akzeptanzkriterien:
Gegeben POST /api/councils/run mit {"input_topic": "Test"}
Wenn der Endpunkt aufgerufen wird
Dann gibt er 202 Accepted mit run_id zurück
Und der Run läuft asynchron im Hintergrund
Gegeben ein abgeschlossener Run
Wenn GET /api/councils/run/{run_id} aufgerufen wird
Dann gibt er status: "completed" und final_draft zurück
Gegeben eine unbekannte run_id
Dann gibt er 404 Not Found zurück
Epic 3: Visueller Baukasten Frontend (Phase 2)
Ziel: React Flow Canvas mit Custom Nodes/Edges, Node-Einstellungs-Panel, Blueprint-Parser und PostgreSQL-Speicherung.
Story 3.1: React-Flow-Canvas mit Custom Agent Node
Als Nutzer möchte ich Agent-Nodes per Drag & Drop auf den Canvas ziehen, damit ich meinen KI-Rat visuell zusammenstellen kann.
Akzeptanzkriterien:
Gegeben der Rat-Architekt-Tab ist geöffnet Wenn ich einen Node aus der Seitenleiste auf den Canvas ziehe Dann erscheint ein Custom-Agent-Node mit Default-Name, Default-Modell und Tool-Badges
Gegeben ein Node ist auf dem Canvas Wenn ich ihn anklicke Dann öffnet sich das rechte Einstellungs-Panel
Gegeben das Einstellungs-Panel ist offen Wenn ich den Namen ändere Dann aktualisiert sich der Canvas-Node sofort (Live-Bindung)
Story 3.2: Lineare und bedingte Edges
Als Nutzer möchte ich Pfeile zwischen Nodes ziehen und als linear/bedingt markieren, damit ich den Workflow meines Councils definieren kann.
Akzeptanzkriterien:
Gegeben zwei Nodes auf dem Canvas Wenn ich vom Ausgangs-Handle des ersten zum Eingangs-Handle des zweiten ziehe Dann erscheint ein linearer Pfeil (grau, durchgehend)
Gegeben ich klicke eine Edge an Wenn ich sie als „bedingt" mit Label „rework" markiere Dann wird sie gestrichelt rot mit Label dargestellt
Gegeben ich markiere eine Edge als „approve" Dann wird sie grün dargestellt
Story 3.3: Blueprint-Parser (React Flow → JSON)
Als System
möchte ich eine parseGraphToBlueprint()-Funktion,
damit sie den Canvas-State in ein valides Blueprint-JSON konvertiert.
Akzeptanzkriterien:
Gegeben ein Canvas mit zwei Nodes und einer linearen Edge
Wenn parseGraphToBlueprint(nodes, edges, name) aufgerufen wird
Dann enthält das JSON version, name, nodes[], edges[]
Gegeben eine bedingte Edge mit Condition-Label
Dann ist type: "conditional" und condition: "<label>" im Edge-JSON
Gegeben ein isolierter Node (keine Edges) Dann erscheint eine Konsolenwarnung — der Node wird nicht aus dem JSON entfernt
Story 3.4: Blueprint CRUD — Frontend & Backend
Als Nutzer möchte ich Councils speichern, laden und löschen können, damit ich meine Configurations wiederverwenden kann.
Akzeptanzkriterien:
Gegeben ein ausgefüllter Canvas
Wenn ich „Speichern" klicke
Dann wird POST /api/councils/ aufgerufen und eine id zurückgegeben
Und eine Erfolgsmeldung erscheint
Gegeben bestehende Blueprints
Wenn ich die Blueprint-Liste abrufe (GET /api/councils/)
Dann sehe ich alle gespeicherten Councils mit Name und Datum
Gegeben einen Blueprint per id
Wenn ich DELETE /api/councils/{id} aufrufe
Dann gibt der Endpunkt 204 No Content zurück
Und ein anschließender GET gibt 404 zurück
Epic 4: Frontend-Backend-Integration (Phase 3)
Ziel: LangGraph liest JSON-Blueprint und baut Graph dynamisch. WebSocket-Events pulsieren Nodes im Canvas. Finaler Output erscheint im Frontend.
Story 4.1: Dynamischer Graph-Builder aus Blueprint-JSON
Als Backend-Entwickler
möchte ich dynamic_graph_builder.py,
damit er aus einem Blueprint-JSON zur Laufzeit einen LangGraph-Graphen baut.
Akzeptanzkriterien:
Gegeben ein valides Blueprint-JSON mit 2 Nodes und 1 linearer Edge
Wenn build_graph_from_blueprint(blueprint) aufgerufen wird
Dann gibt er einen kompilierten StateGraph zurück
Gegeben ein Blueprint mit Zyklus (A→B→A, bedingt) Dann kompiliert der Graph korrekt — kein Fehler, Zyklus bleibt erhalten
Gegeben ein Blueprint mit nicht-existenter Node-ID in einer Edge
Dann wird ein ValueError mit klarer Fehlermeldung geworfen
Gegeben ein Blueprint mit 0 Nodes
Dann wird ein ValueError geworfen
Story 4.2: WebSocket-Agent-Events integrieren
Als Frontend möchte ich WebSocket-Events vom Backend, damit der aktive Node im Canvas pulsiert.
Akzeptanzkriterien:
Gegeben ein laufender Council-Run
Wenn LangGraph in master_agent_node eintritt
Dann sendet das Backend {"node": "master_agent", "status": "running"} über WS
Gegeben das Frontend verbindet sich mit WS /ws/council/{run_id}
Wenn ein Node-Event empfangen wird
Dann wechselt der entsprechende Node im Canvas in den Pulsier-Zustand (gelb)
Gegeben der Run ist abgeschlossen
Dann sendet das Backend {"status": "done"} und das Frontend bricht die WS-Verbindung
Story 4.3: Konferenzzimmer — Live-Execution-UI
Als Nutzer möchte ich im Konferenzzimmer-Tab den laufenden Council sehen, damit ich transparent nachvollziehen kann, was die KI tut.
Akzeptanzkriterien:
Gegeben ich starte einen Blueprint-Run Wenn der Run läuft Dann zeigt das Canvas (read-only) den aktuell aktiven Node pulsierend
Wenn der Run abgeschlossen ist Dann erscheint das finale Dokument im Output-Bereich
Gegeben ein Run schlägt fehl Dann erscheint eine klare Fehlermeldung mit dem Fehlergrund
Epic 5: Tools & God Mode (Phase 4)
Ziel: Tavily-Web-Suche, PDF-Reader mit ChromaDB, und Human-in-the-Loop via interrupt_before.
Story 5.1: Tavily Web-Suche als Agent-Tool
Als Nutzer möchte ich Web-Suche als optionales Tool für jeden Agent, damit Agents aktuelle Informationen aus dem Internet nutzen können.
Akzeptanzkriterien:
Gegeben ein Agent mit tools.web_search = true
Wenn der dynamische Graph-Builder den Agent aufbaut
Dann wird web_search als Tool an den Agent gebunden
Gegeben TAVILY_API_KEY ist gesetzt
Wenn web_search("KI-Trends 2025") aufgerufen wird
Dann gibt die Funktion eine formatierte Liste von Treffern zurück (gemockt in Tests)
Gegeben TAVILY_API_KEY ist nicht gesetzt
Dann gibt die Funktion eine klare Fehlermeldung zurück — kein Crash
Story 5.2: PDF-Upload & ChromaDB-Ingestion
Als Nutzer möchte ich ein PDF hochladen, das als Wissensquelle für Agents dient, damit Agents auf Inhalte aus langen Dokumenten zugreifen können.
Akzeptanzkriterien:
Gegeben POST /api/councils/upload-pdf mit einer validen PDF-Datei
Wenn der Endpunkt aufgerufen wird
Dann wird das PDF in Chunks aufgeteilt, in ChromaDB gespeichert, und chunks_ingested zurückgegeben
Gegeben eine Nicht-PDF-Datei
Dann gibt der Endpunkt 400 Bad Request zurück
Gegeben ein Agent mit tools.pdf_reader = true
Wenn pdf_search("Schlüsselergebnisse") aufgerufen wird
Dann gibt die Funktion die Top-K semantisch ähnlichsten Chunks zurück
Story 5.3: God Mode — Human-in-the-Loop
Als Nutzer möchte ich im God Mode jeden Schritt des Councils genehmigen, damit ich volle Kontrolle über den Prozess habe.
Akzeptanzkriterien:
Gegeben ein Blueprint-Run mit god_mode = true
Wenn LangGraph den ersten Node abschließt
Dann pausiert der Graph via interrupt_before und status = "paused"
Gegeben ein pausierter Run
Wenn POST /api/councils/run/{run_id}/approve mit {"action": "approve"} aufgerufen wird
Dann setzt der Graph am nächsten Node fort
Gegeben {"action": "reject"}
Dann wird der Run mit status = "failed" beendet
Gegeben {"action": "modify", "modified_state": {"current_draft": "..."}}
Dann setzt der Graph mit dem modifizierten Draft fort
Gegeben das Frontend verbindet sich im God Mode Wenn der Run pausiert Dann erscheint das God-Mode-Overlay mit Agent-Name, Vorschlag, Grund und den drei Buttons
Story 5.4: Run-Verlauf (History)
Als Nutzer möchte ich vergangene Council-Runs einsehen, damit ich Ergebnisse nachträglich nachschlagen kann.
Akzeptanzkriterien:
Gegeben abgeschlossene Runs
Wenn GET /api/runs/ aufgerufen wird
Dann gibt er eine paginierte Liste aller Runs zurück
Gegeben eine run_id
Wenn GET /api/runs/{run_id} aufgerufen wird
Dann gibt er status, final_draft, critic_score, iteration_count zurück
Gegeben eine unbekannte run_id
Dann gibt er 404 Not Found zurück