---
title: "Plan → Sprint/PBI/Story/Task workflow"
status: active
audience: [ai-agent, maintainer]
language: nl
last_updated: 2026-05-11
when_to_read: "Wanneer de gebruiker een plan goedkeurt en je het werk via Scrum4Me-MCP wilt vastleggen — inclusief sprint-lifecycle."
---

# Plan → Sprint / PBI / Story / Task workflow

Hoe je een **goedgekeurd plan** omzet naar een hiërarchie van Sprint + PBI + Story + Task(s) via de Scrum4Me-MCP, zónder de taken meteen uit te voeren. Eén PBI = één increment = één sprint.

Dit is de **creatie-kant** van het werk. De **uitvoer-kant** staat in [CLAUDE.md → "Hoe werk vinden"](../../CLAUDE.md) en [docs/runbooks/mcp-integration.md → Batch-loop](./mcp-integration.md).

> Sprint-tools `create_sprint` en `update_sprint` zijn live in scrum4me-mcp (PBI-12). Tool-reference: [mcp-integration.md](./mcp-integration.md).

---

## Wanneer wel — wanneer niet

| Type werk | Sprint + PBI maken? |
|---|---|
| Nieuwe feature, refactor, UX-aanpassing, performance-fix | **Ja** |
| Bug-fix die meer dan een trivial-edit vereist | **Ja** |
| Doc-only edit (CLAUDE.md, runbook, README) | Nee — direct edit, commit, klaar |
| Typo, format-fix, dead-code verwijdering (<10 regels) | Nee |
| Spike / verkenning zonder concrete output | Nee — log eventueel als Idea (M12) |

Sprint volgt PBI: **geen PBI → geen sprint**. Twijfel? Vraag het.

---

## De vier-laagse flow

```
plan goedgekeurd
   │
   ├─ create_sprint        → Sprint-record (status=OPEN, start_date=vandaag)
   │     │
   │     └─ create_pbi     → PBI-record onder dat product
   │            │
   │            └─ create_story  → Story-record, koppelt aan de actieve sprint
   │                   │
   │                   └─ create_task (× N)  → sprint_id geërfd van story
   │
   ├─ stop — wachten op uitvoer-instructie
   │
   ├─ … execution-fase via "Hoe werk vinden" …
   │
   └─ PR merged + verify groen  →  update_sprint(status=CLOSED, end_date=vandaag)
```

### 0. `create_sprint` (vóór alle andere create-calls)

```
{ product_id, code, sprint_goal, status: 'OPEN', start_date? }
```

- **`code`** — kort label, max 30 chars. Suggestie: `S-{YYYY-MM-DD}-{kebab-PBI-titel}` of een lopende teller (`S-2026-05-11-web-push`).
- **`sprint_goal`** — één regel, het increment in mensen-taal (komt uit de "Context" van het goedgekeurde plan).
- **`status`** — start op `OPEN`.
- **`start_date`** — vandaag; leeg laten als de server dit zelf invult.
- **Geen reuse:** altijd nieuw record. Bestaande OPEN-sprints van eerder werk blijven naast deze nieuwe leven; niet automatisch sluiten.

> Eén PBI per sprint is de afgesproken één-op-één-koppeling. Als een plan logisch in meerdere onafhankelijke PBI's uiteenvalt, maak je ook meerdere sprints.

### 1. `create_pbi`

```
{ product_id, title, description?, priority, sort_order? }
```

- **`title`** — korte feature-naam, geen PBI-nummer als prefix (DB kent al een id)
- **`description`** — markdown, het "wat & waarom" uit de Context-sectie van het plan
- **`priority`** — `LOW | NORMAL | HIGH` (default `NORMAL`); pas op `HIGH` zetten als de gebruiker het zelf zegt
- **`sort_order`** — leeg laten; server zet `last + 1` binnen de priority-groep
- Status start automatisch op `OPEN`

### 2. `create_story`

