Discoverydotrequirements

The Hard Part of Spec-Driven Development

Will Raymer,

Spec-driven development is having a moment. Get Shit Done  went viral as a spec-driven framework for Claude Code. Thoughtworks added spec-driven development to the Assess ring of the Technology Radar . Y Combinator put out a Request for Startups  calling for “Cursor for Product Managers.” Plan mode in agentic coding assistants increasingly looks like a built-in solution to the same problem. A year ago the default was “prompt and pray”; now there’s a growing ecosystem to help you define expected behavior before (or at least alongside) the implementation.

All of this is welcome. But the conversation so far has been almost entirely about the moment of creation. How do you produce a spec that helps an AI build the right thing right now? The problem that isn’t getting as much attention is what happens next.

The spec after the sprint

A completed feature doesn’t become “done” in the sense that you’ll never look at it again — rather, it becomes substrate. The next dozen times you build something in the same domain area, each change can invalidate, challenge, or extend the behaviour you’ve already defined. A checkout flow that worked fine before subscriptions gets revisited when you add subscriptions. An auth system that was straightforward before multi-tenancy gets revisited when you add multi-tenancy. The spec you wrote to help Claude build the feature in March is context you desperately need when Claude is modifying the feature in September — assuming it’s still around, and assuming it’s still true.

That’s two big assumptions. The first is about context: are your requirements somewhere the people and agents building the software will actually encounter them? A spec buried in a Notion page three clicks from where anyone works might as well not exist. A spec sitting in a Claude Code session that ended two weeks ago literally doesn’t exist anymore.

The second is about persistence. Requirements evolve as the product evolves. If nobody updates the spec when the feature changes, the spec becomes something worse than absent — it becomes a lie that a future reader (or a future AI assistant) will trust at face value.

Speci-fiction

Kamil Nicieja named this problem in Writing Great Specifications over a decade ago:

Documentation and specification artifacts grow obsolete easily. As your product evolves over time, requirements often evolve, flat-out change, or turn out to be poorly defined and have to be refined. Outdated and unwanted, they become speci-fiction. (Yes, I invented the word. No, I’m not a poet.)

Speci-fiction — A specification that poses as a single source of truth but that can’t be one because nobody cares to update it.

If you’ve been building software for a while, you’ve probably seen this dynamic. The Confluence page with a “Last updated: 2023” badge on a feature that’s been rewritten twice. The new developer piecing together what the software is supposed to do from acceptance criteria scattered across closed Linear issues, because that’s where the “what” lived during development and nobody moved it anywhere more durable. The fiction is the illusion of correctness: a reader believes the spec describes the system as it is, when the working system diverged months or years ago.

Speci-fiction used to be a year-three problem. You’d ship for a while, the team would grow, someone would notice the docs were stale, and eventually it would get bad enough to address. AI-assisted development compresses that whole arc. When a tiny team can produce code at the rate of a much larger one, the what-vs-how drift that used to take years to accumulate can happen in weeks.

The solution that didn’t work (and the diagnosis that did)

The BDD community tried to solve this problem fifteen years ago. They nailed the diagnosis: there has to be a description of the software’s behaviour, it has to be versioned with the code, and it has to be mutually accountable with the code somehow. The solution — Cucumber, Gherkin, .feature files — didn’t work for a lot of teams. The automation layer was too heavy, the syntax too ceremonial, the maintenance burden too high.

Teams that bounced off BDD generally landed in one of two places. Some gave up on having a business-facing description of expected behavior altogether — they start from some sort of PRD, but the tests become the ongoing source of truth, and the original requirements quietly become speci-fiction as the implementation evolves. Others moved traceability into mostly-manual processes and tools and pay for it in maintenance overhead. Neither camp is in great shape for the AI era: sending an AI assistant to an external traceability matrix isn’t ideal, but asking it to infer what the software is supposed to do from hundreds of thousands of lines of test code isn’t great either.

It’s worth noting that Thoughtworks, in their Technology Radar assessment of spec-driven development, flagged a separate concern: there’s a risk of “reverting to traditional software-engineering antipatterns — most notably, a bias toward heavy up-front specification and big-bang releases.” In other words, the answer to “we need specs” isn’t “let’s go back to Big Up-Front Design.” The diagnosis that specifications need to be living, versioned, and validated is exactly right. The challenge is getting there without falling into one of the familiar traps: no spec at all, a 200-page requirements document before anyone writes a line of code, or requirements that appear lean but hide a bunch of heavy process in the traceability layer.

What the tool actually needs to do

This is the problem we built dot•requirements  to solve. We were building a travel app with AI, hit the speci-fiction wall, and couldn’t find a tool that addressed it. So we thought about what the tool actually needs to do — and, just as importantly, what it needs to not do.

It needs to let you express intent in a durable way. Write down what the software is supposed to do, in language that’s useful to humans and AI alike. Markdown files in .requirements/ in the repo, versioned in Git alongside the implementation. When you delete a feature branch, the associated requirements go with it. When you merge, the spec and the code arrive together. There’s no separate system to keep in sync, which means there’s no opportunity for silent drift.

It needs to let you connect intent to validation. Unlike BDD, which replaced your test framework with a spec-driven automation layer, dotrequirements lets your existing tests reference a requirement. requirement() is just a function that returns a description string: test(requirement('LOGIN-1'), () => { ... }). Your tests are still Vitest or pytest or JUnit tests. They run the same way they always did. But now there’s a traceable link between a test and the behavior it’s supposed to validate, and when the test breaks, the requirement is immediately implicated. Speci-fiction can’t accumulate silently because the test suite won’t let it.

And it needs to be legible to AI. Requirements that AI assistants can read via MCP become context that helps them understand intent, not just implementation. An AI that knows what the checkout flow is supposed to do — not just what the code currently does — makes better decisions about how to change it, and is less likely to silently invalidate the spec in the process.

The ceremony is minimal, because the problem was never a lack of process — it’s that the spec needs to stay close to the code, stay true to the code, and stay visible to whoever’s changing the code next.


If you’ve opened a spec and wondered whether it describes the system you’re actually working on — that’s what we’re building for. More at dotrequirements.io .

© 2026 Popover AI Ltd.RSS