Skip to content

SDD — Spec-Driven Development with Speckit

Coffer uses Speckit for spec-driven development. Every PR that changes externally visible behavior updates the relevant spec.md first, then the code.

Folder Layout

All specs live flat under specs/<NNN>-<short-name>/, where NNN is a zero-padded three-digit ordinal (001, 002, …). There is one kind of spec — no foundation / capability / quality split.

Cross-cutting mechanisms (audit, credentials, events, jobs, storage, session) get shared modules rather than their own specs; the "extract only after the second feature needs them" rule is the invariant in .specify/memory/constitution.md.

specs/<NNN>-<short-name>/
  spec.md              # User-visible contract. Generated by /speckit-specify.
                       # Includes "## Acceptance Scenarios" section
                       # (Spec Kit convention — scenarios live in spec.md,
                       #  NOT in a separate .feature file).
  plan.md              # Implementation plan. Generated by /speckit-plan.
  tasks.md             # Work breakdown. Generated by /speckit-tasks.
  research.md          # Background, alternatives. /speckit-plan Phase 0.
  data-model.md        # Entities, fields, relationships. /speckit-plan Phase 1.
  contracts/
    api.openapi.yaml   # Wire contract (hand-authored, PR-reviewed).
    events.json        # Event schemas (when applicable).
    tools.json         # MCP tool schemas (when applicable).
  quickstart.md        # How to use this feature. /speckit-plan Phase 1.
  checklists/
    review.md          # Generated by /speckit-checklist.
    release.md

One spec per behavior, not per layer. A spec covers the entire vertical slice — backend services plus whatever surfaces are needed to deliver that user-visible behavior (CLI, MCP / shim, REST). Do not split a single behavior into separate per-surface specs; that creates drift between two halves of the same contract.

Skeleton-first phase: When seeding a new spec, write spec.md first. Other files (plan.md, tasks.md, contracts/, etc.) are added when the spec moves toward implementation, via /speckit-plan and /speckit-tasks.

Keep the Docs in Sync With the Code

When a change alters behavior, update the spec and every related doc in the same PR — before or alongside the code, never as a follow-up. Spec-first: the spec is the source of truth and the code conforms to it. "Related docs" is the whole set, not just spec.md:

  • specs/<NNN>/spec.md (+ its spec.zh.md companion) — the user-visible contract and its acceptance scenarios.
  • specs/<NNN>/contracts/api.openapi.yaml — the wire contract; add/rename/remove endpoints and schemas to match the code.
  • specs/<NNN>/data-model.md, plan.md, quickstart.md (+ each .zh.md companion) — entities, plan, and usage prose.
  • Cross-cutting docs the change touches: the relevant docs/decisions/ ADR, .specify/memory/architecture.md, and any affected agents/* convention such as agents/visual-language.md.

Every prose .md has a .zh.md companion that must be updated in the same commit (the only exemptions are tasks.md and the OpenAPI YAML). The acceptance audit (scripts/audit_acceptance.py, run by make verify) ties each spec.md scenario name to a test marker, so renaming/adding/removing a scenario means updating its @pytest.mark.acceptance(... scenario=...) / acceptance(...) marker too. A pure refactor or a frontend-only change with no contract impact needs no spec edit — but if behavior, an endpoint, a schema, or the IA changes, the docs change with it.

Acceptance Scenarios — In spec.md, Gherkin-Style

Use Gherkin-style language inside the ## Acceptance Scenarios section of spec.md. Each scenario maps to one or more tests (see testing.md).

markdown
## Acceptance Scenarios

### Scenario: <verb-led short name>

- **Given** <precondition>
- **When** <action>
- **Then** <observable outcome>
- **And** <additional assertion>

Tests cover each scenario via the acceptance(spec, scenario) marker — see testing.md "Acceptance Scenarios — Cross-Tier Markers".

End-to-End Deliverable Rule

Every feature, on completion, must deliver a usable end-to-end product: backend persistence + the surfaces that expose it (CLI, MCP / coffer-mcp-shim, REST) — all wired so the user can really operate the feature.

A spec is "shipped" only when the end-to-end deliverable works AND every acceptance scenario has at least one covering test.

Markdown Style for spec.md

  • spec.md is for the user-visible contract; ≤ 300 lines preferred.
  • Don't restate architecture in spec.md; reference .specify/memory/constitution.md.
  • Use plain English. Avoid jargon.
  • No time annotations (Day N, Last updated, etc.) in spec / plan / research / data-model / quickstart.