spec-driven development

Table of content

by Ray Svitla


TDD said: write the test first, then the code. spec-driven development says: write the spec first, then everything else.

the difference isn’t semantic. when an AI agent writes your code, the spec isn’t just documentation — it’s the primary control mechanism. the spec is the code. everything else is compilation.


the problem spec-driven development solves

you open Claude Code. you type “build me an authentication system.” Claude asks some questions, makes some assumptions, and produces code. it works. probably. but it works according to Claude’s interpretation of “authentication system,” which may or may not match yours.

now multiply this by every feature in your application. each one built from a vague description, each one interpreted slightly differently, each one carrying hidden assumptions that nobody documented because the code “works.”

six months later, your codebase is a sedimentary layer of different interpretations of vague instructions, and nobody — including Claude — can explain why the auth system works the way it does.


specs as control

a spec is a contract between you and the agent. not a suggestion. not a guideline. a contract.

## authentication system spec

### behavior
- users register with email + password
- passwords: bcrypt, minimum 12 characters, no maximum
- login returns JWT (1 hour expiry) + refresh token (30 days)
- refresh tokens: single-use, rotating, stored hashed in DB
- failed logins: lock account after 5 attempts for 15 minutes

### API endpoints
- POST /auth/register → 201 {user, token} | 409 conflict
- POST /auth/login → 200 {token, refreshToken} | 401 unauthorized
- POST /auth/refresh → 200 {token, refreshToken} | 401 invalid
- POST /auth/logout → 204 (invalidates refresh token)

### not in scope
- OAuth / social login (separate spec)
- email verification (separate spec)  
- password reset (separate spec)

give this to Claude Code. the output will match the spec. not because Claude is smarter — because the spec removed ambiguity. there’s nothing left to interpret.


spec-driven vs TDD

TDD tests behavior after you’ve decided what the behavior should be. spec-driven development is the step before TDD — deciding what the behavior should be.

traditional:  idea → code → tests → bugs → more code
TDD:          idea → tests → code → refactor
spec-driven:  spec → tests → code → verify against spec

the spec generates the tests. the tests verify the code. the code implements the spec. the spec remains the source of truth. when the spec changes, tests and code follow.

with agentic coding, this sequence becomes almost automatic. write the spec. tell Claude “implement this spec with tests.” review the output against the spec. the review is fast because you’re comparing output to a written contract, not reconstructing intent from memory.


what makes a good spec

specific enough to be testable. “the API should be fast” is not a spec. “the /auth/login endpoint responds in under 200ms at p95 with 100 concurrent users” is a spec.

scoped enough to be implementable. a spec that covers your entire application is a architecture document, not a spec. specs cover one feature, one module, one boundary.

explicit about what’s excluded. half the ambiguity in software comes from unstated assumptions about scope. “not in scope” sections prevent Claude from building OAuth when you asked for password auth.

versioned. specs change. that’s fine. what’s not fine is specs changing without anyone noticing. keep specs in version control next to the code they describe.


the workflow

  1. write the spec. spend time here. this is the thinking phase. every minute spent on the spec saves ten minutes of debugging wrong implementations.

  2. review the spec. have Claude (or a human) poke holes in it. “what happens when the refresh token is used after the user changes their password?” if the spec doesn’t answer this, add the answer.

  3. generate tests from the spec. Claude reads the spec, writes test cases for every specified behavior. review the tests — they should map 1:1 to spec requirements.

  4. implement. Claude writes code that passes the tests. this is the fast part. with good specs and good tests, implementation is almost mechanical.

  5. verify. run the tests. compare behavior to spec. if they diverge, the question is clear: is the spec wrong, or is the code wrong? no ambiguity.


the cultural shift

spec-driven development requires accepting something uncomfortable: the most valuable artifact in your codebase might be a markdown file, not a source file.

developers resist this. code feels productive. specs feel like bureaucracy. but when an AI agent writes code at 1000x your speed, the bottleneck shifts from “writing code” to “knowing what code to write.” the spec is where that knowledge lives.

this doesn’t mean every function needs a spec. it means every feature boundary, every API contract, every behavior that users depend on should have a written spec before it has code. the internal implementation details can remain unspecified — Claude handles those fine on its own.


where this falls apart

exploratory work. when you don’t know what you’re building yet, writing a spec is premature. prototype first, spec later. spec-driven development is for when you know what “done” looks like.

rapidly changing requirements. if your spec changes every day, maintaining the spec becomes overhead instead of leverage. this is a sign you need more exploration, not more specs.

solo projects with clear vision. if you’re the only developer and you know exactly what you want, the spec lives in your head and writing it down might be wasted effort. might. most people’s mental specs have more gaps than they think.

do you write specs before asking Claude to build something, or do you prompt and pray?


context engineering — specs as context artifacts → CLAUDE.md guide — the project-level spec → ai code review patterns — reviewing against specs


Ray Svitla stay evolving

Topics: development methodology specs tdd agentic-coding