quarta-feira, 4 de novembro de 2026

SDD - Spec Driven Development

🇧🇷 Leia este post em português

spec.md AI ✔ tests passing Spec-Driven Development intent first, code second

If you already use AI to write code, you have probably lived this scene: you describe a feature in two lines, the assistant generates forty files, and halfway through the diff you find out it invented a business rule, ignored an edge case and created a table you never asked for. The code even compiles, but it is not what you wanted.

The problem is almost never that the AI is "dumb". The problem is that the intent was never written down. That is exactly what Spec-Driven Development (SDD) solves. In this post I explain what SDD is, how each step works and how to organize the folders, and at the end I introduce an open source template I built to apply SDD with Claude Code.

What is Spec-Driven Development?

SDD is a way of working in which the specification, not the code, is the source of truth. Before any line of code there is a short spec, versioned in the repository, that says:

  • what must happen (objective and observable behavior);
  • why (context, who depends on it);
  • which rules apply (numbered business rules);
  • how to know it is done (verifiable acceptance criteria).

The code is derived from that spec through an explicit chain: spec → tasks → code → review → security. Tests cite the rules they cover, and the review checks that every rule has its test. When reality changes, the spec changes first, and only then the code.

In one sentence: with SDD you review intent before you review code. Approving a two-page spec is much cheaper than undoing a forty-file diff.

Why SDD took off with AI

The idea of specifying before coding is not new (TDD and BDD were already heading that way). What changed is that most of the code is now written by an agent that cannot guess requirements and forgets everything when the session ends.

So-called vibe coding (chatting with the AI until it "looks good") works very well for prototypes. But in a system you are going to maintain, decisions made in the chat get lost, every new session starts from scratch and nobody can really review what was agreed.

Vibe coding SDD
Source of truth The chat history Spec files in the repository
Ambiguity Discovered in the diff Resolved before the code
Review One "looks good" at the end One check-point per step
Tests If there is time left One test per business rule
New session Starts from scratch Reads the same specs and conventions
Best for Throwaway prototypes and scripts Anything you are going to maintain

The SDD cycle, step by step

There are several variations of the flow (GitHub Spec Kit, for example, separates a "technical plan" from the spec). The version I use has a fixed foundation and five steps, each with an approval check-point:

The SDD cycle 1 · Specify spec · rules · flows 2 · Tasks tasks.md per layer 3 · Implement code + tests 4 · Review spec compliance 5 · Security 0 open Critical/High ✔ Done clean commit changed? spec first 0 · Project foundation (read in every step) CLAUDE.md · ai/conventions.md · ai/module_map.md

Step 0 — The project foundation

Before the first feature, the project needs a set of permanent principles that every spec inherits. Some tools call this a "constitution". It covers the architecture (which apps exist, where each kind of code lives), the conventions (test and lint commands, naming, database, environment variables, commits) and the non-negotiable rules (for example: "every business rule has a test" or "no secrets in the code").

This foundation lives in lean files, because the assistant reads them in every session. Detail lives in documents loaded only when needed.

Step 1 — Specify

You describe the feature and the AI asks questions until the ambiguities are gone. The result is three short files in /specs/<feature>/:

  • spec.md: objective, context, functional and non-functional requirements, numbered acceptance criteria (AC-1, AC-2…), edge cases and what is out of scope;
  • rules.md: the business rules, each one numbered (R-1, R-2…), stating who it applies to, when, and what happens when it is violated;
  • flows.md: the end-to-end flows (F-1 happy path, F-2 failure…), with numbered steps that cite the rules.

Notice that the spec talks about behavior, not technology. "An expired coupon is rejected with message X" is spec. "Add an index on the expires_at column" is an implementation detail.

Check-point: you read and approve the spec before moving on.

Step 2 — Tasks

The approved spec becomes a tasks.md: a list of small, ordered, verifiable tasks, each pointing to the app, module and layer where it will live and to the rules and criteria it implements. When more than one app is affected (say, back end and front end), the file starts with the contract between them (endpoint, request, response, errors), so both sides implement the same thing.