```
{ pbi_id, sprint_id, title, description?, acceptance_criteria?, priority }
```

- **`title`** — concreet, in user-story stijl als dat past ("Als developer wil ik …")
- **`description`** — technische context, scope-grenzen, niet-doelen
- **`acceptance_criteria`** — markdown checklist (`- [ ] …`); bepaalt wanneer de Story `DONE` is
- `product_id` wordt afgeleid uit de PBI — niet meegeven
- **`sprint_id`** — geef de zojuist aangemaakte sprint mee. Als er meerdere OPEN-sprints bestaan: bevestig eerst met de gebruiker welke sprint geldt.
- **`sort_order`** — NIET meegeven. De server berekent `sort_order = parseCodeNumber(code)` automatisch. De volgorde van stories = de volgorde van hun codes (= aanroep-volgorde); niet priority.
- Status start op `OPEN`

> **Eén story per PBI** is de gebruikelijke verhouding. Splits alleen op in meerdere stories als het plan logisch in onafhankelijk-shipbare delen valt — let op dat dit dan ook meerdere sprints betekent.

### 3. `create_task` (één call per taak)

```
{ story_id, title, description?, implementation_plan?, priority }
```

- **`title`** — werkwoord-vorm: "Implementeer …", "Verplaats …", "Voeg test toe voor …"
- **`description`** — wat de taak afdekt, in 1-3 zinnen
- **`implementation_plan`** — **belangrijk**: markdown met de daadwerkelijke stappen + file-paths + reuse-pointers; dit is wat de Implementation-agent later inleest
- **`sort_order`** — NIET meegeven. De server berekent `sort_order = parseCodeNumber(code)` automatisch. De uitvoervolgorde = de aanroep-volgorde (= code-volgorde); niet priority.
- `sprint_id` wordt geërfd van de Story — niet meegeven
- Status start op `TO_DO`

> De uitvoervolgorde van taken is gelijk aan de **aanroep-volgorde** van `create_task` (= code-volgorde). `priority` is een label (urgentie), géén sorteerkriteria. Zet voorbereidende taken (data-model, types) vóór UI-taken; tests komen ná de feature-implementatie tenzij TDD expliciet is afgesproken.

---

## Hardstop — wachten op uitvoer-instructie

Na `create_task` (de laatste): **stop**. Niet:

- ❌ Branch aanmaken
- ❌ Code wijzigen
- ❌ `update_task_status` naar `IN_PROGRESS` zetten
- ❌ `get_claude_context` aanroepen om "vast te beginnen"

De gebruiker leest de aangemaakte items, eventueel via de UI, en geeft expliciet de instructie *"voer de taken uit"* / *"pak deze story"* / *"begin met taak 1"*. Pas dan schakelt de flow over naar de **execution-loop** uit [CLAUDE.md → "Hoe werk vinden"](../../CLAUDE.md).

---

## Sprint sluiten — `update_sprint`

Na de execution-fase (laatste taak `DONE` → branch gepusht → PR aangemaakt) wordt de sprint pas `CLOSED` als **beide** condities waar zijn:

1. **PR merged op `main`** — detecteer met `gh pr view <num> --json mergedAt` (niet-leeg = merged) of een GitHub-merge-webhook
2. **Verify groen** — `gh pr checks <num>` allemaal ✅, óf de bestaande [`mcp__scrum4me__verify_sprint_task`](./mcp-integration.md) tool slaagt voor de laatste taak

Pas dan:

```
update_sprint({ sprint_id, status: 'CLOSED', end_date: today })
   → status = CLOSED
```

**Wat als één van beide rood is?**

