Why You Should Not Commit Your Specs
Disclaimer
When I say “specs” in this article I mean specs as understood in AI assisted Spec Driven Development: markdown files that describe a change before an LLM implements it.
I am NOT talking about OpenAPI, AsyncAPI or similar formats, and I am not talking about README-style documentation that describes what a system does today.
Context
Software development today is in constant change. It feels like every month there is a “new” development method or idea.
Some of these ideas are gone within a month or two, others stick around for longer.
Spec Driven Development (SDD) is one of the ideas that has gotten some traction and is making its way into the mainstream. The idea is not new, but it has been redefined, and when I talk about SDD I only mean its current incarnation:
Before writing any code, write a specification. Then use the spec as an input for an LLM and let it produce the code.
The spec is usually one or more markdown files with a detailed description of what should be done, created by the developer together with an LLM.
In this post I will look at how popular SDD frameworks implement this idea, with a focus on one thing: what happens to the spec files after the code is written.
The Afterlife of a Spec
Before SDD had a name, we called this a “plan”: write the change down, refine it with the LLM until you both agree, let it implement, review the result.
Every SDD framework I have tried follows that same pattern. Where they differ is one question:
What happens to the spec once the code is written?
If we focus just on the lifecycle of the spec file itself, we can group them into three different groups, with different approaches:
Deleted — not committed, or removed after implementation.
Kept and stale — committed, but frozen in time. It describes what was true on the day it was written. Moving it into an
archive/folder is a slightly cleaner version of this, but it is the same category.Kept and updated — committed and kept in sync with the code. The specs always describe the system as it is today.
Some frameworks also use a hybrid approach where some high level specs are always updated and some — usually the ‘feature branch’ specs — are discarded or archived.
All of this is nuance about which specs to keep. It assumes we have already agreed that some specs should be kept at all.
To me this feels like we jumped two steps ahead, instead of answering a simple question first:
Should we commit these specs? Or should we throw them away once the code is implemented?
If you have read the title of this article then you probably already guessed my take on this.
Why you should not commit your specs
Ambiguity
English, like every natural language, is ambiguous by nature.
For example, what does “bi-weekly” mean? Does it mean twice a week? Or every two weeks?
The answer is: yes.
Before the code exists, that ambiguity is unavoidable. But once the code is written, we have an unambiguous description of the feature: the code.
Programming languages can be read by humans and machines alike, and they are by nature much more precise than English, since they have to follow a strict syntax to be valid.
Committing the spec next to the code means keeping an ambiguous description of what something does, next to a precise one.
Intent
People will say that specs capture the intent behind a change better than the code does, and I agree. Sometimes it is hard to tell from the code alone why it exists.
But that is not a reason to commit the spec. We already have plenty of places for intent that live close to the code:
- Commit messages and pull request descriptions
- Comments that explain non-obvious code or other gotchas, with links to JIRA tickets or GitHub issues
- Unit tests, integration tests, E2E tests
- Architecture Decision Records for decisions that should not be casually reversed
README.mdand other markdown files that give humans and LLMs the required context
Duplication
Once the spec is implemented, most of it repeats what is already obvious from the code.
Why maintain something that becomes a burden the moment it is implemented? Why keep the same information twice inside the codebase?
Duplication also means competing sources of truth. If the code says one thing and the spec says another, who decides what is correct?
Information overload
I recently tried out 3 popular SDD frameworks (
Here are the lines of markdown each one created for that single feature, not counting the one-time project setup files:
| Framework | Lines of markdown |
|---|---|
| Spec Kit | 841 |
| OpenSpec | 540 |
| BMad Method | 1,773 |
Are we still pretending to read all these files?
To me a spec has one purpose: to make sure the LLM and the developer share an understanding of what needs to be built.
Once the LLM has ’translated’ this shared understanding into code, and the developer has verified its output, the spec loses its value.
Committing the spec also means committing it to the pull request. 1,773 lines of markdown on top of the actual change leaves the reviewer with two options: skip it, or invest their time actually reading it.
Rot
If every feature that gets implemented leaves behind some type of artifact, these artifacts will start to be outdated quickly.
This will also lead to problems with LLMs: they will inevitably grep one of these files and then get confused as to why the spec is different from the code.
Most models are trained to be careful, so they will burn tokens trying to figure out whether the spec is stale or the code is wrong.
To prevent this from happening some SDD frameworks keep a high level ’living spec’ besides these outdated ‘frozen in time’ specs. The user is then
But keeping the living spec in sync requires its own set of tools and effort (aka tokens).
Regeneration Fantasy
There is also an underlying notion that suggests that the spec is the source of truth and that the code is just the disposable output.
The specification becomes the primary artifact engineers maintain, and code becomes a derived, regenerable output that AI agents produce from that spec on demand.
—
Augment Code, “The Spec as Source of Truth”
The idea is that if you were to delete the whole code of your software system, you could simply regenerate it from your specs.
That notion led Elon Musk to the stupidest take of the year:
Things will move, maybe even by the end of this year, to where you don’t even bother doing coding. The AI just creates the binary directly. And the AI can create a much more efficient binary than can be done by any compiler.
— Elon Musk, xAI all-hands, February 10, 2026 (
video at 11:30 ,original post by xAI )
Great idea. Why generate something both machines and humans understand, when you could generate something only machines understand?
Back to regenerating source code from specs. My main question is simply: Why?
Why would anyone want to regenerate their entire codebase from specs? To switch stacks or languages? Why not use the code and tests you already have? That is exactly
I truly don’t get it, but maybe I am missing the point.
Summary
I am NOT a fan of committing specs (as SDD understands them) into the codebase.
I am fine with committing the spec while working on the feature, as long as it is deleted before the PR is created. That way it stays in the git history without ending up in the codebase.
Instead of committing your specs, here is what I would do:
Throw the spec away once the code is merged, or keep it in git history only.
Make the intent obvious from the code. If that is not possible, add documentation via concise, information-dense markdown files that explain why, not what.
Make sure your repositories need no external context. A new dev should be able to start working on your project without the help of another dev.
Don’t cram everything into a central
README.md. For example, have a separate markdown file for testing or deployment. High-level markdown files that describe non-obvious features are fine too.