Coding agents are good at writing code and bad at guessing what you meant. Give one a two-line prompt for a feature and it will happily fill every gap with its own assumptions: a data model you would not choose, an edge case it decided was out of scope, a library you have never heard of. The code compiles. It is just not the feature you wanted.

Spec-driven development (SDD) is the response that has taken shape over the last few months: write down what you want before the agent writes code, review that, and make the written intent the thing the agent works from. AWS launched Kiro, an IDE built around specs, in preview on July 14, 2025. GitHub open-sourced Spec Kit on September 2, 2025. Thoughtworks' Birgitta Böckeler published a comparison of the tools on martinfowler.com on October 15, 2025.

The idea is old (requirements, design docs, test-first). What is new is that the reader of the spec is now also an agent, which changes what a good spec looks like and how much of the downstream work can be generated from it. This cheatsheet covers the loop, the tools, the templates, and where it goes wrong.

1. Definitions

Term Meaning
Spec A structured description of the behavior you want: user stories, acceptance criteria, constraints, non-goals. Says WHAT and WHY, not HOW
Plan (design) The technical approach for this spec: architecture, data model, interfaces, dependencies, risks
Tasks An ordered list of small, reviewable work items derived from the spec and plan, each traceable to requirements
Constitution / steering Project-wide rules that apply to every spec: stack, conventions, testing policy, things that are never allowed
Spec-driven development A workflow where the reviewed spec is the source of truth for the agent's work, and code is checked against it
Spec drift The spec and the code disagree, and nobody notices

Böckeler's article distinguishes three levels of ambition, which are useful when someone says "we do SDD":

Level Definition (Böckeler) In practice
Spec-first "A well thought-out spec is written first, and then used in the AI-assisted development workflow for the task at hand." The spec drives one change, then is archived or forgotten
Spec-anchored "The spec is kept even after the task is complete, to continue using it for evolution and maintenance of the respective feature." Specs live in the repo next to the code and are updated with it
Spec-as-source "The spec is the main source file over time, and only the spec is edited by the human, the human never touches the code." Code is a generated artifact. Few teams are here

Most teams that try SDD today are doing spec-first. Spec-anchored is where most of the long-term value is, and also where the maintenance cost is.

2. The loop: spec, plan, tasks, implement

Phase Human provides Agent produces Human checks before moving on
1. Specify The goal, users, the problem, what success looks like A detailed spec: stories, acceptance criteria, edge cases, open questions Does it capture the intent? Are the non-goals right? Are open questions answered?
2. Plan Technical direction: stack, constraints, architecture rules A plan: components, data model, interfaces, research notes Does it fit the existing system and constraints? Is anything over-engineered?
3. Tasks (Usually nothing new) Ordered, small tasks, each linked to requirements, including tests Is every requirement covered? Is each task small enough to review?
4. Implement Approval to start, one task or batch at a time Code and tests for each task Does it meet the acceptance criteria? Do the tests actually test them?

Two properties make the loop work: each phase is a checkpoint (catching a wrong assumption in a page of spec costs minutes; catching it in a pull request costs a rewrite), and each artifact narrows the next one (the agent plans from the spec and implements from the plan, not from its own guesses).

When the spec turns out to be wrong during implementation (it will), go back and fix the spec, then regenerate the plan or tasks that depend on it. Patching only the code is how spec drift starts.

3. The tools: Spec Kit and Kiro

GitHub Spec Kit (September 2, 2025)

Spec Kit is an open source toolkit from GitHub, announced by Den Delimarsky on the GitHub blog. It is not an IDE or a model; it is a CLI that sets up templates, scripts and slash commands for the coding agent you already use. The announcement names GitHub Copilot, Claude Code and Gemini CLI.

uvx --from git+https://github.com/github/spec-kit.git specify init my-project

At launch, the workflow maps to agent slash commands:

Command Phase
/specify Generate a spec from a high-level description
/plan Generate a technical plan from the spec plus your technical direction
/tasks Break the spec and plan into tasks
then implement The agent works through the tasks

Böckeler's walkthrough adds the pieces around it: a constitution with "high level principles that are immutable", and a set of generated files per feature such as spec.md, plan.md, research.md, data-model.md and tasks.md. The project moves fast, so check the command names in the version you install.

The repo's spec-driven.md document is worth reading even if you never use the CLI. Two of its rules are good practice anywhere:

  • Specs focus on "WHAT users need and WHY" and avoid "HOW to implement (no tech stack, APIs, code structure)".
  • When the prompt does not specify something, the agent should mark it with [NEEDS CLARIFICATION] rather than guess.

Its example constitution also includes a test-first article: no implementation code before unit tests are written, approved by the user, and confirmed to fail.

The GitHub post positions SDD for three situations: greenfield projects, feature work in existing systems, and legacy modernization. Its framing: "We're moving from 'code is the source of truth' to 'intent is the source of truth.'"

