Skip to content

Specs and Plans

Gregor Biswanger edited this page Aug 26, 2026 · 4 revisions

Specs and Plans

A spec says what and why. A plan says how, in steps small enough to verify one at a time. They are two files that live side by side, move together, and together carry the whole state of a piece of work.

The lifecycle folders

Specs live under .specs/, organised by stage:

Folder Meaning
.specs/backlog/ ideas and not-yet-started specs
.specs/active/ specs currently being implemented
.specs/done/ implemented specs with passing acceptance criteria

A spec exists in exactly one folder at a time. Moving means writing to the destination and deleting the original/sdd-lifecycle does this, including the duplicate check across all three folders.

Each spec declares its status near the top:

**Status:** Draft | In Progress | Implemented | Deprecated

When a spec is implemented and its tests pass: set the status to Implemented, de-duplicate, move it to done/, delete the original, and reflect any architectural or process change in the Memory Bank.

/sdd-lifecycle asks for the evidence before that move — a /sdd-compile brief whose verdict is READY, or the Verified: lines from the plan. Ticked boxes on their own are not evidence, and a done/ folder built on self-assessment is a record of optimism wearing the costume of a verification record.

An Implemented spec whose behaviour is changing is not deprecated — it is reactivated: the pair moves back to active/, spec and plan both In Progress, after /sdd-plan Mode C has reported the impact (criterion → steps → code paths) from the traceability table.

If a later change invalidates an already-Implemented spec, set that spec to Deprecated and name the spec that supersedes it. A done/ folder whose contents contradict the repository is worse than an empty one — that is why FeatherSpec now ships with .specs/ empty rather than with its own build history in it.

Naming

.specs/backlog/0007-user-login.md          the spec
.specs/backlog/0007-user-login.plan.md     its plan

NNNN is zero-padded and continues the highest number found across all three folders. slug is short ASCII kebab-case derived from the title (accented and non-Latin characters are transliterated). The plan is named after its spec with a .plan.md suffix, sits in the same lifecycle folder, and always moves with it.

The spec document

/sdd-specify writes it. Sections are used only when the idea needs them, dropped when it does not, and renumbered consecutively so there are no gaps. Headings are written in DocLanguage.

# <Title>

**Status:** Draft
**Plan:** _none yet_

## 1. Summary
## 2. Goal and problem
## 3. Users and roles
## 4. Scope
### In scope
### Out of scope
## 5. Functional flow
## 6. Business rules
## 7. Functional requirements
## 8. Data requirements
## 9. UI/UX requirements
## 10. Interfaces and integrations
## 11. Security, permissions and privacy
## 12. Non-functional requirements
## 13. Error cases and edge cases
## 14. Acceptance criteria
## 15. Technical notes for developers or AI agents
## 16. Assumptions
## 17. Open points
## 18. Definition of Ready
## 19. Definition of Done
## 20. Recommended next steps

Acceptance criteria

Stable IDs, and one of five shapes. Pick the one that fits the requirement; combine them when a requirement needs it:

AC-001  The system shall <response>.                                     (always true)
AC-002  When <trigger>, the system shall <response>.                     (event)
AC-003  While <state holds>, the system shall <response>.                (state)
AC-004  If <fault or misuse>, then the system shall <response>.          (unwanted behaviour)
AC-005  Where <option or config is present>, the system shall <response>. (optional feature)

Why five and not one. Given/When/Then describes a scenario — one concrete run. It fits event-driven requirements and quietly mangles the rest. An always-true invariant forced into "given a bill of 100 across 3 people, when…" shrinks into a single example, and the example is what gets built. A rule that holds while a state lasts becomes a one-off precondition, so you get one check instead of a state machine. A Where-gated option becomes indistinguishable from ordinary state, and nobody notices there are two configurations to build and test.

You may still add a Given/When/Then scenario under a criterion to pin one concrete run down. It illustrates a criterion; it never replaces one.

Vocabulary. Use shall for anything binding; should is non-binding and belongs in no criterion. These words are rejected: typically · usually · appropriate · sufficient · performant · user-friendly · fast · robust · as needed · etc. · and/or — and so is a passive verb with no actor. The test that settles it: if you cannot name the observation that would prove a criterion false, it is not a criterion. Move it to Open points.

Every must-requirement traces to at least one criterion. Prefer criteria a test can decide; when only a person can decide one, say who checks what. This is what lets /sdd-compile report satisfied or pending with evidence instead of an opinion.

Two sections nobody thinks about until they bite:

  • Out of scope — every exclusion ends in — because <reason>, and the reason says not now, not ever, or needs a decision first. Without it, a deliberate product decision and an oversight look identical, and the next agent helpfully builds the thing you excluded.
  • Assumptions — one row each: | A-001 | What we assume | Why we believe it | What breaks if it is wrong |. An assumption with an empty why column is a guess wearing the typography of a requirement. Ask instead, or move it to Open points.