| Situatie | Handmatige flow | Cron-flow (auto) |
|---|---|---|
| PR merged, verify rood | Sprint blijft `OPEN`. Hot-fix taak/PR, daarna close-check herhalen. | Cron mag de sprint na *N* mislukte verify-runs (drempel TBD) op `FAILED` zetten. |
| Verify groen, PR niet merged | Sprint blijft `OPEN`. Wacht op review/merge. | Cron mag na *X* dagen zonder merge op `FAILED` (stale-detectie). |
| PR gesloten zonder merge | Sprint blijft `OPEN` totdat gebruiker beslist. | Cron mag direct op `FAILED` zetten — PR-`closed && !merged` is een eindstatus. |
| Werk geannuleerd door gebruiker | Sprint → `ARCHIVED` (handmatig). | Niet door cron — vereist gebruikersactie. |

> **Cron-trigger:** een geplande job mag dus zowel `CLOSED` zetten (happy-path: merge + verify groen) als `FAILED` (sad-path: stale PR, blijvend rode verify, PR-closed zonder merge). De drempels (*N*, *X*) en transitie-policy komen in het vervolg-PBI voor de MCP-tools — zie [docs/plans/sprint-mcp-tools.md](../plans/sprint-mcp-tools.md).

---

## Verhouding tot de planning-agent

[docs/plans/tweede-claude-agent-planning.md](../plans/tweede-claude-agent-planning.md) (status: `proposal`) beschrijft een **automatische planning-agent** die deze flow uit een `PLANNING`-job zelfstandig uitvoert. Tot die agent er is, doet de Claude-Code-sessie het handmatig zoals hierboven. De toolchain (`create_sprint`/`create_pbi`/`create_story`/`create_task` + `update_sprint`) blijft identiek — de agent zal dezelfde MCP-tools gebruiken.

---

## Korte voorbeeld-sessie

```
Gebruiker: "plan goedgekeurd"
Claude:    create_sprint({ product_id, code: "S-2026-05-11-web-push",
                           sprint_goal: "Web-Push end-to-end voor open vragen",
                           status: "OPEN" })
           → sprint_id: 73

           create_pbi({ product_id, title: "Web-Push notifications voor open vragen",
                        description: "<plan-context>", priority: "NORMAL" })
           → pbi_id: 142

           create_story({ pbi_id: 142,
                          title: "PBI-142: web-push end-to-end",
                          description: "<scope>",
                          acceptance_criteria: "- [ ] Service worker geregistreerd\n- [ ] …",
                          priority: "NORMAL" })
           → story_id: 988  (gekoppeld aan sprint 73)

           create_task({ story_id: 988, title: "Voeg VAPID-keys toe aan env-schema",
                         implementation_plan: "1. lib/env.ts uitbreiden …",
                         priority: "NORMAL" })
           create_task({ story_id: 988, title: "Server action: subscribe-endpoint",
                         implementation_plan: "…", priority: "NORMAL" })
           create_task({ story_id: 988, title: "Vitest: subscribe-endpoint smoke",
                         implementation_plan: "…", priority: "NORMAL" })

           "Sprint 73 (OPEN), PBI 142, Story 988 met 3 taken aangemaakt.
            Klaar om uit te voeren zodra je 'voer uit' zegt."

Gebruiker: "voer uit"
Claude:    <execution-loop volgens 'Hoe werk vinden' — branch, code, commit, push, PR>

…na PR-merge + verify groen…

Claude:    update_sprint({ sprint_id: 73, status: "CLOSED", end_date: "2026-05-12" })
           → sprint 73 status = CLOSED
           "Sprint 73 gesloten. Increment shipped."
```

---

## Verwante docs

- [docs/runbooks/mcp-integration.md](./mcp-integration.md) — volledige MCP-tool reference + execution-loop
- [docs/runbooks/branch-and-commit.md](./branch-and-commit.md) — git-discipline bij uitvoer
- [docs/runbooks/worker-idempotency.md](./worker-idempotency.md) — job-status protocol (uitvoer-fase)
- [docs/plans/tweede-claude-agent-planning.md](../plans/tweede-claude-agent-planning.md) — toekomstige planning-agent (proposal)
