Spec-driven development: Spec Kit, Kiro, and what sticks

The third rebuild was the one that made the point. A team had asked their coding agent for a bulk-import feature, got a clean implementation in an afternoon, demoed it, and discovered it deduplicated on the wrong key. Rebuilt it. The second version handled the key correctly and rejected the entire file on a single bad row, which nobody had said it shouldn't. Rebuilt it again. The third version was fine, and by then they had spent more time discovering what they wanted than any of the three implementations had taken.

Nothing was wrong with the agent. Each version was a faithful implementation of what it had been told. The problem is structural, and it's the premise of this whole movement: when implementation gets cheap, the expensive mistake becomes building the wrong thing precisely — and the requirement that would have prevented it lived in a Slack thread, a product manager's head, and a prompt that was thrown away after it ran.

Spec-driven development is the response. The idea is simple enough to state in one sentence and takes real judgment to apply, which is the interesting part.

What spec-driven development actually claims

SDD makes the specification the durable, version-controlled, reviewed artifact, and treats code as its output — regenerable, and traceable back to the requirement that caused it. Three things follow from that, and they're what distinguish it from the two things it superficially resembles:

What's durableWhat review catchesFailure mode
Prompt-driven ("vibe coding")The code. The prompt is discarded.Whatever a reviewer notices in a large diffNobody can say what was intended, so nobody can say if it's wrong
Classical up-front specA document, written onceEverything, before anything is realCode and spec diverge within a sprint, and the document rots
Spec-drivenThe spec, continuously — it's the input to every regenerationIntent, before implementation is paid forSpec drift, if the loop back from code to spec is never closed

The word doing the work in that third row is continuously. A spec written once and abandoned is waterfall with extra steps. What makes SDD different is that the spec is executable in the practical sense: an agent reads it and produces the plan, the tasks and the code, so a change to the spec has somewhere to go.

The artifact chain, and what each tool calls it

Both major toolkits landed on nearly the same sequence, which is a decent signal that the sequence is right rather than the branding.

StageGitHub Spec KitAWS KiroWhat it's actually for
Standing rulesconstitutionSteering filesProject-wide principles the agent must not violate. Written once, reused forever.
What & why/speckit.specifyRequirements — user stories with EARS-notation acceptance criteriaIntent, testable. No technology in it.
How/speckit.planDesign — interfaces, schemas, data flow, endpointsThe architecture review, while it's still cheap to change
Work breakdown/speckit.tasksTasksResumable units; the thing an agent can finish and you can check
Build/speckit.implementImplementation, traced to requirementsThe part everyone thought was the hard bit

Spec Kit is GitHub's open-source toolkit — a CLI plus a set of slash commands that work across a long list of agents (Claude Code, Copilot, Cursor, Gemini CLI, Codex and others), which makes it the tool-agnostic option and the easier one to adopt incrementally. Kiro is AWS's agentic IDE, generally available since March 2026 and positioned as the replacement for Amazon Q Developer; it's more opinionated, and its use of EARS — a constrained syntax for requirements, of the form "When <trigger>, the system shall <response>" — is the single most underrated idea in this space, because it makes acceptance criteria unambiguous enough to test mechanically.

You can also run the whole pattern with no toolkit at all: a markdown spec template in the repo, an AGENTS.md for standing rules, and your existing ADRs for decisions. That's what I'd do first, and I'll come back to why.

