Atlas / BUILD / AI Engineering / Spec-Driven Development
DEEP-DIVE · AI ENGINEERING

Spec-Driven Development: Specs as the New Source Code

When an agent can write the implementation on demand, the code stops being the asset worth guarding. The specification, precise intent plus executable tests, becomes the artifact you maintain.

TL;DR
  • When generation is cheap and reliable, hand-written code stops being the primary asset. The durable artifact is the specification: requirements, interface contracts, acceptance criteria, and executable tests that an agent implements and a suite verifies.
  • Tests are the executable form of the spec. A passing suite is the definition of done, and the agent iterates against it; the human works at the level of intent, not lines. A good agent prompt is itself a specification.
  • The practice is strongest for well-bounded features with clear acceptance criteria and weakest for exploratory or novel-architecture work, where writing the spec is the hard part. Governance of generated code still applies; treat specs as first-class version-controlled artifacts.

The inversion: code becomes an output

For sixty years the source code was the artifact. It was what you wrote, reviewed, versioned, and defended; everything else, the design docs, the tickets, the diagrams, decayed the moment it left someone's screen because only the code was authoritative and only the code ran. That hierarchy held because writing code was the expensive, skilled, irreducible step. When a coding agent can produce a correct implementation from a precise description in minutes, the economics that made code the crown jewel quietly invert.

The move is not that code stops mattering. It is that code stops being the thing worth maintaining by hand. If an implementation can be regenerated reliably from a sufficiently precise statement of intent, then the implementation is an output, like a compiled binary, and the input is the asset. The durable artifact becomes the specification: the exact statement of what the system must do, under what constraints, verified by what tests. Code is downstream of it, the way object files are downstream of source.

This is an emerging 2025 practice, not a settled industry standard, and it earns its place by naming something teams already feel. Anyone who has watched an agent rewrite a module twice in an afternoon has noticed that the diff is no longer where the value sits; the value sits in knowing precisely what the module was supposed to do. Spec-driven development makes that observation load-bearing.

The regeneration test. Ask of any artifact: if it were deleted, could an agent reconstruct an acceptable version from what remains? If yes, it is an output. If no, it is source. In a spec-driven codebase the implementation passes this test and the specification does not, which is exactly the inversion, and exactly which artifact deserves your review budget.

What a usable spec actually is

The word "specification" invites a lazy reading: a wishful paragraph in a ticket, a wiki page nobody opens twice. That is not what carries the weight here. A usable spec is precise enough that an agent can implement against it without guessing and a test can confirm the result without human judgment. Vagueness is the failure mode; if two competent readers would build materially different systems from the same document, it is not yet a spec.

In practice a usable spec has four parts, and the discipline is in making each one concrete rather than aspirational.

The line between the last two is where spec-driven development gets its power. Acceptance criteria in prose still require a human to adjudicate whether the output satisfies them; the same criteria expressed as tests are self-adjudicating. A spec that stops at prose is a better ticket. A spec that carries its own executable verification is a contract an agent can close against on its own, which is what makes regeneration cheap enough to treat code as an output in the first place.

None of this is new as an ideal; it is a restatement of behavior-driven and contract-first design that most teams admired and few practiced. What changed is the payoff. Precision used to be a courtesy to the next human. Now it is the interface to a machine that will build exactly, and only, what you specified.

Tests as the executable specification

Tests occupy a privileged position in this model because they are the one part of the spec that both humans and agents can check without interpretation. Prose describes intent; a test encodes it in a form that either passes or fails. That property is what lets the human step back. Once the acceptance criteria are tests, "is this done?" stops being a review conversation and becomes a command you run.

The workflow that follows is direct. The tests define the target. The agent writes an implementation, runs the suite, reads the failures, and iterates until everything is green, closing the loop itself on each cycle rather than returning to a human between attempts. A passing suite is the definition of done. The agent is not guessing at what you wanted; it is optimizing against an objective you wrote down, which is a far more reliable thing to hand a machine than an English paragraph.

Two honest caveats keep this from becoming magical thinking. First, tests specify what they assert and nothing more. An agent will satisfy the letter of the suite, so gaps in coverage become gaps in behavior, and an underspecified test invites an implementation that is technically green and practically wrong. The suite is now the specification, which means its blind spots are the system's blind spots. Second, tests bound behavior; they do not prove correctness across an unbounded input space, a limit that matters most in exactly the high-stakes settings where correctness is the point.

Write the test you would refuse to fake. Because the agent optimizes against the suite, the suite carries the full weight of your intent. The useful discipline is adversarial: for each test, ask what wrong-but-passing implementation it would admit, then close that gap before you let the agent start. In spec-driven work, weak tests are not a testing problem, they are a specification defect.

The spec-driven workflow

Assembled, the practice is a loop with the human deliberately positioned at the top of it. You write the spec and its tests. The agent implements and runs the suite. If it fails, the agent iterates. If it passes but the output reveals something the spec did not anticipate, an edge case, a wrong assumption, a missing constraint, you do not patch the code. You fix the spec, and the corrected spec becomes the thing that regenerates the code. The gradient of your effort points at intent, not implementation.

     +------------------------------+
     |  Human: write spec + tests   |
     +--------------+---------------+
                    |
                    v
     +------------------------------+
     |  Agent: implement, run suite |
     +--------------+---------------+
                    |
              suite green?
               /          \
             no            yes
             /               \
            v                 v
   +---------------+   +------------------+
   | Agent iterates|   | Human inspects.  |
   | vs the tests  |   | Gap in intent?   |
   +------+--------+   +---+----------+---+
          |               |          |
          +--<------------+         no
          (loop)          |          |
                   refine spec       v
                  (not the code)   done
            
