Next-Gen App & Browser Testing Cloud
Trusted by 2 Mn+ QAs & Devs to accelerate their release cycles

Spec-driven development puts the specification, not the code, at the centre. Here is what makes a spec an agent can actually build from, how the Spec Kit workflow runs, and the verification half that decides whether any of it worked.

Anubhav Singhmaar
Author

Saksham Arora
Reviewer
Last Updated on: August 25, 2026
An agent can now produce a thousand lines of working code from a paragraph of description. The bottleneck moved: the hard part is no longer writing the code, it is stating precisely enough what the code was supposed to do, and then proving that what came back matches.
Spec-driven development is the practice built around that shift. This guide covers what it actually requires, how the tooling workflow runs, what separates a spec an agent can build from off a wishlist, and the verification half that most teams adopt second or not at all.
TL;DR
Writing the spec first is not a new idea, and its previous incarnations mostly failed. Model-driven engineering and behavior-driven development both asked a team to maintain a formal description of behavior alongside the implementation. The description drifted, nobody trusted it, and it became documentation.
What changed is who reads the artifact. When an agent generates the implementation from the spec, the spec stops being a parallel document that must be kept in sync and becomes an input the build consumes. The synchronization cost that killed the earlier approaches largely disappears, because there is no second thing to synchronize.
The scale of the shift is visible in the tooling. GitHub's Spec Kit repository describes itself as "an open source toolkit for building high-quality software with any AI coding agent" offering "a ready-to-use spec-driven process", and it carries over 131,000 stars.
The definition is a claim about where intent lives. In conventional development, the code is the source of truth and the spec, if one exists, describes it after the fact. In spec-driven development that inverts: the specification is the artifact, and the code is its output.
The Spec Kit repository puts the consequence plainly, saying specifications "become executable, directly generating working implementations rather than just guiding them." That word, executable, is what separates this from a requirements document.
| Question | Code-first | Spec-driven |
|---|---|---|
| Where does intent live? | In the implementation, and in the heads of whoever wrote it | In the spec, which the implementation is derived from |
| What does a change start with? | Editing the code | Editing the spec, then regenerating |
| What is reviewed? | A diff of the implementation | A diff of intended behavior, which more people can read |
| What proves it works? | Tests written against the code | Tests traced back to specific criteria in the spec |
The last row is the one teams underinvest in, and the rest of this article is largely about it.
Spec Kit is useful to study even if you never adopt it, because its command sequence is an opinionated answer to what the practice requires. It states support for 30+ AI coding agents across CLI tools and IDE assistants, so the process is deliberately not tied to one model.
| Command | What it produces | Why the step exists |
|---|---|---|
| constitution | Governing principles and development guidelines | Standing constraints the agent should respect on every feature, not just this one. |
| specify | Requirements and user stories: the what and the why | Deliberately excludes the how, so implementation choices do not leak into intent. |
| plan | A technical implementation plan with the chosen stack | Where the how goes, kept separate so the spec survives a change of stack. |
| tasks | An actionable task list derived from the plan | Breaks the work into units small enough to review individually. |
| implement | The executed tasks, as working code | The generation step, which is the part everyone already knows about. |
| converge | An assessment of the codebase against spec, plan, and tasks | Names the remaining gap, which is an admission that one pass rarely lands it. |
Note what the sequence separates. Specify holds the what, plan holds the how, and keeping them apart is why the spec stays valid when the stack changes. Optional clarify, analyze, and checklist commands sit around this core for sharpening an underspecified spec.
Most specs that fail do so for the same reason: they describe a feeling rather than a behavior. An agent given "the orders page should be fast and intuitive" will produce something plausible, and nothing about it can be checked.
The fix is criteria that are individually testable and individually identified:
## Orders page
### Non-goals
- Pagination. The list is capped at 50 orders for this release.
- Search. Filtering ships separately.
### Constraints
- Must not call the billing service more than once per page load.
### Acceptance Criteria
- AC-1: A logged-out user visiting /orders is redirected to /login.
- AC-2: A logged-in user sees only their own orders.
- AC-3: An expired session returns 401 and clears the session cookie.
- AC-4: Orders are sorted newest first.Four properties make that usable:
Writing criteria this way is the same discipline as writing a capability spec before testing an autonomous system, which we work through in agent functional testing.
Here is the part that gets adopted late. Generating code from a spec is one problem; establishing that the generated code satisfies the spec is a different one, and finishing the first does not make progress on the second.
That second problem has its own name and its own literature. Our guide to verification-driven development covers the three competing definitions of the term, the loop that produces proof alongside each change, and what separates a check that proves something from one that only appears to.
It matters more with generated code than with hand-written code, because the failure mode is different. A human who misunderstands a requirement usually writes code that looks confused. An agent that misunderstands a requirement writes clean, idiomatic, well-named code that does the wrong thing, and code review is much weaker against that.
The cheapest useful check is mechanical: does every acceptance criterion have a test pointing at it? Give each test an annotation naming the criterion it covers, then fail the build when one is missing.
export function criteriaFrom(spec) {
return [...spec.matchAll(/^-\s*(AC-\d+):\s*(.+)$/gm)]
.map(([, id, text]) => ({ id, text: text.trim() }));
}
export function coveredIds(tests) {
return new Set([...tests.matchAll(/@covers\s+(AC-\d+)/g)].map(([, id]) => id));
}
export function coverageReport(spec, tests) {
const criteria = criteriaFrom(spec);
const covered = coveredIds(tests);
const uncovered = criteria.filter((c) => !covered.has(c.id));
// A test covering a criterion the spec no longer has is the reverse failure.
const orphanTests = [...covered].filter((id) => !criteria.some((c) => c.id === id));
return { total: criteria.length, covered: criteria.length - uncovered.length, uncovered, orphanTests };
}
test('reports the criterion nobody wrote a test for', () => {
const r = coverageReport(SPEC, TESTS);
assert.equal(r.total, 4);
assert.equal(r.covered, 3);
assert.deepEqual(r.uncovered.map((c) => c.id), ['AC-3']);
});Running the full file against the spec above, where the tests deliberately skip AC-3, gives this actual output:
$ node --test spec-coverage.test.mjs
ok 1 - every acceptance criterion is parsed out of the spec
ok 2 - reports the criterion nobody wrote a test for
ok 3 - flags a test that covers a criterion the spec no longer has
ok 4 - the gate fails the build when coverage is incomplete
# tests 4
# pass 4
# fail 0
# duration_ms 165.7577Four checks in 166 milliseconds, no framework and no model call. It is not proof the implementation is correct, and it is not meant to be. It is proof that nobody shipped a criterion nobody tested, which is a claim most teams practising spec-driven development currently cannot make.
The orphan check earns its place separately. When a criterion is deleted from the spec, its test usually survives, and the suite quietly keeps guarding behavior the product no longer wants.
A regex gate works for one repository. Across several teams shipping against many specs, the question becomes which requirements have coverage, which of those tests actually ran this release, and which failures map back to which criterion.
That is the job TestMu AI's Test Management exists to do. It generates structured test cases from a description, user story, or requirement document, with steps, expected results, preconditions, and priority, which is the same transformation spec-driven development performs on the implementation side. It then maintains a traceability matrix connecting requirements to test cases to execution history to defects, and pulls manual and automated results into one pass or fail view so coverage gaps show up before a release rather than after.
The generation direction is worth noting for spec-driven teams: if a spec is precise enough for an agent to build from, it is precise enough for test cases to be generated from too. The AI test case documentation covers that workflow, and KaneAI takes the same natural-language input down to executable tests.
Note: A spec an agent can build from is a spec you can generate test cases from. TestMu AI turns requirements into structured cases and traces every one to its runs and defects. Try TestMu AI free!
It is not a universal method, and the honest failure cases are worth naming before you commit a team to it.
The broader trade-offs of building this way are covered in our guide to AI-driven development.
Take the next feature you were going to describe in a ticket and write its acceptance criteria as numbered, individually testable lines with an explicit non-goals section. That single change is most of the value, and it works whether or not you adopt any spec-driven tooling around it.
Then add the coverage gate before you add anything else, because a spec-driven pipeline without it automates writing the code and leaves proving it to chance. Once more than one team is working this way, move the matrix somewhere it can be queried across releases rather than living in a regex. If your specs also describe declarative config rather than behavior, YAML based testing covers the parsing traps that silently change what such a file means.
Author
Anubhav Singhmaar is an AI Product Manager at TestMu AI driving Kane CLI, the command-line tool that brings browser automation to the terminal, turning natural-language flows into runs in a real Chrome browser that return pass or fail with shareable proof. He owns the roadmap and prioritization and works with engineering to ship developer-facing features. Before TestMu AI, he spent over four years at Sprinklr owning enterprise voice AI across APAC and EMEA. A mechanical engineer turned product manager, he grounds guidance in real QA workflows.
Reviewer
Saksham Arora is an Associate Product Manager at TestMu AI (formerly LambdaTest), working on product-led growth across the agentic AI quality engineering platform. He pairs a software-engineering background with product ownership, connecting how teams adopt and use the platform with what gets built, and previously worked as an Associate Software Engineer at MAQ Software. Saksham holds a B.Tech in Computer Science Engineering from Thapar Institute of Engineering and Technology.
Did you find this page helpful?
More Related Blogs
TestMu AI forEnterprise
Get access to solutions built on Enterprise
grade security, privacy, & compliance