Check-point: you check that the breakdown makes sense and nothing was left out.

Step 3 — Implement

Now the code. The agent follows tasks.md task by task, writes the tests along the way, follows the foundation's conventions and leaves lint clean. If it hits something the spec does not answer, it stops and asks instead of inventing. That is the whole point of SDD.

Check-point: green tests and a look at the diff.

Step 4 — Review

A compliance review, not a matter of taste: was every rule and every acceptance criterion implemented? Does every rule have a test that cites it? Is the code in the right layer, with no business logic leaking into a controller or a screen? Findings come ranked by severity.

Check-point: you decide whether to fix the blocking findings now before moving on.

Step 5 — Security

An AppSec checklist over what changed: access control, injection, secrets, data exposure, dependencies. Findings are mapped to OWASP and there is a gate: nothing is done while a Critical or High finding is open. Security becomes a mandatory step, not a reminder for later.

Check-point: you confirm that no Critical or High finding is left.

Only then comes the commit, ideally with a final scan of the diff to make sure no secret, credential file or real data is going along with it.

Traceability: the thread that ties it all together

The numbering (R-n, AC-n, Tn) looks like bureaucracy, but it is what makes the review objective. Each piece cites the previous one, so you can follow the thread from the rule to the test:

R-1 rules.md AC-1 spec.md T2 tasks.md test cites R-1 review ✔ checks it all a rule without a test, or a test without a rule = a review finding

Example: a real spec (abridged)

Imagine the feature "apply a discount coupon to the cart". A lean version would look like this:

# specs/discount-coupon/rules.md

## R-1 — Expired coupon
A coupon past its expiry date is rejected with
"Coupon expired". The cart does not change.

## R-2 — One coupon per order
Applying a second coupon replaces the first one.

## R-3 — Minimum total
A discount never takes the total below $0.00.

# specs/discount-coupon/spec.md (excerpt)

## Acceptance Criteria
- AC-1: a valid coupon reduces the total and shows in the order summary.
- AC-2: an expired coupon shows "Coupon expired" and keeps the total (R-1).
- AC-3: a $50 coupon on a $30 cart results in a $0.00 total (R-3).

## Out of Scope
- Stackable coupons.
- Coupons on subscription checkout.

With this in hand, anyone (or any model) knows exactly what to build, what to test and what not to build.

Folder structure

Everything lives in the repository itself, next to the code, and goes through the same code review. A layout that works well:

my-project/
├── CLAUDE.md                  # lean foundation, read in every session
├── ai/
│   ├── module_map.md          # where each kind of code lives
│   ├── conventions.md         # commands, tests, naming, database, env, commits
│   └── docs-authoring-rules.md
├── docs/
│   ├── Product.md             # product vision
│   └── Architecture.md        # existing projects: written during reverse engineering
├── specs/
│   ├── _template/             # templates: spec, rules, flows, tasks
│   ├── _inventory.md          # legacy features without a spec yet
│   ├── discount-coupon/
│   │   ├── spec.md            # objective, requirements, AC-n, out of scope
│   │   ├── rules.md           # R-1, R-2, ...
│   │   ├── flows.md           # F-1 (happy), F-2 (failure), ...
│   │   └── tasks.md           # T1, T2, ... per app/module/layer
│   └── checkout/
│       └── ...
├── .claude/
│   ├── skills/                # the workflow commands (start, tasks, code...)
│   └── agents/                # tech lead + one specialist per app
├── .sdd/                      # template version + update script
└── src/ ...                   # your usual code

The golden rule is one fact, one home: a business rule lives in rules.md and everything else links to it instead of copying the text. That prevents contradictory specs and saves tokens.

How much SDD should you adopt?

In practice there are three levels of rigor:

  • Spec first: the spec drives the first implementation and is then forgotten. It helps, but it rots quickly.
  • Spec anchored: the spec evolves with the code; every behavior change goes through it. This is the sweet spot for most teams and what I recommend.
  • Spec as source: only the spec is edited and the code is regenerated from it. Interesting, but still experimental.

