Agents write most of the code at GrowthX. That moved the expensive review question upstream.
Reviewing a code diff answers "is this correct." Reviewing a spec answers "is this the right change." The second question is where our judgment goes now.
So we do the first half of spec-driven development: a markdown spec that looks a lot like a PRD, argued over and adversarially reviewed before any executable code exists. We reject the second half, where the spec outlives the code as a permanent source of truth. At merge, we throw ours away, sort of.
What spec-driven development is
Spec-driven development means writing the specification before an agent writes code, and treating that recorded intent as the durable artifact rather than the prompt or the output.
Tessl's definition is the cleanest I have found: "the structured counterpart to vibe coding: before the agent writes code, you produce a specification, requirements, design, and a task breakdown, as an editable, human-readable artifact, and the agent builds against it." That separates it from better prompts, which are disposable, and from vibe coding, which keeps no record of intent at all.
The tools often split by role. GitHub Spec Kit defines the canonical four-phase workflow: Specify, Plan, Tasks, Implement, each producing its own markdown file. AWS Kiro builds that workflow into an IDE. Tessl makes the strongest version of the claim, marking generated code do-not-edit. Claude Code and GitHub Copilot sit on the consumption side, reading whatever conventions file you hand them.
There are three levels.
Spec-first means you write a spec and use it for the task in front of you.
Spec-anchored means you keep it for maintenance.
In spec-as-source, humans edit only the spec and never the code.
Birgitta Böckeler, who wrote that taxonomy after running all three tools herself, is not sold on any of them. Her objection is the one a skeptical reader arrives with: "I'd rather review code than all these markdown files." She ran Spec Kit and got back a pile of repetitive, verbose documents, and asks whether the whole thing is a Verschlimmbesserung, the German word for making something worse while trying to make it better.
She is right about what she reviewed. Our answer is that not all of the markdown is written for a person. The pitch a colleague reads is 62 lines. The implementation file an agent reads is 978.
Why prompt-first workflows break down
Why not just prompt? This exists because prompting alone stopped scaling. A prompt-first session builds a shared understanding that erodes as the session runs and vanishes when it ends. Nothing carries to the next one.
There's some data on the impact of AI that seems pretty accurate according to my own experience. Copy-pasted code rises from 8.3% to 12.3% while refactoring fell from 25% to under 10% across 2021 to 2024, in an analysis of 211 million changed lines.
That debt compounds differently now, because agents read the repo to decide what to write next. A mediocre pattern merged today is the house style tomorrow.
Scaffold-driven development: our own version of SDD approach
The big idea in spec-driven development is that the spec outlives the code, and now you code in spec. You round-trip through it, and when requirements change you edit the spec rather than the implementation. Generated code do-not-edit for exactly that reason, with requirements becoming the long-lived thing at the centre.
Not every tool goes that far. Kiro deletes the spec once the feature is built. That one is closer to us, and it is also the version I like least: it solves the maintenance bill by throwing away the reasoning.
What worked out the best for us at GrowthX was the opposite. Write the spec with that much rigor and then trash it (sort of).
At merge it stops being authoritative. The tests carry the contract. Whoever finished the work moves the folder into docs/plans/executed/, and nothing in there governs anything again. That directory in GrowthOS, our core product, currently holds 42 plans and 645 markdown files, about 1.46 million words. Another 48 plans are live.
The word for that is scaffolding. Engineered, load-bearing, safety-critical, and designed from day one to be "taken down" when the construction is finished.
Both halves matter.
A spec you do not take seriously is not scaffolding, it is a sketch.
A scaffold that never comes down is a second copy of the truth, with a maintenance bill and no test protecting it.
It loses its authority and keeps its information. That distinction is what stops this being waste, and I come back to it below.
We are spec-first, deliberately, and we reject the spec-as-source part.
Why we review the spec, not the code diff
We are about 20 engineers and just in our core platform we are merging some 397 pull requests a month. 86% of them carry almost no human review comments (we do have a ridiculous amount of agent reviews, though).
That number looks like a rubber stamp, and it would be one if the diff were where our judgment lived. A study of 400 repeat reviewers found that approval rates rise and inline comments fall 22% as agent PRs pile up. Latency more than triples.
So we moved the examination upstream. The spec defines scope and breakage risk before a line exists. Tests and CI still check behavior. What the spec review replaces is the fiction that a human skimming a diff was doing design review.
Example of what our specs contain
Three files, and their proportions
The "Find Opportunities, from anywhere" plan shipped as two PRs #2766 and #2872. Three files.
pitch.md, 62 lines. The problem and the idea, followed by a Non-goals section. Its main move is collapsing four fuzzy agent verbs (Develop, Refresh demand, Find new ideas, Research opportunities) into two clear stages. Non-goals is where the tradeoffs get made. Deciding what you will not build is the cheapest scope cut available.
ux-ui.md, 406 lines. ASCII wireframes for seven surfaces, each drawn today then after. A naming map of every string that changes. Empty and edge states. Copy drafted in the spec instead of improvised during implementation.
implementation.md, 978 lines. Three slices. We labeled slice two the risky one and isolated it on purpose. Real file paths and migrations. Acceptance criteria and architectural constraints. The reasoning sits between the code rather than after it. Sometimes the implementation is a folder with multiple slices.
Markdown in the repo, not a doc tool
The spec lives in docs/plans/, next to the code it describes. The agent reads it directly. It versions with the code. It diffs in review like anything else. While the work is live, one file is the source of truth for humans and agents both.
Not every change earns a spec
Quick changes stay in the conversation and never become a file. Standard work gets one file. High-impact work gets a directory with an index and numbered phases. A depth flag moves the same spec between architectural detail and implementation or handoff detail, depending on who reads it next.
These tiers exist because over-specifying costs real time. Most changes do not earn a file.
We tend to integrate our phases, and anything that gets merged under a feature flag, as one slice, which is the approach Basecamp describes in Shape Up.
How a coding agent consumes a spec
A structured spec beats raw prompting for a mechanical reason. It front-loads decisions into the context window instead of hoping the model recalls them mid-session. Token limits then shape how you modularize: we sliced that 978-line document into three so a working session carries one slice, not the whole plan.
The part worth copying is the grounding facts section our implementation docs open with. Before planning starts, every claim gets verified against real code and cited to file and line, with a date on it. The agent builds on checked assumptions rather than recalled ones.
It also draws a boundary. The agent records what it confirmed statically and names what a human has to verify against a running system. An agent that says "I confirmed the webhook config in code" is useful. An agent that says "I could not confirm the retry behavior without a live run" is more useful, because it tells you exactly where to spend your attention.
What a human review on a spec looks like
During the creation of the spec, we run extensive rounds of Codex adversarial reviews to catch things Claude does not catch.
In this example, before any code existed, Codex ran three review passes against the spec.
Pass two ran after the spec had changed and found ten more. The spec treated a status field as a free string. The system validates it as an enum. Pass three verified the fixes and caught the bugs the fixes themselves had introduced.
Twenty findings later, and still zero lines of code, every fix is cited inline in the spec, next to the paragraph it changed, so the document carries its own review history.
The third pass to catch the last defects introduced by the fixes.
What a retired spec is still good for
Losing authority, keeping information
An executed spec keeps its information. It no longer says what the code should do. It says why: what we considered, what we rejected, and what it cost to find out.
This is the part Kiro throws away and Tessl pays forever to keep. Dropping the authority and keeping the reasoning was the whole trick for us.
We often keep a decision record in our repo with a section titled "Rejected, and why (the part that stops the argument recurring)." Every rejection in it names the prototype that killed it. This is basically an ADR (architecture decision record).
Design docs were a graveyard when only humans read them.
People do not reopen old documents. Agents do.
Retrieval is cheap for them, and they have no ego about reading history before proposing something we already rejected twice.
That is what makes writing specs this carefully worth paying for now, and it has nothing to do with code generation or re-generation after execution, as level three of "spec dev" suggests.
Drift, and why it is a smaller problem for us
Two things catch drift while a plan is live. We re-run the adversarial review against the real PR with the final code diff, slice by slice. And there is a hands-on QA pass before a plan retires.
After merge our spec has retired, so there is no round-tripping obligation and no living document to re-sync. Test failures catch drift in covered behavior. Uncovered behavior can still drift quietly, and does.
When requirements change, we open new work with fresh grounding facts rather than editing an authoritative document.
Spec-driven development next to TDD and BDD
TDD and BDD constrain behavior at the test layer and stay live for the life of the code. Dan North framed BDD as "outside-in", starting from business outcomes and drilling into features. A spec constrains intent before the work exists at all, and in our model it retires at merge.
They constrain different layers. The clearest framing I have read is that SDD anchors the work in a specification, BDD protects the macro behavior, and TDD improves the micro design. In our version that is literal: at merge, the behavioral contract moves into tests and the spec goes to executed/.
We also have our own way to write QA tests with Chrome MCP, inspired by Gherkin, the language behind BDD's famous Cucumber framework. Something I might cover another day.
If you run a different arrangement, especially spec-anchored at volume, I'd love to know your experience in practice.
How is spec-driven development different from writing better prompts?
A prompt is disposable and lives in one session. A spec is a versioned artifact in the repo that people and agents build against across many sessions. The prompt-first failure is that the shared understanding vanishes when the session ends.
What goes inside a spec?
At minimum: the problem, explicit non-goals, acceptance criteria and architectural constraints. Ours add UX wireframes with drafted copy and a naming map, sliced implementation steps with real file paths and migrations, and a dated grounding-facts section citing code to file and line.
What are the three maturity levels, and where should a team start?
Spec-first means write it and use it for the task. Spec-anchored means keep it for maintenance. In spec-as-source, humans edit only the spec. Start at spec-first. It captures most of the review-quality benefit with none of the round-tripping obligation. We stayed there on purpose.
How do you detect and recover when generated code drifts from the spec?
While the plan is live: re-run adversarial review against the real diff per slice and before merge, plus a hands-on QA pass against a real workspace. After merge our spec has retired, so the test suite catches drift in the behavior it covers.
How does code review change when an agent writes most of the code?
Design judgment moves to the spec, before code exists. Diff review narrows to checking that the implementation matches an already-argued plan. Most of our merged PRs carry almost no comments because the findings that mattered landed on a markdown file weeks earlier.
Notes
In GitHub Spec Kit: Specify writes
spec.md, Plan writesplan.mdplus supporting research and data-model files, Tasks writestasks.md, and Implement executes those tasks in dependency order. Spec Kit was announced on 2 September 2025, based on John Lam's research. AWS Kiro's equivalents arerequirements.mdin EARS notation,design.md, andtasks.md; it reached general availability in November 2025. Claude Code readsCLAUDE.mdand can importAGENTS.md; GitHub Copilot reads.github/copilot-instructions.mdand supportsAGENTS.mddirectly.GitClear's analysis of 211 million changed lines. Two adjacent findings point the same way: METR's randomized trial found experienced developers took 19% longer with AI while believing they were faster, and a 2026 code-ownership study found AI-assisted participants answered questions about their own code correctly 87.5% of the time, against 100% without.
Lethbridge, Singer and Forward, where 44% somewhat agreed and 24% strongly agreed that documentation is always outdated relative to the system.







