-
Notifications
You must be signed in to change notification settings - Fork 2
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.
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 | DeprecatedWhen 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.
.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.
/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 stepsStable 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.
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.
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.
/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 continuePlan status vocabulary: Not started | In Progress | Blocked | Done. It is separate from
the spec's vocabulary and one never overwrites the other.
- 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 — writemanual: <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. -
Recorded —
Verified:stays empty until theVerify: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.
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.
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.
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.
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.
Start here
Reference
Design & interop
- Interop Matrix
- Design Decisions
- Specify Method
- Committing to One Tool
- Migrating from the predecessor
- Releasing
Help