AWS Kiro (preview, July 14, 2025)

Kiro is an agentic IDE from AWS, built on Code OSS (the open source base of VS Code), announced in preview by Nikhil Swaminathan and Deepak Singh. Specs are a first-class feature:

Kiro artifact Content
requirements.md User stories with acceptance criteria in EARS notation, generated from a prompt such as "Add a review system for products"
design.md Technical design from the requirements and the codebase: data flow, interfaces, schemas, endpoints
tasks.md Sequenced tasks linked to requirements, including tests
Steering files Project memory, by default product.md, structure.md and tech.md
Agent hooks Automations triggered by events such as file saves, for example updating tests when a component changes

Kiro also supports MCP servers and a regular agentic chat for work that does not need a spec. AWS describes specs that stay synced with the codebase in both directions: code changes can update specs, and spec changes can refresh tasks.

Side by side

Spec Kit Kiro
Form CLI plus templates for your existing agent Full IDE
Phases Constitution, specify, plan, tasks, implement Requirements, design, tasks
Project rules Constitution Steering files
Agent Bring your own Built in
Weight (Böckeler) Heavier: many markdown files per feature "The simplest (or most lightweight) one of the three I tried"

Böckeler also looked at Tessl (private beta at the time of her article), the only one of the three aiming at spec-anchored and spec-as-source, with a 1:1 mapping between spec files and code files and generated code marked // GENERATED FROM SPEC - DO NOT EDIT.

You do not need any of these tools. A specs/ folder, three templates and a rule in your agent instructions ("read the spec and plan before writing code; stop and ask about anything marked as needing clarification") get you most of the loop.

4. Writing requirements an agent can check: EARS

EARS (Easy Approach to Requirements Syntax) was developed by Alistair Mavin and colleagues at Rolls-Royce and published at the IEEE Requirements Engineering conference in 2009. Kiro uses it for acceptance criteria, and it works well for agents because every requirement has a trigger and an observable response.

Pattern Template Example
Ubiquitous The system shall ... The system shall store amounts in integer cents
Event-driven When ..., the system shall ... When a refund is requested within 14 days of purchase, the system shall issue a full refund
State-driven While ..., the system shall ... While the payment provider is unavailable, the system shall queue refund requests
Unwanted behavior If ..., then the system shall ... If the provider returns a timeout, then the system shall retry once after 2 seconds
Optional feature Where ..., the system shall ... Where the customer has a business account, the system shall attach an invoice PDF

Each line is close to a test name. That is the point.

5. Templates

Keep templates short. The agent can expand them; you have to review them.

spec.md

# Feature: Self-service refunds
ID: 001-refunds | Status: approved | Owner: @alice

## Problem
Support handles ~300 refund tickets/week by hand.

## Users and goals
- Customer: get a refund without contacting support.

## Requirements
- REQ-001 When a customer requests a refund within 14 days, the system shall issue a full refund.
- REQ-002 If the payment provider times out, then the system shall retry once.
- REQ-003 The system shall email a receipt for every refund.

## Non-goals
- Partial refunds. Refunds after 14 days.

## Open questions
- [NEEDS CLARIFICATION] Do gift-card purchases qualify?

plan.md

# Plan: 001-refunds
Spec: specs/001-refunds/spec.md | ADRs: ADR-014 (payment provider client)

## Approach
New RefundService in billing/, uses existing PaymentClient.

## Data model
refunds(id, order_id, amount_cents, status, created_at)

## Interfaces
POST /orders/{id}/refunds -> 201 | 409 (already refunded) | 422 (outside window)

## Risks
Provider idempotency: use order_id as idempotency key.

tasks.md

- [ ] T1 Migration for refunds table (REQ-001)
- [ ] T2 RefundService.request() with 14-day rule + tests (REQ-001)
- [ ] T3 Retry on provider timeout + test with fake provider (REQ-002)
- [ ] T4 Receipt email + test (REQ-003)
- [ ] T5 API endpoint + contract tests (REQ-001, REQ-002)

Small habits that pay off: stable requirement IDs, an explicit non-goals section, open questions that block the plan until answered, and every task citing the requirement it serves.

6. Specs, tests and ADRs: who owns what

A spec does not replace tests or architecture decision records. Each answers a different question:

Artifact Answers Lifetime Who reads it
Spec What should the system do, for whom, and why? What is out of scope? As long as the feature exists (if spec-anchored) Product, engineers, agents
Plan How will this change be built? Usually one change; then it is history Engineers, agents
ADR Why did we choose this architecture over the alternatives? Permanent; superseded, never edited Future engineers and agents
Tests Does the code do what the spec says, right now? As long as the code exists CI

