spec-driven
De artefacten van de standaardworkflow: hun volgorde, hun formaten en de wijzigingsmap die ze opleveren.
spec-driven is het ingebouwde standaardschema van OpenSpec. schema.yaml definieert de velden die het instelt.
Artefacten
De workflow stelt vier artefacten op:
| Artefact | Bestand | Doel |
|---|---|---|
proposal | proposal.md | Waarom de wijziging nodig is |
specs | specs/<capability-path>/spec.md, één per capability | Welk gedrag verandert |
design | design.md | Hoe je het bouwt |
tasks | tasks.md | De implementatiechecklist |
Volgorde van opstellen
┌─ specs ──┐
proposal ────┤ ├── tasks ── apply
└─ design ─┘Het voorstel komt eerst. Specificaties en ontwerp volgen in willekeurige volgorde, en taken vereisen beide. Implementatie (apply) start zodra tasks.md aanwezig is.
Twee artefacten kunnen worden overgeslagen:
design: wanneer geen van de voorwaarden van toepassing is, laat de agent dit weg en stelt hij tochtasksop.specs: stelskip_specs: truein in het.openspec.yamlvan de wijziging.
Voorbeeld wijzigingsmap
Een wijziging met de naam add-user-auth, waarbij elk artefact is opgesteld:
openspec/changes/add-user-auth/
├── .openspec.yaml wijzigingsmetadata, geschreven wanneer de wijziging wordt aangemaakt
├── proposal.md
├── specs/
│ └── user-auth/
│ └── spec.md één delta-specificatie per mogelijkheid
├── design.md
└── tasks.mdproposal.md
Legt uit waarom de wijziging nodig is.
Structuur
De sjabloon die de agent ontvangt als uitvoerformaat (templates/proposal.md):
# Proposal
## Why
<!-- Explain the motivation for this change. What problem does this solve? Why now? -->
## What Changes
<!-- Describe what will change. Be specific about new capabilities, modifications, or removals. -->
## Capabilities
### New Capabilities
<!-- Capabilities being introduced. Name each capability for a cohesive system
behavior that can own related requirements as the system evolves. Do not name
implementation tasks or proposal sections. Avoid broad catch-all names. Use
kebab-case for path segments you introduce (e.g., user-auth or identity/user-auth)
that follow the project's existing spec organization. Each creates
specs/<capability-path>/spec.md. -->
- `<capability-path>`: <brief description of what this capability covers>
### Modified Capabilities
<!-- Existing capabilities whose REQUIREMENTS are changing (not just implementation).
Only list here if spec-level behavior changes. Each needs a delta spec file.
Use the exact existing path under openspec/specs/. Leave empty if no requirement
changes. A change with no capabilities at all (pure refactor, tooling, docs)
must set `skip_specs: true` in its .openspec.yaml - openspec validate rejects
a zero-delta change without that marker. Do not invent a requirement just to
satisfy validation. -->
- `<existing-capability-path>`: <what requirement is changing>
## Impact
<!-- Affected code, APIs, dependencies, systems -->Instructies
De instructie die naar de agent wordt gestuurd wanneer hij dit artefact opstelt (uit schema.yaml):
Create the proposal document that establishes WHY this change is needed.
Sections:
- **Why**: 1-2 sentences on the problem or opportunity. What problem does this solve? Why now?
- **What Changes**: Bullet list of changes. Be specific about new capabilities, modifications, or removals. Mark breaking changes with **BREAKING**.
- **Capabilities**: Identify which specs will be created or modified:
- **New Capabilities**: List capabilities being introduced. Each becomes a new `specs/<capability-path>/spec.md`. Name each capability for a durable system behavior (for example, `user-auth`), not the work in this change (for example, `add-login-endpoint`). Choose a cohesive boundary that can own related requirements as the system evolves; avoid broad catch-all capabilities. Use kebab-case for path segments you introduce (e.g., `user-auth` or `identity/user-auth`) and follow the project's existing spec organization.
- **Modified Capabilities**: List existing capabilities whose REQUIREMENTS are changing. Only include if spec-level behavior changes (not just implementation details). Each needs a delta spec file. Use the exact existing path under `openspec/specs/`. Leave empty if no requirement changes.
- **Impact**: Affected code, APIs, dependencies, or systems.
IMPORTANT: The Capabilities section is critical. It creates the contract between
proposal and specs phases. Research existing specs before filling this in:
run `openspec list --specs` for the project's capability inventory, then
`openspec show "<spec-id>" --type spec --json --no-scenarios` for any that
look related - that returns a capability's purpose and requirement texts
without pulling whole spec files into context. Append `--store "<id>"` to
both commands only for a registered standalone store, and keep `--type
spec`: a change and a spec sharing a name is otherwise an ambiguous-item
error. `openspec list` without `--specs` lists in-flight changes, not
specs - it never shows what the project already covers. Reuse an existing
capability's exact path instead of introducing a near-duplicate name.
The filtered read is only an overview. Before deciding what is already
covered or what should change, read each relevant spec in full, including
scenarios, with `openspec show "<spec-id>" --type spec` (same `--store` rule).
Each capability listed here will need a corresponding spec file.
Every change must either declare at least one capability (new or
modified) or explicitly opt out of specs: `openspec validate` rejects a
change with zero deltas unless the change's `.openspec.yaml` sets
`skip_specs: true`. Use `skip_specs: true` only when no spec-level
behavior changes (pure refactor, tooling, docs) - specs describe
behavior, so if behavior does not change, no spec should change either.
Do not invent a requirement just to satisfy validation.
Keep it concise (1-2 pages). Focus on the "why" not the "how" -
implementation details belong in design.md.
This is the foundation - specs, design, and tasks all build on this.Deltaspecificaties (spec.md)
Definieert wat er aan gedrag verandert, met één deltaspecificatie per mogelijkheid die het voorstel opsomt.
Elke deltaspecificatie is de spec.md binnen zijn mogelijkhedenmap. openspec validate en openspec archive weigeren delta-secties die in enig ander bestand onder specs/ zijn geschreven, zoals specs/user-auth.md, omdat archief ze nooit samenvoegt.
Structuur
De sjabloon die de agent ontvangt als uitvoerformaat (templates/spec.md):
# Spec Delta
## Purpose
<!-- New capabilities only: one or two sentences (50+ characters) on what this capability is for. Delete this section for an existing capability. -->
## ADDED Requirements
### Requirement: <!-- requirement name -->
<!-- requirement text -->
#### Scenario: <!-- scenario name -->
- **WHEN** <!-- condition -->
- **THEN** <!-- expected outcome -->Instructies
De instructie die naar de agent wordt gestuurd wanneer hij dit artefact opstelt (uit schema.yaml):
Create specification files that define WHAT the system should do.
A spec is a behavior contract, not an implementation plan.
Good spec content:
- Observable behavior users or downstream systems rely on
- Inputs, outputs, and error conditions
- External constraints (security, privacy, reliability, compatibility)
- Scenarios that can be tested or explicitly validated
Avoid in specs:
- Internal class/function names
- Library or framework choices
- Step-by-step implementation details
- Detailed execution plans (those belong in design.md or tasks.md)
Quick test: if the implementation can change without changing externally
visible behavior, it likely does not belong in the spec.
Create one spec file per capability listed in the proposal's Capabilities section.
`<capability-path>` is the spec directory relative to `specs/` (for example,
`user-auth` or `identity/user-auth`). Preserve the full path:
- New capabilities: use the exact path from the proposal at `specs/<capability-path>/spec.md`. Any path segment newly introduced in the proposal must be kebab-case. Follow the project's existing organization; do not add a new domain level when the project uses a flat layout.
- Modified capabilities: use the exact existing path from `openspec/specs/<capability-path>/` when creating the delta at `specs/<capability-path>/spec.md`. Run `openspec list --specs` to confirm that path before writing the delta, appending `--store "<id>"` only for a registered standalone store - a mistyped or invented path targets a capability that does not exist rather than the one you meant. Do not move or rename the capability.
Write the spec files one at a time, so the user sees progress and an
interrupted run keeps the files it already wrote:
- Before writing anything, compare the capabilities the proposal lists
with the `specs/<capability-path>/spec.md` files that already exist,
and start with the first capability that has no file. Do not rewrite
an existing file unless the user asks you to.
- Before each file, say in one line which capability you are writing.
- Write each file as soon as you have drafted it. Do not plan every file
before writing the first.
- Stop when every capability the proposal lists has its file.
There must be at least one spec file unless the change's `.openspec.yaml`
sets `skip_specs: true` (no spec-level behavior change) - `openspec validate`
rejects a zero-delta change without that marker. If the proposal lists no
capabilities and `skip_specs` is not set, revisit the proposal first.
Delta operations (use ## headers):
- **ADDED Requirements**: New capabilities
- **MODIFIED Requirements**: Changed behavior - MUST include full updated content
- **REMOVED Requirements**: Deprecated features - MUST include **Reason** and **Migration**
- **RENAMED Requirements**: Name changes only - use FROM:/TO: format
Format requirements:
- Each requirement: `### Requirement: <name>` followed by description
- Use SHALL/MUST for normative requirements (avoid should/may)
- Each scenario: `#### Scenario: <name>` with WHEN/THEN format
- **CRITICAL**: Scenarios MUST use exactly 4 hashtags (`####`). Using 3 hashtags or bullets will fail silently.
- Every requirement MUST have at least one scenario.
- Every scenario MUST have a WHEN/GIVEN step (its trigger) and a THEN step (its outcome). A scenario with only AND lines or plain prose still counts as a scenario, but `openspec validate` flags it as a warning: normal validation still passes, but `openspec validate --strict` fails on it.
- Keep each requirement's description (the text between `### Requirement:` and its first scenario) to 500 characters or fewer. `openspec validate` flags longer descriptions in ADDED requirements and in the main spec. This is a warning: normal validation still passes, but `openspec validate --strict` fails on it. When writing a new requirement, state one behavior per requirement: move examples and edge cases into scenarios, and split a requirement that covers several behaviors into separate `### Requirement:` blocks, each with its own scenarios. Under MODIFIED, keep the existing requirement block whole; never split, trim or rewrite existing text just to meet the length. Split an existing long requirement only when the user asks for it, in a change made for that purpose: under MODIFIED, keep its header and every scenario and cut its description down to one behavior without changing its meaning, then add each behavior you removed as its own ADDED requirement with its own scenarios.
New capabilities only: the delta spec's first section is `## Purpose` -
one or two sentences (50+ characters, or `openspec validate --strict`
reports it as too brief) describing what the capability is for. Archive
copies it into the main spec it creates; without it the new main spec is
left with a `TBD ... Update Purpose after archive` placeholder to fill in
by hand. Do NOT add `## Purpose` to a delta for an existing capability -
that spec already has one and the delta's is ignored. To change an
existing capability's Purpose - including a leftover `TBD` placeholder -
edit `<planningHome.root>/openspec/specs/<capability-path>/spec.md`
directly. `planningHome.root` comes from the `openspec instructions ...
--json` response. Always use it rather than a repo-relative path: it
resolves to the store whenever the change lives in one - whether that
came from `--store`, a project `store:` pointer, or a global default
store - and to the current repository otherwise. Do not try to work out
which case applies; the field already has.
MODIFIED requirements workflow:
1. Locate the existing requirement in `<planningHome.root>/openspec/specs/<capability-path>/spec.md` (the same store-aware root as above)
2. Copy the ENTIRE requirement block (from `### Requirement:` through all scenarios)
3. Paste under `## MODIFIED Requirements` and edit to reflect new behavior
4. Ensure header text matches exactly (whitespace-insensitive)
Common pitfall: Using MODIFIED with partial content loses detail at archive time.
If adding new concerns without changing existing behavior, use ADDED instead.
Example (a new capability, so its first section is `## Purpose`):
```
# Spec Delta
## Doel
Stelt gebruikers in staat hun gegevens in een draagbaar formaat uit het product te halen.
## TOEGEVOEGDE Vereisten
### Vereiste: Gebruiker kan gegevens exporteren
Het systeem ZAL gebruikers in staat moeten stellen hun gegevens in CSV-formaat te exporteren.
#### Scenario: Succesvolle export
- **WANNEER** gebruiker op de knop "Exporteren" klikt
- **DAN** downloadt het systeem een CSV-bestand met alle gebruikersgegevens
## VERWIJDERDE Vereisten
### Vereiste: Verouderde export
**Reden**: Vervangen door nieuw exportsysteem
**Migratie**: Gebruik nieuw exportendpoint op /api/v2/export
```
Specificaties moeten testbaar zijn - elk scenario is een mogelijke testcase.design.md
Legt uit hoe de wijziging moet worden geïmplementeerd. Alleen opgesteld wanneer de wijziging dat nodig heeft.
Structuur
De sjabloon die de agent als uitvoerformaat ontvangt (templates/design.md):
# Ontwerp
## Context
<!-- Huidige staat en beperkingen die de aanpak vormgeven. Zie proposal.md voor motivatie - herhaal het niet -->
## Doelen / Niet-doelen
**Doelen:**
<!-- Wat dit ontwerp wil bereiken -->
**Niet-doelen:**
<!-- Wat expliciet buiten scope valt -->
## Beslissingen
<!-- Belangrijke ontwerpbeslissingen met beargumentering en overwogen alternatieven -->
## Risico's / Afwegingen
<!-- Bekende risico's en afwegingen -->Instructies
De instructie die naar de agent wordt gestuurd wanneer het dit artefact opstelt (uit schema.yaml):
Maak het ontwerpdocument dat uitlegt HOE de wijziging te implementeren.
Wanneer design.md opnemen (alleen aanmaken als van toepassing):
- Dwarslopende wijziging (meerdere services/modules) of nieuw architectonisch patroon
- Nieuwe externe afhankelijkheid of significante gegevensmodelwijzigingen
- Beveiligings-, prestatie- of migratiecomplexiteit
- Ambiguïteit die baat heeft bij technische beslissingen vóór codering
Secties:
- **Context**: Alleen de huidige staat en beperkingen die nodig zijn om de aanpak uit te leggen. Verwijs naar de proposal voor motivatie in plaats van deze te herhalen (bijv. "Zie proposal.md - Waarom").
- **Doelen / Niet-doelen**: Wat dit ontwerp bereikt en expliciet uitsluit. Herhaal de scope van de proposal niet - voeg alleen ontwerpniveau-grenzen toe.
- **Beslissingen**: Belangrijke technische keuzes met beargumentering (waarom X boven Y?). Neem voor elke beslissing de overwogen alternatieven op.
- **Risico's / Afwegingen**: Bekende beperkingen, dingen die fout kunnen gaan. Formaat: [Risico] → Mitigatie
- **Migratieplan**: Stappen voor uitrol, terugdraai-strategie (indien van toepassing)
- **Open vragen**: Onbekenden die veilig later kunnen worden beantwoord zonder
de specificaties, de aanpak of de taakverdeling te wijzigen. Weglaten als er geen zijn.
Open vragen zijn voor werkelijk uitstelbare onbekenden, niet beslissingen die je
hebt overgeslagen. Als een vraag de specificaties, de gekozen aanpak of
de taakverdeling zou veranderen, los die dan nu op - vraag de gebruiker in plaats van te raden.
Richt je op architectuur en aanpak, niet op regel-voor-regel implementatie.
De proposal behandelt waarom en wat; ontwerp behandelt hoe. Verwijs naar de
proposal voor motivatie en, eenmaal geschreven, naar de specificaties voor eisen -
als een sectie die alleen zou herhalen, verwijs er dan naar in plaats van dat.
Goede ontwerpdocumenten leggen de "waarom" achter technische beslissingen uit.tasks.md
Breekt de implementatie op in controleerbare taken. apply volgt de voortgang hier.
Structuur
De sjabloon die de agent als uitvoerformaat ontvangt (templates/tasks.md):
# Taken
## 1. <!-- Taakgroepnaam -->
- [ ] 1.1 <!-- Taakomschrijving -->
- [ ] 1.2 <!-- Taakomschrijving -->
## 2. <!-- Taakgroepnaam -->
- [ ] 2.1 <!-- Taakomschrijving -->
- [ ] 2.2 <!-- Taakomschrijving -->Instructies
De instructie die naar de agent wordt gestuurd wanneer het dit artefact opstelt (uit schema.yaml):
Maak de takenlijst die het implementatiewerk opbreekt.
Controleer vóór het schrijven van taken design.md op Open vragen. Als een ervan
zou veranderen wat er wordt gebouwd, los die dan eerst met de gebruiker op - verwerk
geen onuitgesproken aanname in de takenlijst.
**BELANGRIJK: Volg het onderstaande sjabloon voor bijgehouden taken.** De apply-fase verwerkt het
selectievakformaat om de voortgang bij te houden. Een vak met alleen `x` telt als gedaan,
hoofd- of kleine letter en met alle spaties, dus `- [ x]` is ook gedaan. Elk
ander teken, waaronder `- [~]`, `- [-]` en een leeg `- []`, wordt gelezen als
onafgerond. Een regel zonder selectievak wordt helemaal niet bijgehouden.
Richtlijnen:
- Groepeer gerelateerde bijgehouden taken onder ## genummerde koppen
- Elke bijgehouden taak MOET een selectievak zijn: `- [ ] X.Y Taakomschrijving`
- Taken moeten klein genoeg zijn om in één sessie te voltooien
- Orden taken op afhankelijkheid (wat moet eerst?)
- Houd implementatie- en verificatiewerk bij dat kan worden voltooid vóór
archivering. Als de gevraagde workflow archivering of werk omvat dat vereist
dat deze wijziging wordt gearchiveerd, bewaar die stappen dan als gewone opsommingstekens in een
optionele `## Workflow follow-up`-sectie aan het einde van tasks.md. Deze
opsommingstekens zijn referentieinformatie buiten de bijgehouden taakvoortgang.
- Elke taak MOET vermelden hoe voltooiing kan worden geverifieerd (een test, commando,
waarneembaar gedrag of geleverd artefact). Zet de verificatie in
de selectievakbeschrijving van die taak. Gebruik een aparte verificatietaak alleen
als het bredere integratie of systeemgedrag controleert dat meerdere
implementatietaken omvat.
- Elke taakgroep MOET de tests en documentatie opleveren die haar eigen werk
vereist. Verzamel testing of documentatie NIET in een laatste groep -
wanneer een late groep voor het eerst werk van een vroege groep uitvoert, cascaderen de fouten
terug door elke tussenliggende groep en dwingen ze tot overwerk. Een groep
waarvan het werk geen van beide vereist, zoals scaffolding of afhankelijkheidsinstelling,
draagt er geen van beide. Een laatste groep is alleen voor integratiecontroles, niet voor
de tests en documentatie die een eerdere groep verschuldigd was.
Voorbeeld:
```
# Taken
## 1. Opzet
- [ ] 1.1 Maak nieuwe modulestructuur aan en verifieer dat de verwachte bestanden aanwezig zijn
- [ ] 1.2 Voeg afhankelijkheden toe aan package.json en verifieer dat pakketinstallatie slaagt
## 2. Kernimplementatie
- [ ] 2.1 Implementeer gegevensexportfunctie en verifieer dat de exporttest slaagt
- [ ] 2.2 Voeg CSV-opmaakhulpprogramma's toe en verifieer dat unit tests aanhalingstekens en scheidingstekens dekken
- [ ] 2.3 Documenteer de export-API in docs/export.md en verifieer dat het gedocumenteerde commando werkt zoals beschreven
```
Indien van toepassing, voeg workflow follow-up toe als gewone opsommingstekens, bijvoorbeeld:
```
## Workflow follow-up
- Archiveer de wijziging nadat de reviewvereisten van het project zijn voldaan.
- Verifieer het gearchiveerde resultaat.
```
Verwijs naar specificaties voor wat er gebouwd moet worden, ontwerp voor hoe het te bouwen.Apply
De overdracht van planning naar implementatie. Apply is de fase die tasks.md doorloopt, geen artefact.
- Begint: zodra
tasks.mdbestaat en minstens één taak bevat. - Volgt: de selectievakjes in
tasks.md. Ze afvinken is het voortgangsrecord. - Eindigt: elk selectievakje is aangevinkt. OpenSpec suggereert dan de wijziging te archiveren.
Instellingen
De apply-instellingen (uit schema.yaml):
apply:
requires: [tasks]
tracks: tasks.md
# instruction: shown belowInstructies
De instructie die naar de agent wordt gestuurd wanneer de implementatie begint (uit schema.yaml):
Lees contextbestanden, werk lopende taken af, markeer ze als voltooid terwijl je bezig bent.
Pauzeer als je obstakels tegenkomt of verduideliging nodig hebt.schema.yaml
De complete schema.yaml, met instructielichamen weggelaten. Elk wordt volledig getoond in zijn sectie hierboven.
name: spec-driven
version: 1
description: Standaard OpenSpec-workflow - proposal → specs → design → tasks
artifacts:
- id: proposal
generates: proposal.md
description: Initieel voorsteldocument dat de wijziging schetst
template: proposal.md
# instruction: volledig getoond onder proposal.md hierboven
requires: []
- id: specs
generates: "specs/**/*.md"
description: Gedetailleerde specificaties voor de wijziging
template: spec.md
# instruction: volledig getoond onder Delta specificaties hierboven
requires:
- proposal
- id: design
generates: design.md
description: Technisch ontwerpdocument met implementatiedetails
template: design.md
# instruction: volledig getoond onder design.md hierboven
requires:
- proposal
- id: tasks
generates: tasks.md
description: Implementatiechecklist met bijgehouden taken
template: tasks.md
# instruction: volledig getoond onder tasks.md hierboven
requires:
- specs
- design
apply:
requires: [tasks]
tracks: tasks.md
# instruction: volledig getoond onder Apply hierboven