Product Engineering
Spec-driven development: writing the specification as the source of truth
Spec-driven development treats the specification as the source of truth and code as its output. Where that works, where it does not, and the tooling behind it.
Key takeaways
- Spec-driven development treats a written specification as the primary artefact and generated code as its output, rather than the reverse.
- It became viable because generation got cheap: rewriting an implementation from an amended spec is now hours rather than weeks.
- The real benefit is not automation. It is that ambiguity has to be resolved before implementation, when resolving it is cheapest.
- It works well for well-understood problems with clear acceptance criteria and badly for exploratory work where the requirement is discovered by building.
- Do not let the specification become write-only. If it drifts from the code, it is worse than no specification at all.
Spec-driven development inverts the usual relationship between documents and code. For most of the history of software, the specification was overhead. You wrote it because a process demanded it, it was out of date within a fortnight, and the code was the only thing anyone actually trusted. Every experienced engineer learned to treat documentation as a well-intentioned lie.
That calculation has changed, and the reason is economic rather than philosophical.
Why the economics flipped
Specifications went stale because regenerating an implementation from an amended spec was impossible. Once code existed, it was the expensive artefact. Changing the document without changing the code was free, so documents drifted; changing the code without updating the document was also free, so they drifted the other way too.
When an agent can produce a working implementation from a precise specification in an afternoon, that asymmetry weakens. The specification becomes the thing worth maintaining, because it is now the thing you can act on.
Where the tooling actually is
This stopped being a philosophy and became tooling during 2025 and 2026, which is the main reason it is worth a second look now.
GitHub's Spec Kit is the most widely adopted open-source implementation — a CLI that scaffolds a specification, a plan and a task breakdown, then drives a coding agent through them. Its notable design decision is agent-neutrality: it targets a large and growing set of coding agents rather than binding the workflow to one vendor, which matters if you do not want your development process to be a switching cost.
AWS's Kiro takes the opposite approach and builds the workflow into the IDE itself, moving through Requirements, Design and Tasks phases before any code is generated. The phase gate is the product.
Both encode the same claim: the specification is the artefact, and code is downstream of it. They differ on whether that belongs in your repository or in your editor.
There is also early academic work formalising the loop — for example IACDM, which structures AI-assisted development as an adversarial convergence process rather than a single generate-and-review pass. It is worth reading as a signal of where the practice is heading, not as validated methodology; the empirical literature on whether spec-driven workflows outperform ordinary iterative development is still thin.
What a working specification contains
Not a document template. Four things, and they fit on two pages.
Outcome. What changes for the user, in their language. If it names a technology it is written at the wrong altitude.
Constraints. What is fixed: systems to integrate with, compliance requirements, performance floors, budget ceilings including runtime cost, and the skills of the team who will maintain it.
Non-goals. Everything a reasonable reader would assume is included but is not. This is the section that stops scope from growing without anyone deciding it should, and it is the one people skip.
Acceptance criteria. Concrete enough that two people would independently agree on whether they had been met. These become the tests, which is what makes the specification executable rather than decorative.
What is deliberately absent: implementation detail. A spec that dictates the code has stopped being a specification and become a very slow way of writing code.
The loop
- Write the spec. Short. Reviewed by whoever gets to say the work succeeded.
- Derive the tests. Acceptance criteria become failing tests — authored or at minimum approved by a person. This is the step that prevents an agent from grading its own work.
- Generate. The agent implements against the spec and iterates until the tests pass.
- Review the diff. Against the spec, not against your own taste. Does it do what was written?
- Amend the spec, not the code. When something needs to change, change the document and regenerate the affected part. This is the discipline that keeps the two in sync, and it is the one that erodes first.
Step five is where this succeeds or fails. The moment someone patches the code directly under time pressure and does not update the spec, you are back to documentation as fiction — except now people trust it, which is worse than the old situation.
A worked example
Abstractions about specifications are unconvincing, so here is a real one at the size we actually use — short enough to fit on two pages, specific enough to build from.
Outcome. An operations manager finds out within two minutes when a shipment misses its delivery window, without having to watch a dashboard.
Constraints. Events arrive from the existing carrier webhook, which we do not control and which delivers at-least-once. Notifications go to the Slack workspace already in use. Must work for the 40 managers currently in the system, with room for 400. No new user-facing login.
Non-goals. Not building a dashboard. Not handling early deliveries. Not covering the two carriers still on EDI — those come later. Not doing per-user notification preferences in this milestone; everyone in a region gets the same alert.
Acceptance. Given a shipment with a window ending at 14:00 and no delivery event by 14:02, a message appears in the region's Slack channel naming the shipment, the customer and the delay. Given a duplicate webhook event, exactly one message is sent. Given the carrier webhook being down for an hour, no false alerts fire and a single summary appears when it recovers.
Note what that contains and what it does not. No database schema, no service boundaries, no mention of a queue — those are implementation decisions, and a specification that makes them has stopped being a specification.
Note also that the non-goals section is doing the most work. "Not handling early deliveries" and "everyone in a region gets the same alert" are exactly the assumptions that, left unstated, would have been silently implemented one way and argued about later.
The three acceptance criteria become three tests. Once they pass, the milestone is done — not as a judgement call, but as an observation anyone can make.
How it interacts with agentic coding
The two trends are frequently discussed separately and are really the same argument approached from different sides.
Agentic coding made delegation cheap and moved the bottleneck to specification and verification. Spec-driven development is what you do about the specification half. The acceptance criteria that make a spec executable are the same failing tests that stop an agent grading its own work.
That is why the tooling converged so quickly. GitHub's Spec Kit and AWS's Kiro are not really specification products; they are agent-driving products that discovered a specification was the missing input. The workflow they encode — requirements, then design, then tasks, then code — is a bet that the expensive step is now deciding rather than typing.
Whether that bet pays off depends on something the tooling cannot supply: whether the person writing the spec understands the problem. A precise specification of the wrong thing is built faster than a vague specification of the right thing, and the failure is harder to spot because everything downstream looks well-run.
Failure modes to watch for
Four, in rough order of how often we see them.
The spec drifts from the code. Somebody patches production directly under time pressure and does not update the document. Now people trust something untrue, which is worse than having no document. This is the one that kills the practice, and the defence is the discipline of amending the spec and regenerating rather than editing code in place.
Specs grow to fill the available process. Two pages becomes eight, then a template, then a review board. At that point you have reinvented the thing everyone abandoned for good reasons. Hold the page limit; if it does not fit, split the increment.
Implementation detail creeps in. The spec starts naming tables and endpoints. This is usually a sign that whoever wrote it is more comfortable designing than deciding, and it removes the freedom that made regeneration cheap in the first place.
It is applied to exploratory work. Forcing a specification onto something genuinely unknown produces a confident document about the wrong problem. The discipline is knowing which two-thirds of your work it suits.
Where it fits, and where it does not
| Work | Fit | Why |
|---|---|---|
| Well-understood features with clear criteria | Strong | The spec can be precise, and precision is the whole mechanism |
| API and integration work | Strong | Contracts are naturally specifiable |
| Migrations and refactors | Strong | The invariant is explicit: same behaviour, different structure |
| Compliance-driven work | Strong | The requirement already exists in written form |
| Exploratory product work | Weak | You cannot specify what you have not discovered |
| UI and interaction design | Weak | The requirement is "does it feel right", which is not writable in advance |
| Performance investigation | Weak | The problem is unknown until measured |
| Bug fixes | Overkill | The failing test is the specification |
The pattern: spec-driven development is strong where the difficulty is communication and weak where the difficulty is discovery.
Doing it without the ceremony
The failure mode is turning this into a process that generates documents nobody reads. A few things keep it honest:
- Two pages, hard limit. If it needs more, the increment is too big. Split it.
- One spec per increment, not per project. A spec covering six months is a plan, and plans are a different artefact with a different failure mode.
- Version them with the code. Same repository, same pull request, reviewed together — the approach we describe in how to scope a software project. Same repository, same pull request, reviewed together. A spec in a wiki has already started drifting.
- Delete them when they are done. A merged, shipped spec has served its purpose; keeping a graveyard of them makes the live ones harder to find. Keep the decisions, not the paperwork.
We work this way by default
Every engagement opens with a short written spec — outcomes, constraints, non-goals and acceptance criteria — agreed before anyone writes code. It is yours whether or not we go on to build the thing.
Adopting it without a process rollout
If you want to try this without announcing a methodology, the smallest useful version is one increment.
- Pick a well-understood piece of work — a feature with clear criteria, not an exploration. Two to four weeks of effort at most.
- Write the two pages before anything else. Outcome, constraints, non-goals, acceptance. Give yourself an hour, not a day; if it needs longer, the increment is too large.
- Have somebody else read it — ideally whoever gets to say the work succeeded. Every question they ask is a decision you had not made.
- Turn the acceptance criteria into failing tests. This is the step that converts a document into something executable.
- Build against it, with or without an agent. The discipline works either way; agents just make the payoff arrive sooner.
- At the end, compare. Did the spec change? Where? Those are the places your understanding was weakest, and they are the most useful output of the whole exercise.
What people usually report after one round is not that they shipped faster. It is that they found two or three unresolved decisions in the first hour that would otherwise have surfaced in week three, when they would have cost considerably more to resolve.
Where the practice came from
None of this is new, which is worth saying plainly because the tooling markets it as though it were.
Specification by example, acceptance-test-driven development and behaviour-driven development all made the same argument a decade or more ago: write down the criteria first, in the language of the business, and let them decide when the work is done. Those practices never became universal, and the reason was economic rather than intellectual — writing a precise specification cost roughly as much as writing the code, and once the code existed the specification stopped being the artefact anyone acted on.
What changed is the ratio. When an implementation can be regenerated from an amended specification in an afternoon, the document becomes the thing worth maintaining, because it is now the thing you can act on. That is the whole of the argument. The practices are borrowed; only the economics are new.
The honest assessment
Spec-driven development is not new. Writing down what you are going to build before building it is the oldest advice in the field, and it has been ignored for decades for a very good reason: it did not pay off, because the spec could not be executed.
What changed is that it now can be, approximately. That is enough to shift the cost-benefit — not enough to make it universal. The teams getting value from it are applying it to the well-understood two-thirds of their work and leaving the exploratory third alone, which is roughly the split you would expect and considerably less exciting than the framing usually suggests.
Frequently asked questions
What is spec-driven development?
A workflow where a structured, version-controlled specification is the primary artefact. You write what the system should do and how you will know it works; an AI agent implements against that spec; the tests derived from the acceptance criteria decide whether it succeeded. When requirements change you amend the specification and regenerate, rather than patching the code and hoping the document gets updated.
How is this different from waterfall?
Waterfall's defining property was a long, expensive, one-way gate — you specified everything upfront because changing course later cost enormously. Spec-driven development works in small increments where regenerating from an amended spec is cheap, so the spec stays alive and changes constantly. The similarity is superficial: writing things down before building is not the same as refusing to change them.
Does spec-driven development actually save time?
Not on the first pass — writing a precise specification takes about as long as it saves. It pays off on the second and third iteration, on handover, and on every occasion where a misunderstanding would otherwise have surfaced after the code was written. The saving is in avoided rework, not in typing.
When should you not use it?
When you do not yet know what you are building. Exploratory work, UI and interaction design, performance investigation and anything where the requirement is discovered by trying things all resist upfront specification. Forcing a spec onto genuinely unknown work produces confident documents about the wrong thing.
What goes in the specification?
The outcome in user-facing language, the constraints that are non-negotiable, an explicit list of non-goals, and acceptance criteria concrete enough that two people would agree on whether they had been met. Notably not: implementation detail. A spec that specifies the code has stopped being a spec.
Is spec-driven development the same as test-driven development?
They overlap and operate at different levels. Test-driven development works unit by unit, inside the implementation, and is a technique for designing code. Spec-driven development works at the level of an increment of user-visible behaviour and is a technique for deciding what to build. The point where they meet is acceptance criteria: a spec's criteria become failing tests, which is what makes the specification executable rather than decorative.
Who should write the specification?
Whoever is accountable for the work succeeding, with review from whoever will build it. That is usually a product owner or founder drafting, and an engineer challenging. The pattern that fails is engineers writing specs for themselves, which tends to produce implementation plans rather than statements of intent, and removes the ambiguity-surfacing benefit that is the main reason to do this at all.
How long should writing a specification take?
About an hour for a two-to-four week increment. If it is taking a day, one of two things is wrong: the increment is too large and should be split, or there are genuine unknowns that no amount of writing will resolve and which need a spike to answer instead. The time cost is not the point anyway — the value is in the decisions the hour forces, which would otherwise surface mid-build at several times the price.
Does spec-driven development work for maintenance and bug fixes?
It is overkill for bug fixes, where the failing test already is the specification. It works well for maintenance that changes behaviour rather than restoring it — a pricing change, a new permission rule, an altered workflow — because those are exactly the cases where the intended outcome is easy to state and easy to get subtly wrong.
References & further reading
- [1]
- [2]
- [3]
- [4]
- [5]Martin Fowler — Specification by Example ↗
martinfowler.com
- [6]
Related reading
Agentic coding: what changes when AI writes most of the code
What agentic coding changes for engineering teams — the METR and DORA evidence, where agents fail, and how to fix review before it becomes the bottleneck.
How we scope a build so it does not run over
The two-page specification format we use before writing code: outcomes, constraints, non-goals and acceptance criteria — and why scoping is now the constraint.
What to build first: cutting scope without gutting the product
How to cut MVP scope without gutting the product: find the moment of value, defer everything off that path, and decide what a person can just do by hand.