When to use it (and when it is bureaucracy)

It pays off in any system you are going to maintain: products, APIs, business rules involving money or permissions, teams of more than one person and projects where several AI sessions will work over time. It even works on legacy code: you can write the spec of what the code already does today (reverse engineering) and bring the old feature into the flow.

Skip it for throwaway prototypes, proofs of concept and one-off scripts. For small changes to features that already have a spec, use a short path (implement with tests and a self-review, go through security, and update the spec if code and spec diverge) instead of the full cycle.

Common mistakes

  • A giant spec: if nobody reads it, nobody reviews it. Two pages are usually enough.
  • A spec that picks the technology: the spec says what; the how belongs in the tasks and the conventions.
  • Vague criteria: "must be fast" is not verifiable; "responds in under 300 ms at p95" is.
  • Forgetting "out of scope": it is what stops the AI from building things nobody asked for.
  • Fixing the code but not the spec: in the next session the AI will "fix" it back. The spec changes first.
  • Skipping review and security "just this once": that is exactly when the problem slips through.

Tools

You can do SDD with nothing but markdown files and any assistant, but some tools package the flow: GitHub Spec Kit, Kiro (AWS) and OpenSpec, among others. And there is the project I built for my own daily work, described next.

My template: SDD for Claude Code

🚀 github.com/emersonmendes/sdd

An open source (MIT) set of skills, agents and project docs for Claude Code that puts any project, new or existing, into the flow described in this post. Go to the repository →

Instead of copying generic commands, the template is rendered into your project: a guided setup interviews you (language, name, architecture, technologies, test and lint commands, non-negotiable rules), reverse-engineers the code if the project already exists, and generates the skills with your project's prefix and the docs already filled in.

The commands (replace app with the prefix you choose):

Command What it does
/app.startStep 1: writes spec.md, flows.md and rules.md
/app.tasksStep 2: tasks.md per app, module and layer, with the contract between apps
/app.codeStep 3: implements with tests and clean lint, delegating to the specialist agents
/app.reviewStep 4: spec compliance, architecture, clean code and tests
/app.securityStep 5: OWASP-mapped AppSec checklist with a severity gate
/app.goAll five steps with an approval check-point after each one
/app.expressFast lane for simple features (skips the review, never security)
/app.fixSmall change to a feature that already has a spec
/app.reverseWrites the spec from existing code (brings legacy into SDD)
/app.askTechnical and architecture advisor; writes no code
/app.commitScans the diff for secrets and real data, then makes a clean commit
/app.updateUpdates the project to the new template version

Besides the skills, you get a tech lead agent, which drives the flow and delegates, and one specialist agent per app, which implements its slice and answers BLOCKED: instead of guessing when information is missing.

How to use it: open Claude Code in your project folder and paste the prompt below. The setup's first question is which language you want to use, so the conversation, the specs and the reports can be in English, Portuguese or any other language.

Set up Spec-Driven Development in this project from the template at
https://github.com/emersonmendes/sdd. Clone it into a temporary folder, read its
setup/SETUP.md and follow it step by step: interview me first (start by asking which
language I want to use), reverse-engineer the codebase if this is an existing project,
then render and adapt the skills, agents and project docs. Do not commit anything.

After the setup, day-to-day work looks like this:

/app.go apply a discount coupon to the cart     # full flow
/app.express export orders as CSV               # simple feature
/app.fix expired coupon message                 # small change
/app.commit                                     # clean commit

And when the template evolves, your project gets the improvements with bash .sdd/sdd update (or /app.update). The script does a 3-way merge that keeps the customizations you made to the skills, and your project docs are never overwritten.

Conclusion

SDD is not about writing more documentation. It is about writing the intent once, in the right place, so that humans and AI work from the same source. You trade a few minutes of specification for less rework, objective reviews, tests that mean something and a project any new session understands.

If you want to try it, start small: pick your next feature, write the numbered rules and the acceptance criteria before asking for code, and see the difference. And if you want the flow ready to go in Claude Code, the template is on GitHub. Issues, suggestions and stars are very welcome! ⭐

References