|
| 1 | +# Spec-Driven Development |
| 2 | + |
| 3 | +This document describes how we use spec-driven development (SDD) in this codebase — what it is, why we use it, how the pieces fit together, and how to work within the system as a contributor. |
| 4 | + |
| 5 | +## Why spec-driven development |
| 6 | + |
| 7 | +AI coding agents are effective at writing code but unreliable at making design decisions. Without constraints, an agent will produce working code that doesn't fit the architecture, misses edge cases, or solves a different problem than intended. Spec-driven development addresses this by separating _what to build_ from _how to build it_. |
| 8 | + |
| 9 | +The spec is a short document (80–150 lines) that captures intent, constraints, and sequencing _before_ any code is written. It serves three purposes: |
| 10 | + |
| 11 | +1. **Reduces ambiguity** — the agent works from explicit behavioral requirements instead of inferring intent from vague prompts. |
| 12 | +2. **Creates traceability** — every requirement has an ID, every task traces to a requirement, so nothing gets lost or invented. |
| 13 | +3. **Keeps humans in control** — four review gates ensure the developer approves direction before implementation begins. |
| 14 | + |
| 15 | +--- |
| 16 | + |
| 17 | +## When to use a spec |
| 18 | + |
| 19 | +Not every change needs a spec. We use a three-tier complexity model: |
| 20 | + |
| 21 | +| Tier | Trigger | Process | |
| 22 | +| ------------- | ----------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------- | |
| 23 | +| **Quick fix** | Config edits, CSS fixes, helper functions, single-file changes, presentation-only changes | No spec. Just implement. | |
| 24 | +| **Plan mode** | 3+ steps or architectural decisions, but < 5 files and < 5 unconstrained decisions | Agent enters plan mode, outlines the approach, gets developer approval, then implements. No spec file created. | |
| 25 | +| **Full spec** | 5+ files, 5+ unconstrained decisions, or developer explicitly requests a spec | Use the `writing-spec` skill to collaboratively produce a `spec.md` before any code is written. | |
| 26 | + |
| 27 | +The threshold is intentionally conservative — a spec adds 15–30 minutes of upfront work but prevents hours of rework when the agent builds the wrong thing. |
| 28 | + |
| 29 | +--- |
| 30 | + |
| 31 | +## How the pieces fit together |
| 32 | + |
| 33 | +The SDD system consists of six interconnected files: |
| 34 | + |
| 35 | +``` |
| 36 | +CLAUDE.md ← Agent behavior rules (plan mode, verification, self-improvement) |
| 37 | +docs/ |
| 38 | + architecture.md ← Project structure, layers, dependency rules |
| 39 | + spec-template.md ← Section structure for spec documents |
| 40 | +specs/ |
| 41 | + NNN-feature-name/ |
| 42 | + spec.md ← Individual feature spec (produced by the workflow) |
| 43 | + lessons.md ← Accumulated learnings from past implementations |
| 44 | +skills/ |
| 45 | + writing-spec/SKILL.md ← Four-phase gated workflow for writing specs |
| 46 | + building-blocks/ |
| 47 | + SKILL.md ← Catalog index with short summaries |
| 48 | + rules/ ← One file per building block (full pattern + example) |
| 49 | +``` |
| 50 | + |
| 51 | +The flow between these files: |
| 52 | + |
| 53 | +1. **CLAUDE.md** tells the agent _when_ to write a spec (5+ files or 5+ decisions) and establishes the plan-mode-first workflow. |
| 54 | +2. **writing-spec/SKILL.md** drives the _how_ — the four-phase collaborative process. |
| 55 | +3. **spec-template.md** provides the _structure_ — the section template that the spec fills in. |
| 56 | +4. **building-blocks/SKILL.md** provides the _vocabulary_ — typed building block names that the spec references in its Building Blocks Diff section. |
| 57 | +5. **architecture.md** provides the _context_ — project structure, layer rules, and state management patterns. |
| 58 | +6. **specs/lessons.md** provides _accumulated wisdom_ — patterns learned from past mistakes that feed back into future specs. |
| 59 | + |
| 60 | +--- |
| 61 | + |
| 62 | +## The spec template |
| 63 | + |
| 64 | +Every spec follows a fixed section structure defined in `docs/spec-template.md`. Here's what each section does and why: |
| 65 | + |
| 66 | +### Meta (required) |
| 67 | + |
| 68 | +Status tracking table — `draft` → `review` → `approved` → `implementing` → `done` → `archived`. Keeps the spec lifecycle visible. |
| 69 | + |
| 70 | +### Section 1: Goal & Context (required) |
| 71 | + |
| 72 | +2–5 sentences answering _what problem does this solve and why now_. Constrains intent, not approach. The agent reads this to understand the purpose — if it can't explain the goal, the feature isn't well enough defined. |
| 73 | + |
| 74 | +### Section 2: Requirements (required) |
| 75 | + |
| 76 | +Behavioral requirements using **EARS notation** (Easy Approach to Requirements Syntax). Each requirement follows the pattern: |
| 77 | + |
| 78 | +``` |
| 79 | +WHEN [condition] THE SYSTEM SHALL [behavior]. |
| 80 | +``` |
| 81 | + |
| 82 | +Each requirement gets a stable ID (R1, R2, R3, …) used for traceability — tasks in Section 7 reference these IDs. |
| 83 | + |
| 84 | +**Why EARS?** Traditional requirements are often vague ("the form should validate properly"). EARS forces requirements into unambiguous, testable statements that constrain exactly one observable behavior. The agent can't misinterpret "WHEN the login form is submitted with an empty email field, THE SYSTEM SHALL display an inline validation error without making an API call." |
| 85 | + |
| 86 | +EARS was developed by Alistair Mavin at Rolls-Royce and is documented in the paper [_Easy Approach to Requirements Syntax (EARS)_](https://ieeexplore.ieee.org/document/5328509). The five EARS patterns are: |
| 87 | + |
| 88 | +| Pattern | Template | Use when | |
| 89 | +| ----------------- | ----------------------------------------------- | ----------------------------------- | |
| 90 | +| Ubiquitous | THE SYSTEM SHALL [behavior] | Always-on behavior | |
| 91 | +| Event-driven | WHEN [event] THE SYSTEM SHALL [behavior] | Response to a trigger | |
| 92 | +| State-driven | WHILE [state] THE SYSTEM SHALL [behavior] | Ongoing behavior during a condition | |
| 93 | +| Unwanted behavior | IF [condition] THEN THE SYSTEM SHALL [behavior] | Error handling, fallbacks | |
| 94 | +| Optional | WHERE [feature] THE SYSTEM SHALL [behavior] | Configurable behavior | |
| 95 | + |
| 96 | +In practice, most frontend requirements use the event-driven pattern (WHEN/SHALL). |
| 97 | + |
| 98 | +### Section 3: Non-Goals (required) |
| 99 | + |
| 100 | +Explicit list of what the feature will NOT do. Prevents scope creep and stops the agent from "helpfully" adding unrequested capabilities. |
| 101 | + |
| 102 | +### Section 4: Building Blocks Diff (required) |
| 103 | + |
| 104 | +The core of the spec. Lists every building block that is **added**, **modified**, or **deleted** — referenced by name and type from the building blocks catalog. No implementation details. The agent reads the relevant building block rule file to understand the pattern. |
| 105 | + |
| 106 | +Example: |
| 107 | + |
| 108 | +```markdown |
| 109 | +### Added |
| 110 | + |
| 111 | +- `loginMutation` (mutation) — handles POST /auth/login |
| 112 | +- `LoginForm` (component) — form with email/password fields |
| 113 | + |
| 114 | +### Modified |
| 115 | + |
| 116 | +- `AppRouter` (route) — add /login route |
| 117 | +- `authStore` (store) — add `isAuthenticated` derived state |
| 118 | +``` |
| 119 | + |
| 120 | +### Section 5: Design Decisions (required for non-trivial features) |
| 121 | + |
| 122 | +Key choices with brief rationale — what you chose, what you rejected, and why. Kept short (2–4 decisions max). If you need more, the feature should be split. |
| 123 | + |
| 124 | +### Section 6: Boundaries (required) |
| 125 | + |
| 126 | +Three-tier classification controlling what the agent can do autonomously: |
| 127 | + |
| 128 | +- ✅ **Always** — proceed without asking (e.g., create files in `src/features/auth/`) |
| 129 | +- ⚠️ **Ask first** — needs human approval (e.g., modify API contracts, add dependencies) |
| 130 | +- 🚫 **Never** — hard stops (e.g., modify core auth internals, remove tests, commit secrets) |
| 131 | + |
| 132 | +This pattern comes from [GitHub's analysis of 2,500+ agent configuration files](https://github.blog/ai-and-ml/github-copilot/how-to-write-a-great-agents-md-lessons-from-over-2500-repositories/), where "Never commit secrets" was the single most impactful constraint. |
| 133 | + |
| 134 | +### Section 7: Task Breakdown (required) |
| 135 | + |
| 136 | +Ordered list of independently testable tasks. Each task: |
| 137 | + |
| 138 | +- References building blocks from Section 4 |
| 139 | +- Traces to requirement IDs (R1, R2, …) |
| 140 | +- Includes target file paths |
| 141 | +- Is marked `[P]` (parallelizable) or `[S]` (sequential) |
| 142 | + |
| 143 | +### Section 8: Error & Edge Cases (optional but recommended) |
| 144 | + |
| 145 | +Uses **GIVEN/WHEN/THEN** format (from BDD) for precision: |
| 146 | + |
| 147 | +``` |
| 148 | +GIVEN the user is already authenticated, |
| 149 | +WHEN they navigate to /login, |
| 150 | +THEN redirect to dashboard. |
| 151 | +``` |
| 152 | + |
| 153 | +If you skip this section, expect the agent to guess — and guess wrong. |
| 154 | + |
| 155 | +### Sections 9–11 |
| 156 | + |
| 157 | +- **Acceptance Criteria** (optional) — high-level "done" checklist, often redundant if requirements are precise. |
| 158 | +- **Open Questions** (optional) — unresolved decisions blocking specific tasks. |
| 159 | +- **References** (optional) — links to related specs, mockups, API docs. |
| 160 | + |
| 161 | +--- |
| 162 | + |
| 163 | +## The writing workflow |
| 164 | + |
| 165 | +The `writing-spec` skill guides the developer through a four-phase process. Each phase ends with a human review gate — the agent does not advance without explicit approval. |
| 166 | + |
| 167 | +### Phase 1 — Goal & Scope (Intent) |
| 168 | + |
| 169 | +The developer describes the feature. The agent drafts Goal & Context, Requirements (EARS), and Non-Goals. Before drafting, the agent asks 3–5 clarifying questions about scope boundaries, error scenarios, and unstated assumptions. |
| 170 | + |
| 171 | +**Key principle:** The agent never invents requirements. If the developer hasn't specified a behavior, the agent asks about it. |
| 172 | + |
| 173 | +### Phase 2 — Design (Approach) |
| 174 | + |
| 175 | +The agent proposes a Building Blocks Diff and, for non-trivial features, two plausible designs with tradeoffs. The developer chooses. The winner and rationale go into Design Decisions. Boundaries are drafted. |
| 176 | + |
| 177 | +**Key principle:** Building blocks reference name + type only — no implementation details in the spec. The spec describes a _change to the status quo_, not the code itself. |
| 178 | + |
| 179 | +### Phase 3 — Spec (Sequencing) |
| 180 | + |
| 181 | +Tasks are broken down, traced to requirements, and ordered. Error & edge cases are documented in GIVEN/WHEN/THEN. Open questions are captured. |
| 182 | + |
| 183 | +### Phase 4 — Review & Finalize |
| 184 | + |
| 185 | +The agent runs a structured self-audit and presents findings: |
| 186 | + |
| 187 | +- **Coverage matrix** — each requirement ID mapped to implementing tasks. Flags requirements with zero tasks. |
| 188 | +- **Orphan tasks** — tasks that don't trace to any requirement. |
| 189 | +- **EARS compliance** — flags requirements missing WHEN/SHALL or using vague language. |
| 190 | +- **Boundary specificity** — flags boundary items referencing vague categories instead of file paths. |
| 191 | +- **Building block references** — flags blocks not found in the catalog. |
| 192 | +- **Line count** — reports total; identifies bloated sections if >150 lines. |
| 193 | + |
| 194 | +Issues are fixed before presenting the final spec for developer sign-off. |
| 195 | + |
| 196 | +--- |
| 197 | + |
| 198 | +## Building blocks |
| 199 | + |
| 200 | +Building blocks are typed, named patterns that form the project's architectural vocabulary. When a spec says `loginMutation (mutation)`, that name maps to a specific pattern with defined constraints, layer placement, and a canonical code example. |
| 201 | + |
| 202 | +### The catalog |
| 203 | + |
| 204 | +The building blocks catalog lives in `skills/building-blocks/`. It uses progressive disclosure: |
| 205 | + |
| 206 | +- **SKILL.md** — summary index table with block name, layer, and one-line description. The agent reads this to know _which_ blocks exist. |
| 207 | +- **rules/{block-name}.md** — full description, constraints, and canonical example. The agent reads these _only when implementing_ a specific block. |
| 208 | + |
| 209 | +### Block categories |
| 210 | + |
| 211 | +| Category | Blocks | What they cover | |
| 212 | +| ------------------ | --------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------ | |
| 213 | +| Data Fetching | `mutation-hook`, `query-options-factory`, `query-keys-factory`, `dto-model` | Server reads/writes, cache keys, API response types | |
| 214 | +| State Management | `store`, `provider` | Zustand stores, React Context dependency injection | |
| 215 | +| App Orchestration | `use-case-hook` | Feature-level operations composing mutations + notifications | |
| 216 | +| Component Patterns | `notification-hook`, `pure-component`, `compound-component`, `hoc`, `page`, `facade-hook`, `named-effect` | UI components, hooks, and composition patterns | |
| 217 | +| Data Modeling | `frontend-model`, `value-object` | Domain types, value-based logic grouping | |
| 218 | + |
| 219 | +### How specs reference building blocks |
| 220 | + |
| 221 | +In the spec's Section 4 (Building Blocks Diff), each entry references a block by name and type: |
| 222 | + |
| 223 | +```markdown |
| 224 | +- `addToCartMutation` (mutation-hook) — handles PUT /carts/:id |
| 225 | +``` |
| 226 | + |
| 227 | +The agent then reads `rules/mutation-hook.md` to understand the implementation pattern — error handling conventions, cache invalidation approach, return tuple shape, etc. |
| 228 | + |
| 229 | +--- |
| 230 | + |
| 231 | +## Architecture integration |
| 232 | + |
| 233 | +The spec system works within the project's feature slice architecture documented in `docs/architecture.md`. Key architectural constraints that affect spec writing: |
| 234 | + |
| 235 | +**Feature layers:** Each feature has four layers — `components/`, `application/`, `providers/`, `models/`. Building blocks map to specific layers (e.g., `mutation-hook` → `providers/`, `use-case-hook` → `application/`). |
| 236 | + |
| 237 | +**Dependency rules:** Components and application import from models and providers. Providers and models have no internal feature dependencies. Library-specific code (React Query, etc.) stays inside providers — never leaks beyond. |
| 238 | + |
| 239 | +**API layer:** All HTTP logic starts in `src/lib/api/` (query options factories, mutations, DTOs by resource), then gets exposed through the relevant feature's `providers/`. |
| 240 | + |
| 241 | +**State management:** |
| 242 | + |
| 243 | +| Tool | Use case | |
| 244 | +| ----------- | -------------------------------------------------------------------- | |
| 245 | +| XState | State orchestration with explicit states and constrained transitions | |
| 246 | +| Zustand | Complex local state (auth, modals, etc.) | |
| 247 | +| React Query | Server state and caching | |
| 248 | +| React state | Simple component state | |
| 249 | + |
| 250 | +--- |
| 251 | + |
| 252 | +## Self-improvement loop |
| 253 | + |
| 254 | +After every implementation, the agent captures lessons learned in `specs/lessons.md` — patterns that caused rework, misunderstandings, or repeated mistakes. This file is reviewed at the start of each session so the same mistake doesn't happen twice. |
| 255 | + |
| 256 | +This creates a feedback loop: specs improve over time as lessons accumulate, and the agent's behavior becomes more aligned with the team's expectations. |
| 257 | + |
| 258 | +--- |
| 259 | + |
| 260 | +## Anti-patterns |
| 261 | + |
| 262 | +These are common failure modes the system is designed to prevent: |
| 263 | + |
| 264 | +**Spec that's actually a task list.** "First create the model, then add the service" constrains sequencing but not intent. The agent follows every step and still builds the wrong thing. Fix: write requirements first, derive tasks from them. |
| 265 | + |
| 266 | +**Over-specification that becomes code.** If the spec includes TypeScript interfaces, database DDL, or code snippets, it has crossed from "what" into "how." Implementation details belong in building block patterns and existing code, not the spec. |
| 267 | + |
| 268 | +**Under-specification that forces guessing.** "Handle errors gracefully" without specifying _which_ errors and _what_ "gracefully" means guarantees the agent will guess. Fix: use GIVEN/WHEN/THEN for every error scenario. |
| 269 | + |
| 270 | +**Auto-generated specs without human input.** LLM-generated context files have been shown to reduce task success rates. The developer drives content; the agent structures and challenges it. |
| 271 | + |
| 272 | +**Specs exceeding 150 lines.** If the review cost exceeds the value, the spec fails its purpose. Split the feature or compress the spec. If a section is long, it likely contains content that belongs in architecture docs or coding standards instead. |
| 273 | + |
| 274 | +--- |
| 275 | + |
| 276 | +## Quick reference for contributors |
| 277 | + |
| 278 | +**Starting a new feature:** |
| 279 | + |
| 280 | +1. Describe the feature to the agent. |
| 281 | +2. If it spans 5+ files or involves 5+ design decisions, the agent will initiate the spec workflow. |
| 282 | +3. Collaborate through four phases — review and approve each before moving on. |
| 283 | +4. Once the spec is approved, implementation begins task by task. |
| 284 | + |
| 285 | +**Working on an existing spec:** |
| 286 | + |
| 287 | +- Specs live in `specs/NNN-feature-name/spec.md`. |
| 288 | +- Check the `Status` field in the Meta table. |
| 289 | +- The task breakdown in Section 7 shows what's done and what remains. |
| 290 | +- Open questions in Section 10 may block specific tasks. |
| 291 | + |
| 292 | +**Adding a new building block:** |
| 293 | + |
| 294 | +1. Create `skills/building-blocks/rules/{block-name}.md` following the format of existing blocks. |
| 295 | +2. Add the block to the catalog table in `skills/building-blocks/SKILL.md`. |
| 296 | +3. Use the block name in future specs. |
| 297 | + |
| 298 | +--- |
| 299 | + |
| 300 | +## References |
| 301 | + |
| 302 | +### Project files |
| 303 | + |
| 304 | +- `CLAUDE.md` — agent behavior rules and workflow principles |
| 305 | +- `docs/architecture.md` — project structure, layers, dependency rules |
| 306 | +- `docs/spec-template.md` — spec section structure with inline guidance |
| 307 | +- `skills/writing-spec/SKILL.md` — four-phase spec writing workflow |
| 308 | +- `skills/building-blocks/SKILL.md` — building block catalog index |
| 309 | +- `specs/lessons.md` — accumulated learnings from past implementations |
| 310 | + |
| 311 | +### External references |
| 312 | + |
| 313 | +- [GitHub Spec Kit](https://github.blog/ai-and-ml/generative-ai/spec-driven-development-with-ai-get-started-with-a-new-open-source-toolkit/) — GitHub's open-source SDD toolkit |
| 314 | +- [Addy Osmani: How to write a good spec for AI agents](https://addyosmani.com/blog/good-spec/) — five principles for effective AI specs |
| 315 | +- [Matt Rickard: The Spec Layer](https://blog.matt-rickard.com/p/the-spec-layer) — specs as a constraint layer between humans and AI |
| 316 | +- [Birgitta Böckeler: Understanding Spec-Driven Development](https://martinfowler.com/articles/exploring-gen-ai/sdd-3-tools.html) — comparative analysis of SDD tools (Thoughtworks/Martin Fowler) |
| 317 | +- [Birgitta Böckeler: Harness Engineering](https://martinfowler.com/articles/harness-engineering.html) — guides vs. sensors framework for AI agent constraints |
| 318 | +- [EARS: Easy Approach to Requirements Syntax](https://ieeexplore.ieee.org/document/5328509) — the requirements notation we use (Alistair Mavin, Rolls-Royce) |
| 319 | +- [GitHub: Lessons from 2,500+ agent configurations](https://github.blog/ai-and-ml/github-copilot/how-to-write-a-great-agents-md-lessons-from-over-2500-repositories/) — data-driven findings on effective agent constraints |
| 320 | +- [Eng Leadership: How to Do AI-Assisted Engineering](https://newsletter.eng-leadership.com/p/how-to-do-ai-assisted-engineering) — survey of 15 engineering leaders on SDD practices |
0 commit comments