--- title: "M12 — Drie-fase agent-pipeline voor feature-ideatie" status: proposal audience: [maintainer, contributor] language: nl last_updated: 2026-05-03 applies_to: [M12] related: - docs/adr/0009-three-phase-feature-pipeline.md - docs/plans/M11-claude-questions.md - docs/plans/ST-1111-claude-job-trigger.md - docs/obsidian-authoring.md --- # M12 — Drie-fase agent-pipeline voor feature-ideatie Implementatie van [ADR-0009](../adr/0009-three-phase-feature-pipeline.md): één geïntegreerde flow van een idee op een product naar een geïmplementeerde feature, in drie agent-fasen met menselijke checkpoints. Bouwt verder op M11 (vraagkanaal) en ST-1111 (job queue). Breidt `scrum4me-mcp` uit met docs-tools zodat alle agent-context — DB en docs — via één kanaal loopt. **Hard dependencies:** M11 + ST-1111 moeten afgerond zijn voor ST-1204. **Gekozen kaders:** - Drie aparte job-types — `FEATURE_BRAINSTORM`, `DETAIL_PLAN`, en de bestaande `STORY_EXECUTE`. Geen auto-advance tussen fasen; user triggert fase 2 en 3 expliciet. - Plan-content blijft file-based (`docs/plans/`); execution-state blijft DB. - Docs-context loopt via nieuwe MCP-tools (`list_docs`, `read_doc`, `search_docs`) — niet via directe filesystem-read door de worker. - **`ClaudeBrainstorm` is een aparte entiteit** naast `Story`. Brainstorm-Q&A loopt via `ClaudeBrainstormQuestion` parallel aan M11's `ClaudeQuestion`. M11 wordt **niet** aangeraakt. - **Workers draaien onder een dedicated `agent_writer`-account** per environment, niet onder een persoonlijke user. - **Plan-templates** in `docs/plans/templates/` zorgen voor reproduceerbare structuur in fase 2. - **In-app draft-preview** ship't in v1 (naast `obsidian://`-link) zodat Cowork-only users niet afhankelijk zijn van Obsidian. --- ## ST-1201 — MCP docs-tools (in `scrum4me-mcp`-repo) **Bestanden** - `scrum4me-mcp/src/tools/list-docs.ts` — nieuw - `scrum4me-mcp/src/tools/read-doc.ts` — nieuw - `scrum4me-mcp/src/tools/search-docs.ts` — nieuw - `scrum4me-mcp/src/lib/docs-root.ts` — nieuw (env `DOCS_ROOT` resolver + path-safety) - `scrum4me-mcp/src/lib/front-matter.ts` — nieuw, dependency-vrij parser (mirror `scripts/generate-docs-index.mjs`) - `scrum4me-mcp/src/index.ts` — registreer drie tools - `scrum4me-mcp/scripts/smoke-test.ts` — uitbreiden met docs-roundtrip - `scrum4me-mcp/README.md` — tool-tabel + `DOCS_ROOT` env doc - `scrum4me-mcp/.env.example` — `DOCS_ROOT` toevoegen **Stappen** 1. **`docs-root.ts`** — resolver: leest `DOCS_ROOT` env var (absolute path), throw bij ontbreken. Helper `safeJoin(rel)` blokkeert `..`-traversal en symlinks-buiten-root. 2. **`list_docs`** (read-tool) — input `{ category? }`, output `{ path, title, status?, last_updated?, category }[]`. Skip `_*.md` sidecars. Sorteer op `last_updated desc`. 3. **`read_doc`** (read-tool) — input `{ path }` relatief vanaf `DOCS_ROOT`, output `{ path, content, frontMatter, lastModified }`. Cap 200 KB. 4. **`search_docs`** (read-tool) — input `{ query, max_results? }` (default 10, max 30). Substring scan v1; switch naar `lunr`/`fuse.js` als v2 nodig blijkt. Excerpt 200 chars rond eerste match. 5. **Smoke-test**: `list_docs({category:'pattern'})` ≥10 items; `read_doc({path:'patterns/server-action.md'})` bevat "Server Action"; `search_docs({query:'iron-session'})` bevat ADR-0005. **Aandachtspunten** - Géén write-tools voor docs in deze story. `write_plan` (fase 2) komt in ST-1206 met striktere path-rules. - `DOCS_ROOT` is per-environment. Documenteer in `obsidian-authoring.md` (gebeurt in ST-1208). - Front-matter parser dependency-vrij — geen `gray-matter`. **Verificatie** - MCP Inspector toont 3 nieuwe tools - Smoke-test groen - Path-traversal test: `read_doc({path:'../package.json'})` → error - `tsc --noEmit` clean op `scrum4me-mcp` --- ## ST-1202 — Schema: `ClaudeBrainstorm` + worker-account **Bestanden** - `prisma/schema.prisma` — `JobType`-enum uitbreiden, `Role`-enum uitbreiden, `ClaudeBrainstorm` + `ClaudeBrainstormQuestion`-models - `prisma/migrations/_add_brainstorm_pipeline/migration.sql` - `prisma/seed-data/agent-writer.ts` — nieuw, seedt service-account per environment - `prisma/seed.ts` — invoke nieuwe seed - `vendor/scrum4me`-submodule sync in `scrum4me-mcp` ná merge **Stappen** 1. **Job-type uitbreiden**: ```prisma enum JobType { STORY_EXECUTE // bestaand uit ST-1111 FEATURE_BRAINSTORM // nieuw — fase 1 DETAIL_PLAN // nieuw — fase 2 } ``` 2. **`Role`-enum uitbreiden** (bestaand: `OWNER`, `MEMBER`, `DEMO`): ```prisma enum Role { OWNER MEMBER DEMO AGENT_WRITER // nieuw — alleen voor service-accounts die door workers gebruikt worden } ``` Toegangslogica: `requireWriteAccess` accepteert `AGENT_WRITER` net zoals `OWNER`/`MEMBER`. Demo-blok blijft alleen op `DEMO`. UI-rendering hoort `AGENT_WRITER`-users te verbergen uit member-lijsten (eigen filter, niet via role-omittance). 3. **`ClaudeBrainstorm`-model** (vervangt eerdere voorstel `BrainstormSession`): ```prisma model ClaudeBrainstorm { id String @id @default(cuid()) product_id String product Product @relation(fields: [product_id], references: [id], onDelete: Cascade) created_by String creator User @relation("BrainstormCreator", fields: [created_by], references: [id]) idea_text String @db.Text status String // 'brainstorming' | 'draft_ready' | 'detailing' | 'plan_ready' | 'cancelled' | 'failed' draft_path String? // bv. 'plans/_draft-feature-foo.md' plan_path String? // gevuld door fase 2 pbi_id String? brainstorm_job_id String? detail_job_id String? created_at DateTime @default(now()) updated_at DateTime @updatedAt questions ClaudeBrainstormQuestion[] @@index([product_id, status]) @@map("claude_brainstorms") } ``` 4. **`ClaudeBrainstormQuestion`-model** (parallel aan M11's `ClaudeQuestion`, geen wijziging op M11): ```prisma model ClaudeBrainstormQuestion { id String @id @default(cuid()) brainstorm_id String brainstorm ClaudeBrainstorm @relation(fields: [brainstorm_id], references: [id], onDelete: Cascade) product_id String // gedenormaliseerd voor SSE-filter (zelfde patroon als M11) product Product @relation(fields: [product_id], references: [id], onDelete: Cascade) asked_by String asker User @relation("BrainstormQuestionAsker", fields: [asked_by], references: [id]) question String @db.Text options Json? status String // 'open' | 'answered' | 'cancelled' | 'expired' answer String? @db.Text answered_by String? answerer User? @relation("BrainstormQuestionAnswerer", fields: [answered_by], references: [id]) answered_at DateTime? created_at DateTime @default(now()) expires_at DateTime @@index([brainstorm_id, status]) @@index([product_id, status]) @@map("claude_brainstorm_questions") } ``` 5. **Postgres-triggers** op beide tabellen, mirror M11 ST-1101 — emit op `scrum4me_changes` met `entity: 'brainstorm'` resp. `entity: 'brainstorm_question'`. Solo-route filtert beide weg (zelfde update als M11 deed voor `'question'`). 6. **Service-account seed** in `prisma/seed-data/agent-writer.ts`: - Maakt één user `agent-writer@scrum4me.local` met role `AGENT_WRITER` als die nog niet bestaat - Wachtwoord-hash van een random secret uit env `AGENT_WRITER_SECRET` (zo kan workers' iron-session-vergelijkbare auth via bcrypt-compare valideren) - User heeft géén product-membership by default — wordt per `ClaudeBrainstorm.product_id` runtime gemachtigd via een aparte `ProductAgentGrant`-laag (zie ST-1207) 7. `npx prisma migrate dev --name add_brainstorm_pipeline` **Aandachtspunten** - M11's `ClaudeQuestion` blijft volledig ongewijzigd. Alleen brainstorm-Q&A gebruikt de nieuwe tabel. - `entity: 'brainstorm'` en `entity: 'brainstorm_question'` zijn twee nieuwe SSE-payload-waarden — solo-route en M8/M11-routes moeten ze filteren of afhandelen - `AGENT_WRITER_SECRET` is een nieuwe env var — toevoegen aan `.env.example` + `lib/env.ts` - `ProductAgentGrant`-tabel komt in ST-1207 (apart) zodat dit story behapbaar blijft **Verificatie** - `npx prisma validate` clean - Seed-run maakt agent-writer user; herhaalde run idempotent (geen duplicate) - `psql $DIRECT_URL -c "LISTEN scrum4me_changes;"` toont nieuwe entity-waarden bij INSERT - M11-vraag-flow nog steeds werkend (regressie-check) - Submodule-sync drift-check ná merge --- ## ST-1203 — MCP brainstorm-question-tools (in `scrum4me-mcp`-repo) **Bestanden** - `scrum4me-mcp/src/tools/ask-brainstorm-question.ts` — nieuw - `scrum4me-mcp/src/tools/get-brainstorm-answer.ts` — nieuw - `scrum4me-mcp/src/tools/list-open-brainstorm-questions.ts` — nieuw - `scrum4me-mcp/src/index.ts` — registreer **Stappen** 1. **Spec-mirror van M11's question-tools**, maar gebonden aan `brainstorm_id` i.p.v. `story_id`: - `ask_brainstorm_question({ brainstorm_id, question, options?, wait_seconds? })` - `get_brainstorm_answer({ question_id })` - `list_open_brainstorm_questions({ brainstorm_id? })` 2. **Limit-enforcement**: `ask_brainstorm_question` weigert als `count(claude_brainstorm_questions WHERE brainstorm_id=… AND status≠'cancelled') ≥ 12`. Returnt `{ error: 'limit_reached' }` zodat de grill-me-skill afrondt. 3. **Auth**: `requireWriteAccess`-check; `userCanAccessProduct(brainstorm.product_id, auth.userId)`. `AGENT_WRITER`-account passeert deze check via `ProductAgentGrant` (ST-1207). 4. **Smoke-test** uitbreiden: ask + answer roundtrip op een test-brainstorm. **Aandachtspunten** - Code-duplicatie met M11-tools is aanvaardbaar (twee onafhankelijke flows). Als duplicatie pijn doet, factor in v2 een gemeenschappelijke `question-tool-factory` uit. - `cancel_brainstorm_question` niet in v1 — alleen agent-asker zou cancellen, en de caps maken het zelden nodig **Verificatie** - MCP Inspector toont 3 nieuwe tools (totaal docs+brainstorm = 6 nieuwe in M12) - Smoke-test groen — ask-with-wait + parallel answer - Limit-enforcement test: 13e vraag retourneert `limit_reached` --- ## ST-1204 — Fase 1: `FEATURE_BRAINSTORM`-worker **Bestanden** - `lib/jobs/handlers/feature-brainstorm.ts` — nieuw - `lib/jobs/dispatcher.ts` — uitbreiden met nieuwe type - `lib/agents/brainstorm-prompt.ts` — system-prompt template - `lib/agents/worker-session.ts` — nieuw — opent een iron-session voor `AGENT_WRITER`-account **Stappen** 1. **Worker-session helper** — `getAgentWriterSession(productId)`: - Authenticate `agent-writer@scrum4me.local` met `AGENT_WRITER_SECRET` - Return een MCP-bearer-token gebonden aan deze user voor de duur van het subprocess - Audit-log entry: "agent_writer accessed product X for brainstorm Y" 2. **Job-handler** ontvangt `ClaudeBrainstorm.id`: - Laad brainstorm + product - Genereer slug uit `idea_text` (lowercase, dash, max 40 chars) - Bepaal `_draft-feature-.md`-pad. Update brainstorm: `draft_path`, `status: 'brainstorming'` - Spawn Claude Code subprocess met env: `MCP_BEARER` (van worker-session), `DOCS_ROOT`, `BRAINSTORM_ID=` - Bij subprocess-exit: status → `draft_ready` (success) of `failed` (non-zero exit) 3. **Prompt-template** — `brainstorm-prompt.ts`: - Statisch met `{productName}`, `{ideaText}` placeholders - "Je bent in fase 1. Tools: `get_product`, `list_pbis`, `list_docs`, `search_docs`, `read_doc` voor context. `ask_brainstorm_question` om vragen te stellen (max 12). Trigger de `grill-me`-skill. Schrijf het resultaat naar `` via `write_doc_draft` (komt in ST-1206) zodra je voldoende context hebt." 4. **Caps**: max 30 min wall-time → SIGTERM → na 5s SIGKILL. **Aandachtspunten** - `write_doc_draft`-tool komt in ST-1206 — tot dan tijdelijke mock die naar stdout dumpt - grill-me wordt niet hier ingeladen; dat doet Claude Code's eigen skill-systeem zodra de prompt 'm noemt - Audit-log per worker-spawn is verplicht — nodig voor "wie heeft welke PBI aangemaakt"-traceerbaarheid **Verificatie** - Handmatig: maak `ClaudeBrainstorm` via prisma-studio met simpel idee → handler runt → na 5-10min verschijnt `_draft-feature-…md` - Tijdens run: in-app brainstorm-tracker toont vragen via SSE - Audit-log heeft entry per spawn --- ## ST-1205 — UI: "Nieuw idee", brainstorm-tracker, draft-preview **Bestanden** - `components/product/new-idea-button.tsx` — nieuw - `components/product/new-idea-dialog.tsx` — nieuw, volgt `docs/patterns/dialog.md` - `components/product/brainstorm-list.tsx` — nieuw - `components/product/draft-preview.tsx` — nieuw — in-app modal-preview voor draft + plan - `actions/brainstorm.ts` — `createBrainstorm`, `cancelBrainstorm`, `triggerDetailPlan` - `stores/brainstorm-store.ts` — nieuw - `lib/realtime/use-brainstorm-realtime.ts` — listen op `entity: 'brainstorm'` + `entity: 'brainstorm_question'` - `app/(app)/products/[id]/page.tsx` — bridge mount + button-render **Stappen** 1. **NewIdeaDialog** — entity-dialog per `docs/patterns/dialog.md`. Body: textarea (max 2000, char-counter), helper "Beschrijf het idee in eigen woorden — Claude stelt straks vervolgvragen." Submit → `createBrainstorm` Server Action. Demo-modus: knop disabled met tooltip. 2. **BrainstormList** op product-pagina: - Status-pills met MD3-tokens (zie `docs/design/styling.md`) - Per item: idea-truncate, created_by, last_updated-relative, action-buttons per status - `draft_ready` → "Bekijk draft" (opent ``) + secondary `obsidian://`-link + "Maak detail-plan" knop - `plan_ready` → "Bekijk plan" + "Open PBI" als pbi_id gevuld - `brainstorming` → "Annuleer" + indicator "Wacht op vragen" (blinkt als ask-pending) - Realtime-update via M12-bridge 3. **DraftPreview** (in-app v1): - shadcn `Dialog` met markdown-render (`react-markdown`, al gebruikt in M5 task-detail) - Inhoud opgehaald via MCP `read_doc({ path })` door een Server Action `getDraftContent(brainstormId)` die access-check doet - Read-only; bewerken gaat via Obsidian (link toont "Open in Obsidian" als secondary action) - Footer: "Maak detail-plan"-button (zelfde action als in lijst) 4. **Server Actions** — volgt `docs/patterns/server-action.md`: - `createBrainstorm({ productId, ideaText })` — Zod, demo-blok, access-check, transactie insert brainstorm + insert job - `triggerDetailPlan(brainstormId)` — vereist `status === 'draft_ready'`, insert `DETAIL_PLAN`-job - `cancelBrainstorm(brainstormId)` — alleen creator of OWNER, kill-signal naar job indien actief - `getDraftContent(brainstormId)` — read-only, access-check, roept MCP `read_doc` aan 5. **Bridge + store** — analoog aan M11 NotificationsBridge. **Aandachtspunten** - Twee bronnen van M12-events: brainstorm-status-changes en brainstorm-questions. Bridge subscribet beide. - Brainstorm-questions hoeven NIET in M11's notification-bell te verschijnen — ze zitten in BrainstormList op de product-pagina. Houd ze visueel apart van M11-questions. - Open punt: wil je later toch een unified-bell? Buiten M12-scope. - Paginate BrainstormList na 10 items, "Toon archief" voor cancelled/failed **Verificatie** - E2E tot fase 1: product → "Nieuw idee" → typ → submit → BrainstormList toont "brainstorming" → vragen verschijnen in component → user beantwoordt → status flipt naar "draft_ready" → "Bekijk draft" opent modal met markdown-content - Demo-modus: alle write-knoppen disabled met tooltip - Cancel: status flipt, subprocess wordt gekillt --- ## ST-1206 — Fase 2: `DETAIL_PLAN`-worker + `write_plan`-tool + plan-templates **Bestanden** - `scrum4me-mcp/src/tools/write-plan.ts` — nieuw, write-tool met strikte path-rules - `scrum4me-mcp/src/tools/write-doc-draft.ts` — nieuw, write-tool voor `_draft-*.md` (gebruikt door fase 1) - `scrum4me-mcp/src/index.ts` — registreer - `lib/jobs/handlers/detail-plan.ts` — nieuw - `lib/agents/detail-plan-prompt.ts` — system-prompt template - `docs/plans/templates/milestone.md` — nieuw - `docs/plans/templates/story.md` — nieuw - `docs/plans/templates/_README.md` — nieuw, beschrijft wanneer welke template gebruiken **Stappen** 1. **`write_doc_draft`** (write-tool, geen demo-blok want alleen agent_writer): - Input: `{ relativePath, content, overwrite? }` - Path moet matchen `plans/_draft-[a-z0-9-]+\.md` (regex enforcement) - Schrijven; output `{ path, bytesWritten }` 2. **`write_plan`** (write-tool, geen demo-blok): - Input: `{ relativePath, content, overwrite? }` - Path moet matchen `plans/(M\d+|ST-\d+)-[a-z0-9-]+\.md` — geen `_draft-`, geen subdirs - Mag niet bestaan tenzij `overwrite=true` (default false) - Output: `{ path, bytesWritten }` 3. **Plan-templates** — `docs/plans/templates/`: - `milestone.md` — voor ≥3 stories. Bevat front-matter-skelet, intro-blok, story-template (h2, bestanden-lijst, stappen, aandachtspunten, verificatie), branch-strategie-blok, acceptatie-blok, scope-out-blok. Gebruik `{{placeholders}}` in dezelfde stijl als `docs/adr/templates/nygard.md`. - `story.md` — voor 1-2 stories, lichter - `_README.md` — kies-criteria + handmatig-vs-fase-2 instructies. Underscore-prefix → niet in INDEX. 4. **Detail-plan-handler** ontvangt `ClaudeBrainstorm.id`: - Laad brainstorm, lees draft via MCP `read_doc({path: brainstorm.draft_path})` - Spawn Claude Code subprocess met `MCP_BEARER` (worker-session), `DOCS_ROOT`, `BRAINSTORM_ID` - System-prompt: - "Fase 2. Lees `read_doc({path:''})`. Gebruik `search_docs` + `read_doc` voor relevante patterns/ADRs/architecture. Lees `read_doc({path:'plans/templates/milestone.md'})` of `plans/templates/story.md` voor het skelet (kies milestone bij ≥3 stories). Schrijf canonical plan via `write_plan` naar `plans/M{N}-.md` of `plans/ST-XXXX-.md` (volgnummer via `list_docs({category:'plan'})` + max+1). Maak vervolgens via `save_pbi` + `save_story` + `save_task` de DB-rijen aan. Geen vragen aan de user — open punten markeer je als `**TODO:**` in het plan." - Bij subprocess-exit: update brainstorm `plan_path`, `pbi_id`, status `plan_ready` of `failed` **Aandachtspunten** - Plan-templates moeten zelf in INDEX-generator gefilterd worden via `_README.md`-prefix-rule (al bestaand) en via een `templates/`-pad-skip in `scripts/generate-docs-index.mjs` — kleine generator-edit nodig - Volgnummer-bepaling: lees alle `plans/M\d+-*.md` files, parse max nummer, +1. Race-conditie als twee fase-2-jobs tegelijk draaien — accept; dubbele nummers geven manuele review - `write_plan` mag een PBI-rij maken voor je het plan schrijft; volgorde in prompt: eerst plan-file (rollback-bestand bij fout), dan DB-rijen - Path-injection-test verplicht in unit-test **Verificatie** - Handmatig: trigger `triggerDetailPlan` op een draft → na 5-15min verschijnt nieuw `plans/M{N}-…md` + PBI in DB → BrainstormList status `plan_ready` - `npm run docs:index` regenereert INDEX.md met het nieuwe plan en negeert `templates/` - Path-rules: prompt-injection-test `write_plan({relativePath:'../adr/0009.md', ...})` faalt - Bestaand plan niet overschreven zonder `overwrite=true` --- ## ST-1207 — `ProductAgentGrant`: per-product machtiging voor `AGENT_WRITER` **Bestanden** - `prisma/schema.prisma` — `ProductAgentGrant`-model - `prisma/migrations/_add_product_agent_grant/migration.sql` - `lib/auth/agent-grant.ts` — helper `grantAgentForBrainstorm(brainstormId)` - `lib/auth/access.ts` — `userCanAccessProduct` uitbreiden om `AGENT_WRITER` met geldige grant te accepteren - `actions/brainstorm.ts` — `createBrainstorm` maakt grant aan in dezelfde transactie **Stappen** 1. **`ProductAgentGrant`-model**: ```prisma model ProductAgentGrant { id String @id @default(cuid()) product_id String product Product @relation(fields: [product_id], references: [id], onDelete: Cascade) agent_user_id String agent User @relation(fields: [agent_user_id], references: [id], onDelete: Cascade) reason String // 'brainstorm:' | 'detail_plan:' | 'story_execute:' granted_by String granter User @relation("AgentGrantGranter", fields: [granted_by], references: [id]) created_at DateTime @default(now()) expires_at DateTime // 24h voor brainstorm/detail; 7d voor story_execute @@unique([product_id, agent_user_id, reason]) @@index([agent_user_id, expires_at]) @@map("product_agent_grants") } ``` 2. **Access-uitbreiding** in `lib/auth/access.ts`: - Bestaand: `userCanAccessProduct(productId, userId)` checkt ProductMember - Nieuw: als user-role `AGENT_WRITER` is, valid grant-check via `ProductAgentGrant WHERE product_id=… AND agent_user_id=… AND expires_at > now()` 3. **Grant-helper** `grantAgentForBrainstorm(brainstormId)`: - Haal agent-user op (gecachet) - Insert grant met `reason='brainstorm:'`, `granted_by=brainstorm.created_by`, `expires_at=now+24h` - Idempotent via unique-constraint 4. **`createBrainstorm`-action** doet de grant aan in dezelfde transactie als de brainstorm + job. Fase 2 maakt een tweede grant met `reason='detail_plan:'`. 5. **Cleanup-cron** (lichtgewicht — kan in bestaande `expire-questions`-cron uit M11 ST-1107): - `DELETE FROM product_agent_grants WHERE expires_at < now()` - Hergebruik `CRON_SECRET`-pad **Aandachtspunten** - Audit-trail: `granted_by` legt vast welke menselijke user de agent gemachtigd heeft — voor compliance bij eventuele schade-analyse - Grant verloopt automatisch — voorkomt dat een lang-stilstaande agent later nog kan schrijven - Demo-user kan geen grants aanmaken (hij kan geen brainstorm starten — demo-blok op `createBrainstorm`) **Verificatie** - Unit-test: grant binnen window → access ja; grant verlopen → access nee - Unit-test: `AGENT_WRITER` zonder grant → access nee - Bestaande user-flows ongewijzigd (regressie) --- ## ST-1208 — Fase 3-integratie + acceptatietests + docs **Bestanden** - `lib/jobs/handlers/story-execute.ts` — uitbreiden om `story.metadata.plan_path` mee te nemen - `docs/architecture/agent-pipeline.md` — nieuw — sequence-diagram + threat-model - `docs/patterns/agent-pipeline-stage.md` — nieuw — herbruikbaar pattern - `docs/runbooks/mcp-integration.md` — uitbreiden met 6 nieuwe tools - `docs/obsidian-authoring.md` — corrigeer "MCP exposes geen docs"-passage - `docs/backlog/index.md` — M12-tabel + sectie - `prisma/seed-data/parse-backlog.ts` — `M12: 'PROPOSED'` - `CLAUDE.md` — patterns quickref-tabel uitbreiden - `scripts/generate-docs-index.mjs` — skip `plans/templates/` **Stappen** 1. **ST-1111 minimale aanpassing**: story-execute-handler leest `story.metadata.plan_path` indien gevuld en includeert "Lees `plan_path` voor je begint" in de prompt. Backwards-compatible. 2. **Architecture-doc** met Mermaid sequence: User → UI → Job → Worker (fase 1) → MCP (DB+docs+brainstorm-Q) → User → Worker schrijft draft → User triggert fase 2 → Worker (fase 2) → write_plan + save_pbi → User triggert fase 3 → bestaande flow. 3. **Pattern-doc** "agent-pipeline-stage" — generiek per fase: input-state, agent-context, output-artefact, exit-criteria, escalation-pad, audit-trail. 4. **Obsidian-authoring update** — vervang sectie "the mcp server does not expose docs/ content" door verwijzing naar ADR-0009 + de 6 nieuwe tools (`list_docs`, `read_doc`, `search_docs`, `write_plan`, `write_doc_draft`, `ask_brainstorm_question`/`get_brainstorm_answer`/`list_open_brainstorm_questions`). Behoud "Obsidian is geen tweede waarheidsbron"-stelling. 5. **Index-generator** — skip `plans/templates/` zodat templates niet in `INDEX.md` belanden. 6. **Backlog + parser** — M12 als PROPOSED; activeren wanneer M11 + ST-1111 done. 7. **Acceptatie-scenario's** (zeven): 1. **Happy path E2E**: idee → grill-me → draft → fase 2 → plan + PBI → fase 3 → code ✅ 2. **MCP docs-tool**: agent vindt via `search_docs` + `read_doc` de juiste pattern ✅ 3. **Path-safety**: prompt-injection via `write_plan` of `read_doc` faalt ✅ 4. **Demo-block**: alle drie de Server Actions geblokkeerd voor demo-user ✅ 5. **Cancel mid-flight**: brainstorm cancellen kill't subprocess ✅ 6. **Plan-overwrite-protectie**: bestaand plan niet overschreven ✅ 7. **Agent-grant-expiry**: agent kan na grant-expiry geen `save_pbi` meer doen voor dat product ✅ **Aandachtspunten** - Acceptatie 1 vereist M11 + ST-1111 volledig groen - Threat-model in architecture-doc: prompt-injection via `idea_text` (max-length + escape), agent-grant-misbruik (audit-log + auto-expire), schema-divergentie scrum4me ↔ scrum4me-mcp (sync ná merge) - Pipeline-pattern is bruikbaar voor toekomstige flows (bug-triage, refactor-planning) — pattern-doc moet generiek genoeg zijn **Verificatie** - 7/7 acceptatie groen (1+5 handmatig, 2+3+4+6+7 unit-test) - `npm run docs:index` clean — M12-plan, ADR-0009, nieuwe pattern + architecture in INDEX.md, templates niet - `npm run lint && npm test && npm run build` clean op Scrum4Me - `tsc --noEmit && npm test` clean op `scrum4me-mcp` - Submodule-sync ná merge --- ## Branch- en commit-strategie Per [Branch & PR Strategy](../runbooks/branch-and-commit.md): - **Eén branch op Scrum4Me**: `feat/M12-feature-pipeline` afgesplitst van `main` ná M11-merge - **Aparte branch op `scrum4me-mcp`**: `feat/M12-docs-and-plan-tools` - **MCP-PR pas mergen ná Scrum4Me-PR** + submodule-sync - **Push pas na handmatige acceptatie** van scenario 1 (happy path) + 3 (path-safety) + 7 (grant-expiry) Commit-volgorde: ``` feat(ST-1201): add list_docs, read_doc, search_docs MCP tools feat(ST-1201): add DOCS_ROOT env + safeJoin path validator feat(ST-1202): add JobType enum extension feat(ST-1202): add Role.AGENT_WRITER + agent-writer seed feat(ST-1202): add ClaudeBrainstorm + ClaudeBrainstormQuestion models feat(ST-1202): add notify triggers for brainstorm entities feat(ST-1203): add ask_brainstorm_question + get_brainstorm_answer + list_open_brainstorm_questions feat(ST-1204): add agent-writer worker-session helper feat(ST-1204): add brainstorm-prompt template feat(ST-1204): add FEATURE_BRAINSTORM job handler feat(ST-1205): add createBrainstorm + triggerDetailPlan + cancelBrainstorm server actions feat(ST-1205): add brainstorm Zustand store + realtime hook feat(ST-1205): add NewIdeaButton + dialog on product page feat(ST-1205): add BrainstormList component feat(ST-1205): add DraftPreview modal with read_doc fetch feat(ST-1206): add write_doc_draft + write_plan MCP tools docs(ST-1206): add plans/templates/milestone.md + story.md + _README.md feat(ST-1206): add detail-plan-prompt template feat(ST-1206): add DETAIL_PLAN job handler feat(ST-1207): add ProductAgentGrant model + migration feat(ST-1207): extend userCanAccessProduct with grant-check feat(ST-1207): wire grantAgentForBrainstorm into createBrainstorm + triggerDetailPlan feat(ST-1207): add grant-cleanup to expire-questions cron feat(ST-1208): wire plan_path into story-execute prompt docs(ST-1208): add agent-pipeline architecture doc docs(ST-1208): add agent-pipeline-stage pattern docs(ST-1208): update obsidian-authoring to reflect MCP docs-tools docs(ST-1208): skip plans/templates from index-generator chore(ST-1208): backlog M12 + parser PROPOSED ``` --- ## Buiten scope (volgende milestones) - **Auto-advance fase 1 → 2** wanneer de gebruiker dat per brainstorm aanvinkt (default blijft handmatige checkpoint) - **Multi-agent-detail-plan** (twee agents schrijven elk een variant; user kiest) - **Idee-clustering** via embeddings ("lijken deze 3 brainstorms op elkaar?") - **Stats-dashboard**: gemiddelde tijd per fase, % brainstorms die plan_ready halen, % geïmplementeerd - **Bulk-import** van bestaande backlog-items naar de pipeline - **Cross-product-pipeline**: idee dat impact heeft op meerdere producten - **Unified-bell** die zowel M11- als M12-vragen toont - **Edit-in-place voor draft in DraftPreview** (v1 is read-only; bewerken via Obsidian)