The spec-driven loop. Failures route back to the agent; discovered gaps route back to the spec, never to a manual code patch. The human operates at the spec level, and the code is regenerated from it.

The counterintuitive rule is the one at the bottom of the diagram: when the output is wrong, resist editing the code. A hand-edit to a regenerable artifact is a change that lives nowhere authoritative; the next regeneration erases it, and the spec still describes the wrong thing. Fixing the spec is slower in the moment and correct over the life of the system, because it keeps the source of truth and the running system in agreement. This is the same discipline that made teams stop editing generated clients or compiled output by hand.

The loop is not free. Standing up a good suite and a precise spec front-loads effort that the old workflow spread across the whole implementation. The trade pays off when the feature will be regenerated, extended, or maintained more than once, and it does not pay off for genuine throwaways. Judgment about which is which is part of the skill.

Where prompts and specs converge

There is a second place this pattern shows up, and noticing it clarifies both. When you build an AI feature, the agent's prompt is not decoration around the model; it is the program. The system prompt states the role and rules, the constraints bound the behavior, the examples pin down the edge cases. Read plainly, that is a specification. It states intent, defines interface, and sets acceptance conditions, in natural language aimed at a probabilistic interpreter rather than a deterministic one.

Once you see a prompt as a spec, the engineering discipline transfers directly. A prompt deserves version control, a changelog, and an owner. It deserves tests: an eval suite is to a prompt exactly what a unit-test suite is to a function, the executable acceptance criteria that define whether a change is an improvement or a regression. Editing a production prompt without running its evals is the same category of mistake as editing a spec without rerunning its tests, and it fails the same way, silently. The managed-asset treatment is worked through in Prompts as Managed Assets.

The convergence is not a metaphor; it is the same underlying shift. Whether the interpreter is a compiler, a coding agent, or the model itself at runtime, the durable artifact is the precise statement of intent and the tests that verify it, and the generated behavior is downstream. Prompt engineering done well and spec-driven development are two views of one practice: write the specification precisely, verify it executably, version it like source, and treat the output as regenerable.

Where it holds and where it breaks

Skeptical CTOs are right to distrust any practice pitched as universal, and this one is not. It holds where the problem can be pinned down before the code is written and breaks where pinning it down is the actual work. The honest boundary runs along how much of the difficulty lives in the specification versus the implementation.

Spec-driven works wellSpec-driven strains or fails
Well-bounded features with clear acceptance criteriaExploratory work where the goal is discovered by building
Contract-shaped work: APIs, data transforms, validators, integrationsNovel architecture where the hard question is the shape itself
Behavior that is cheap to express as a testQualities that resist testing: taste, feel, emergent UX
Reimplementation, refactors, and ports against a known targetResearch and prototypes meant to be thrown away

The pattern that runs through the right-hand column is that the spec is now the bottleneck. When you can state precisely what you want, an agent building it is close to a solved problem; when you cannot, no amount of generation speed helps, and a premature spec actively harms by locking in a guess. For genuinely novel architecture the specification is the design work, and it is discovered iteratively, often by writing throwaway code to find out what the real constraints are. Spec-driven development does not remove that work. It relocates the difficulty from typing the implementation to knowing precisely what the implementation should do.

That relocation is the point, and it is also the warning. The skill that used to be spread across writing and debugging code now concentrates in specification and verification. Teams that were mediocre at saying exactly what they wanted did not have that weakness exposed, because the act of coding forced a thousand small decisions. Hand those decisions to an agent against a vague spec and it will make them for you, quickly and plausibly, and you will not notice until the gap surfaces in production.

What it means for engineering orgs

For an engineering leader, the practical consequence is a shift in where value and risk sit, not a new tool to buy. The scarce skill moves from writing code to specifying and verifying it: decomposing a problem into precise contracts, writing acceptance criteria that admit no wrong-but-passing implementation, and reading generated output critically against intent. That is a genuinely different aptitude from fluent coding, and some strong coders are weaker at it than some product-minded engineers. Hire and promote accordingly.

Review follows the artifact. If the spec and its tests are the source of truth, then the spec and tests are what get reviewed with rigor, and generated code is reviewed for what specs cannot easily capture: security posture, resource use, and adherence to standards. This does not lighten governance. Everything the Atlas says about governing AI-generated code still applies to the output; a plausible implementation from a green suite can still carry an injection flaw or a licensing problem that no functional test was watching for.

For regulated environments. Where model risk management applies, the spec-and-eval framing is a strength, not a workaround. Bounding behavior with an executable suite and continuous checks is precisely the direction validation has been forced to take for non-deterministic systems, in the spirit of SR 11-7's pillars of inventory, independent validation, and ongoing monitoring. A versioned spec with a documented eval suite is a more defensible artifact for a validator than a wall of generated code.

The concrete step is unglamorous: treat specifications as first-class, version-controlled artifacts, kept next to the code, reviewed on change, and owned by name. Most organizations already have the tooling; what they lack is the decision that the spec is the thing worth maintaining and the code is the thing worth regenerating. The teams that internalize the inversion stop measuring output in lines written and start measuring it in intent captured precisely enough that a machine can build it, and a test can prove it. That is the same standard good engineering always aspired to. The difference is that it is now the fast path rather than the disciplined one.

← Coding Agents in the Enterprise: from Autocomplete to Delegation ALL OF AI ENGINEERING From Vibe Coding to Production →