How it works
Spec-Driven Development inverts the usual order of agentic coding. Instead of prompting an agent and reading whatever it produces, you first commit a written spec, then let the agent implement against it. The spec is the contract; the code is a derivation.
A typical loop:
- Write the spec. State the goal, the constraints, the interfaces, the acceptance checks, and the non-goals. Keep it small enough to read in one sitting.
- Review the spec, not the diff. A human or a second agent argues with the intent while it is still cheap to change. This is where judgment gets spent.
- Delegate implementation. The agent translates the approved spec into code, tests, and migrations.
- Verify against the spec. Acceptance checks and evals confirm the implementation matches what was agreed, not just that it runs.
- Keep the spec as the record. When behavior needs to change, you edit the spec and re-derive, rather than patching code and letting the spec rot.
The spec does not need to be exhaustive. It needs to capture the decisions a reader could not recover by staring at the source: why this boundary, why this tradeoff, what must never happen.
Why it matters in an agent harness
When an agent writes most of the code, the diff stops being a reliable record of intent. A human skims a 600-line change, approves it, and the reasoning behind it exists nowhere. Six weeks later nobody can say whether a behavior is load-bearing or an accident of generation.
A reviewed spec fixes the layer where control is affordable. Arguing about a paragraph is cheap; arguing about a merged implementation is expensive and usually skipped. Moving the decision point earlier means the human spends attention on the choice that matters and lets the agent absorb the typing.
It also gives you something to evaluate against. Acceptance criteria written before implementation are a specification the agent cannot silently negotiate away. They become the fixtures for regression evals and the definition of "done" that a verifier can check. Without a prior spec, an eval only asks "does this pass its own tests" — tests the same agent wrote to match the code it happened to produce.
And it improves reversibility. If the spec is the source of truth, a bad implementation is a re-derivation, not an archaeology project. You revert to the last agreed intent and regenerate, instead of trying to untangle which lines encode a decision and which are incidental.
Spec-Driven Development vs. Vibe Coding
Both use an agent to write code. They differ in where intent is recorded and when review happens.
| Spec-Driven Development | Vibe coding | |
|---|---|---|
| Source of intent | Reviewed spec | The prompt and the resulting code |
| Review target | The spec, before implementation | The output, if at all |
| Durable record | Spec persists and is edited | Intent lives only in the diff |
| Best for | Load-bearing systems, shared code | Throwaway scripts, exploration |
| Failure mode | Spec goes stale if not maintained | Behavior no one can explain |
The distinction changes a decision: for anything you will maintain or that others depend on, the spec earns its cost. For a one-off you will delete tomorrow, it is overhead.
The Rifty take
We treat the spec as the artifact worth protecting, and the code as replaceable. Review attention is scarce, so we spend it on intent while it is still a paragraph, not on a diff after the agent has already committed to an approach. We accept the tax of keeping the spec current, because the alternative — a codebase that is the only surviving record of why it does what it does — is the exact state that makes an agentic system unreviewable and unsafe to change.
Implementation checks
- Keep specs small and answer-first. A spec no one finishes reading provides no control.
- Write non-goals explicitly. Bounding what the agent must not do prevents scope drift as much as stating the goal.
- Put acceptance criteria in the spec before implementation, and wire them into evals so "matches spec" is machine-checkable.
- Review the spec as a first-class step, not the resulting diff as an afterthought.
- When behavior must change, edit the spec and re-derive; do not patch code and leave the spec describing the old world.
- Watch for spec rot: a spec that silently diverges from the code is worse than none, because it lies about intent.
- Keep specs in version control next to the code so intent and implementation move together.
Frequently asked questions
How is Spec-Driven Development different from writing requirements up front?
Traditional requirements sit outside the codebase and drift immediately. Spec-Driven Development keeps a small, versioned spec as the live source of intent that an agent implements against and that acceptance checks verify. The spec is edited and re-derived, not filed away and forgotten after kickoff.
Doesn't writing a spec slow down agentic coding?
It moves cost earlier, where it is cheaper. Arguing about a paragraph beats untangling a merged 600-line diff. For throwaway scripts the spec is overhead, but for anything you maintain or others depend on, reviewing intent before implementation saves far more time than it spends.
How detailed should a spec be?
Detailed enough to capture what a reader could not recover from the code itself: the goal, key constraints, interfaces, acceptance checks, and non-goals. Skip anything the implementation makes obvious. A spec you can read in one sitting provides real control; an exhaustive one no one finishes provides none.
How does a spec help with evaluation?
Acceptance criteria written before implementation become fixtures the agent cannot silently negotiate away. They define "done" that a verifier or regression eval can check. Without a prior spec, tests only confirm the code matches itself, since the same agent wrote both to agree.
What is the main failure mode?
Spec rot. If the code changes but the spec is not updated, the spec starts lying about intent, which is worse than having none. Enforce editing the spec and re-deriving on behavior changes, and keep it in version control beside the code so the two move together.