graph TB
  INTENT["Intent
a person wants something"] --> SPEC["Spec: what & why
testable acceptance criteria"] RULES[("Standing rules
constitution / steering / AGENTS.md")] -.->|"constrains every stage"| SPEC SPEC --> REVIEW1{"Human review
of INTENT"} REVIEW1 -->|"wrong thing"| SPEC REVIEW1 -->|"right thing"| PLAN["Plan: how
interfaces, schemas, data flow"] PLAN --> REVIEW2{"Human review
of ARCHITECTURE"} REVIEW2 -->|"wrong shape"| PLAN REVIEW2 -->|"right shape"| TASKS["Tasks
resumable units"] TASKS --> IMPL["Implementation
agent-authored"] IMPL --> VERIFY{"Tests + review
against the spec"} VERIFY -->|"code is wrong"| IMPL VERIFY -->|"SPEC was wrong"| SPEC VERIFY -->|"passes"| MERGE["Merge"] MERGE -.->|"reality changed the design"| SPEC

Two edges make this SDD rather than waterfall, and they're the ones tools don't enforce for you: the dotted line from merged code back to the spec, and the "spec was wrong" branch out of verification. Without them the spec is a document that was true once. Note also where the human reviews sit — on intent and on architecture, the two places where being wrong is cheapest to fix and most expensive to discover later.

What genuinely works

Review moves to where it's cheap. This is the real win and it's not primarily about AI. Reviewing a paragraph of intent takes two minutes and catches "you're deduplicating on the wrong key"; reviewing the resulting eight hundred lines takes forty minutes and catches formatting. When implementation is nearly free, the only review that pays is the one that happens before it.

The plan step catches architecture errors while they're still opinions. Making the agent produce interfaces, schemas and data flow before code gives you an artifact an architect can argue with in ten minutes. I've killed more bad designs in that step than in any code review, because at that point nothing has been built and nobody is defending their afternoon.

Standing rules are the highest-leverage file in the repository. A constitution, steering file or AGENTS.md that states your build and test commands, your error-handling conventions, the directories that are off limits and the patterns you consider settled will improve every generated change from now on. This is the paved-road idea from engineering standards, in a form a machine reads — and AGENTS.md has become the cross-tool convention for exactly that, read natively by most current agents and understood by the rest via an import.

Tasks make agent work resumable and checkable. A named task with a definition of done is something an agent can finish and a human can verify without reading the whole change. It's also the unit that survives a context window ending, which matters more in practice than it sounds.

What is ceremony

Being honest about this is what makes the rest credible.

Small changes. A spec, plan and task breakdown for a two-line bug fix costs more than the fix and produces three artifacts nobody will ever read again. There's a size below which SDD is pure overhead, and pretending otherwise is how teams come to resent it.

Generated specs nobody reads. The failure I see most: the agent writes the spec, the human skims it, approves, and it becomes a longer prompt with extra steps. If the human doesn't argue with the spec, the process has added latency and removed nothing. The value is in the disagreement.

Exploratory work. When you don't yet know what you want, specifying it is a way of pretending you do. Prototype first, throw it away, then write the spec — the prototype is how you find out what the acceptance criteria should say.

EARS everywhere. The notation is excellent for acceptance criteria on a defined behaviour and terrible for describing a user experience or a design intent. Use it where it fits and write prose where it doesn't; forcing everything through a syntax produces documents that are precise about the wrong things.

What the evidence actually supports

You'll see large numbers attached to SDD — sizeable reductions in rework, multiples on delivery speed. Nearly all of them are community or vendor reports without a control, and I'd treat them the way I'd treat any self-reported productivity gain, which is to say sceptically. Two pieces of real research shape how I'd position the practice:

METR's randomized trial in mid-2025 found experienced open-source developers were about 19% slower completing real tasks in familiar codebases when allowed to use AI tools — while estimating afterwards that they'd been roughly 20% faster. That perception gap is the most important number in this field, because it means your team's impression that this is working is not evidence that it's working.

DORA's 2025 report on AI-assisted development, drawing on responses from thousands of practitioners, found AI acting as an amplifier: it magnifies the strengths of organizations that already have good practices and magnifies the dysfunctions of those that don't. Which lines up exactly with what I see — SDD is a practice for making intent explicit, and it helps teams that were already capable of arguing about intent.

Read together, they suggest where SDD earns its cost: unfamiliar codebases, high consequence of being wrong, multiple stakeholders with different mental models, and work large enough that a wrong implementation is expensive. And where it doesn't: a senior engineer changing code they know well.

Adopting the idea without buying the tool

Start with two files and one habit. The files are an AGENTS.md with your standing rules and a spec template; the habit is that anything above a threshold size gets a spec reviewed by a human before implementation starts.

# Spec: bulk customer import

## Why
Ops currently re-keys ~200 customers/month from partner CSVs. Errors reach billing.

## Scope
IN:  CSV upload, validation, dedupe, partial commit, error report
OUT: partner API integration (separate spec), historical backfill

## Acceptance criteria

- WHEN a valid CSV is uploaded, THE SYSTEM SHALL import all valid rows and
  return a report listing every rejected row with its reason.
- WHEN two rows share the same `partner_ref`, THE SYSTEM SHALL treat the LAST
  occurrence as authoritative.               
- WHEN any row fails validation, THE SYSTEM SHALL still commit the valid rows.
                                             
- WHEN the same file is uploaded twice, THE SYSTEM SHALL NOT create duplicates.
- The error report must be understandable by an ops user without engineering help.

## Non-functional
- A 50k-row file completes within 5 minutes; the UI never blocks.
- Import is auditable: who, when, which file, which rows.

## Open questions   
- Are partner_refs unique across partners, or only within one? (blocks dedupe design)
- Who receives the error report — uploader, or the ops queue?

## Decisions
- ADR-034: partial commit over all-or-nothing. See docs/adr/034.md

Two sections in there do most of the work. Open questions is where a spec earns its keep — it makes the ambiguity visible before someone codes past it, and in that team's case both of the questions listed were exactly the ones that caused the rebuilds. And Decisions links out rather than restating: a spec says what and why for one feature; an ADR records one decision immutably, and conflating the two gives you a document that can't be updated and a decision record that keeps changing.

Where SDD sits against the rest of the architecture set

Worth being precise, because these get muddled and the muddle produces documents with no audience:

  • ADD — what are we building overall, and why this shape? System-level, thin, oriented to a stakeholder.
  • ADR — one decision, immutable, superseded rather than edited.
  • Spec — one feature: intent, acceptance criteria, scope boundaries. Lives as long as the feature, updated when it changes.
  • Standing rules (AGENTS.md / constitution / steering) — how this repository is built, in a form an agent applies to every change.

The last one is new, and it's the one I'd add first even if you adopt nothing else from SDD. It converts your engineering standards from a wiki page people forget into context that gets applied on every generated line.

Three ways spec-driven development goes wrong. Spec drift, which is worse than having no spec. Code changes under time pressure, the spec doesn't, and now you have a confident document that describes a system you don't have — and the next agent reads it and "fixes" the code to match. The discipline that prevents it is unglamorous: if the change makes the spec wrong, the pull request updates the spec, and review rejects it if it doesn't. The agent writes the spec, and the human approves it. Then whose intent is captured? You've automated the one step whose entire purpose was human judgment. Let the agent draft — it's genuinely good at structure and at surfacing questions — but the acceptance criteria and the open questions need a person who will be blamed if they're wrong. Specifying the solution instead of the problem. A spec full of implementation detail ("use a hash map keyed by partner_ref") forecloses better designs and turns the plan step into transcription. Say what must be true, not how to make it true; the how belongs in the plan, where an architect can argue with it.

When to use it

SituationApproach
Two-line fix, familiar codeJust make the change. A spec is overhead.
A feature with more than one stakeholderFull SDD. This is where it pays — the disagreement surfaces on paper.
Unfamiliar codebasePlan step especially — make the agent state its understanding of the existing design before it changes it.
Exploratory / "I'll know it when I see it"Prototype, discard, then spec.
Regulated or high-consequence changeFull SDD, and keep the spec as evidence — it's the traceability an auditor asks for.
Anything at all, in a repo with no standing rulesWrite AGENTS.md first. Highest return of anything on this page.

What to carry away

When implementation is cheap, the expensive mistake is building the wrong thing precisely — and SDD's answer is to make the specification the durable artifact, reviewed before implementation is paid for, with a loop back from code to spec that keeps it true. That loop is the whole difference between this and waterfall, and no tool enforces it for you.

Both toolkits converge on the same chain — standing rules, then intent, then design, then tasks, then code — which suggests the sequence matters more than the vendor. Spec Kit is the tool-agnostic way in; Kiro is the opinionated IDE, and its EARS-style acceptance criteria are worth stealing regardless of what you use.

Be honest about the evidence: the measured research shows AI assistance can slow experienced developers on familiar code while feeling faster, and that AI amplifies whatever practice you already have. So apply SDD where it earns its cost — multiple stakeholders, unfamiliar code, high consequence, real size — and skip it where it doesn't. Start with AGENTS.md and a spec template with an open questions section, let the agent draft but never let it own the intent, and make "the pull request updates the spec" a rule your review actually enforces.