How they connect:

  • Acceptance criteria become tests. Each requirement ID should appear in at least one test. The spec says what; the test proves it, every run.
  • Plans cite ADRs, and decisions found during planning become ADRs. Michael Nygard's 2011 ADR format (title, status, context, decision, consequences) is short enough that an agent can draft one from a plan section for you to edit.
  • The constitution or steering files are the summary of your accepted ADRs plus conventions, written as rules the agent must follow.
  • The tests are the only artifact that cannot drift silently. If a spec says one thing and a test says another, the test is what runs in CI. Make the link between them checkable.

A minimal traceability check, run in CI:

"""Fail CI when a requirement has no test, or a test cites an unknown requirement."""
import re
import sys
from pathlib import Path

REQ = re.compile(r"\bREQ-\d{3}\b")


def ids(paths: list[Path]) -> dict[str, set[Path]]:
    found: dict[str, set[Path]] = {}
    for p in paths:
        for req_id in REQ.findall(p.read_text(encoding="utf-8")):
            found.setdefault(req_id, set()).add(p)
    return found


specs = ids(sorted(Path("specs").rglob("spec.md")))
tests = ids(sorted(Path("tests").rglob("test_*.py")))

untested = sorted(set(specs) - set(tests))
unknown = sorted(set(tests) - set(specs))

for req_id in untested:
    print(f"untested: {req_id} in {', '.join(map(str, specs[req_id]))}")
for req_id in unknown:
    print(f"unknown requirement cited by tests: {req_id}")

sys.exit(1 if untested or unknown else 0)
$ python spec_check.py
untested: REQ-003 in specs/001-refunds/spec.md

It is crude (a requirement ID in a docstring counts as coverage) but it catches the two most common forms of drift: requirements nobody tested, and tests for requirements that were removed or renamed.

7. When to use it, and when not

Situation Use SDD? Why
New feature touching several components Yes The plan step catches integration and data-model mistakes early
Greenfield service Yes Stops the agent from choosing the stack and architecture for you
Legacy modernization Yes Capturing current behavior as a spec is half the work anyway
Unclear requirements Yes, especially The spec phase forces the questions out before code exists
One-line bug fix No Böckeler: "like using a sledgehammer to crack a nut"
Exploratory prototype you will throw away Usually no Speed matters more than traceability

Scale the ceremony to the change. A small change can get a five-line spec with acceptance criteria and no plan. A cross-team feature gets all three files and an ADR.

8. Pitfalls

Pitfall Symptom Fix
Spec drift Code was patched during implementation; the spec still describes the original idea Rule: behavior changes start with a spec change. Run the traceability check in CI. Review spec diffs in the same PR as code
Over-specification The spec dictates class names, libraries and file layout; the agent follows it into a bad design Keep HOW in the plan, not the spec. Specs state behavior and constraints
Review fatigue Hundreds of lines of generated markdown per feature; reviewers skim and approve Short templates, strict non-goals, review the spec diff, not the whole file. Böckeler found Spec Kit's generated files "very verbose and tedious to review"
False sense of control Detailed specs, but the agent ignores parts of them anyway Specs guide; tests verify. Böckeler "frequently saw the agent ultimately not follow all the instructions", and also saw it go overboard following them too eagerly
Agent-written spec, unread The agent writes the spec and the human approves without reading The human owns the spec. If you did not read it, it is not a spec, it is a longer prompt
Stale constitution Project rules still mention the old framework or test runner Treat steering and constitution files as code: owned, reviewed, updated with ADRs
One workflow for every change Bug fixes go through four phases Define two or three sizes of workflow and pick one per change
Plans that never die Old plans and task lists contradict the current code and confuse the agent Archive or delete plans after merge; keep specs (if spec-anchored) and ADRs

Böckeler's broader warning is worth keeping in mind: model-driven development promised that specs would generate code, and largely did not deliver. She wonders whether spec-as-source, and even spec-anchoring, "might end up with the downsides of both MDD and LLMs: Inflexibility and non-determinism." Use specs to improve the agent's input and your review, not as a promise that code no longer needs reading.

Why this matters

  • Agents fill gaps with guesses. A reviewed spec removes the gaps that matter before code exists.
  • Reviewing intent is cheaper than reviewing code. A page of requirements is faster to correct than a large diff.
  • Specs, tests and ADRs are complementary. Specs state intent, tests enforce it, ADRs explain the architecture.
  • The tooling is new and changing. Spec Kit and Kiro are a few months old; the practices (clear requirements, test-first, decision records) are decades old and will outlast them.
  • Drift is the main failure mode. A spec that no longer matches the code is worse than no spec, because agents will trust it.

Final Thoughts

Spec-driven development is not a new methodology so much as an old discipline with a new reader. Writing requirements down, agreeing on them before building, and testing against them was always good engineering. Coding agents make it pay off faster, because the same document that aligns the humans also steers the agent.

Start small: one feature, three short files, requirement IDs in the tests, and a CI check that they match. If that makes the agent's first attempt closer to what you wanted, and reviews shorter, scale it up. If you find yourself reviewing more markdown than code, cut the templates down.

Sources