Definition of Ready

The spec is ready when goal and problem are unambiguous · user role and business value are clear · scope and out-of-scope are documented · business rules are testable · at least the happy path is described · relevant edge cases are described or deliberately left out · acceptance criteria are measurable · data, permissions and constraints are clarified or marked as assumptions · open questions are visible.

Definition of Done

Implementation is done when all must-requirements are built · all acceptance criteria pass · tests were added and run green · no out-of-scope functionality was added · security and privacy requirements are met · error handling and relevant logging exist · assumptions were verified or documented · docs and the architecture snapshot were updated where needed.

The plan document

/sdd-plan writes it. The plan is the persisted state of the work — not a design essay.

# Plan — <spec title>

**Spec:** [0007-user-login.md](0007-user-login.md)
**Status:** Not started
**Last updated:** <date>
**Current step:** T-001

## Approach

Two or three sentences: the strategy, the chosen technologies with a one-line why each,
why the steps are ordered this way, and which `.memory-bank/*` files the implementation
will touch.

**Quality gates:** <the commands from `techContext.md` that Verify lines draw on; the
final step runs them all>

## Research

- [Title](https://example.org/doc) — what it settled, retrieved <date>

## Steps

### T-001 — <short imperative title>

- [ ] **Covers:** AC-001, AC-002
- **Do:** what changes, in which files or modules
- **Verify:** the command whose output decides this step (or `manual: …` plus the reason)
- **Verified:** _(empty until it was actually run: date · command · result)_
- **Notes:** _(filled while implementing: deviations, findings)_

## Traceability

| Acceptance criterion | Steps | Code / files | Test | State |
| --- | --- | --- | --- | --- |
| AC-001 | T-001, T-004 | _(filled when the step lands)_ | _(the test that fails without the code)_ | open |

## Session handoff

- **Done so far:**- **Next action:** T-001
- **Open decisions:**- **Environment:** build, run and test commands needed to continue

Plan status vocabulary: Not started | In Progress | Blocked | Done. It is separate from the spec's vocabulary and one never overwrites the other.

What makes a step a baby step

  • One concern — a schema change, one endpoint, one component, one test suite.
  • Small enough to finish in one sitting and read in one diff.
  • Verifiable — every step carries a Verify: line that is a command whose output decides it. Only where the domain genuinely has no machine check — visual layout, wording, a third-party sandbox — write manual: <what a person looks at> and say why no command can settle it. If you cannot state either, the step is too big or too vague. Split it.
  • RecordedVerified: stays empty until the Verify: line was actually run, and the checkbox is ticked only after it is filled. A tick with no recorded result is a claim, not a verification. This is the one rule that stops a plan becoming a list of good intentions.
  • Ordered so the repo keeps working after every step; risky or blocking parts come first.
  • Tied to the spec — each step names the acceptance criteria it serves, every criterion is covered by at least one step, and pure scaffolding steps say so explicitly.

Two duties that are not optional

Keep it current in the same change set as the code. The moment a step's state changes: fill Verified:, tick the checkbox, fill Notes, move Current step, refresh Last updated, rewrite Session handoff. A new session must be able to resume from the plan alone. A plan that quietly drifts from the code is worse than no plan.

Keep traceability honest. Fill the table with real paths (src/auth/login.ts, or file:symbol) as soon as a step lands — never a path that does not exist yet; that is what Do: is for. Name the test that decides each criterion in the Test column. State moves open → built → verified, and reaches verified only on a recorded run — built means the code exists and nothing has proved it works. If no test can decide a criterion, write manual: <who checked what> in the Test cell; an empty cell means nobody checked.

Step IDs are references

They are cited from commits, reports and the traceability table. Append new IDs instead of renumbering, and strike obsolete steps with a one-line reason rather than deleting them.

Why the traceability table is the point

It is what makes change cheap. When a requirement moves, /sdd-plan (Mode C) reads the table in reverse: for every touched acceptance criterion it lists the steps and the code paths already built from it, and reports that impact before anything is edited.

AC-004 changed
  → T-003 (src/split/round.ts), T-006 (test/round.test.ts)
  → T-005 becomes obsolete: the old remainder handling no longer applies

That is the chain spec → plan → code → test, and it is the reason both files are worth keeping current. The last link is the one that is easy to drop and expensive to miss: without it the table tells you which file to edit when a requirement changes, but not which tests will go red — which is exactly the check that catches the regression nobody anticipated.

Where the rules live

The lifecycle policy — folder meanings, status vocabularies, the move procedure — is defined in AGENTS.md, which is loaded in every session. The craft rules for writing these files live in .claude/rules/specs.md and .claude/rules/plans.md, which load when a matching file is read. .specs/README.md is orientation and links, not a restatement.

See Design Decisions for why /sdd-specify, /sdd-plan and /sdd-lifecycle each restate a small set of essentials inline.

Clone this wiki locally