← Blog

Your spec is an output, not an input

Level 4 tells you to write the specification first. Every specification worth having was extracted from a working implementation, and the tools all point the arrow the wrong way.

Machine-readable Download Markdown

Last month I wrote that in a dark factory the bottleneck moves from coding to specification, and that the most valuable skill is writing specs precise enough for a machine to execute against. I still believe the first half. I have spent the weeks since trying to actually do the second half, and I think the way it is usually described is backwards.

The Level 4 pitch is clean: you write a detailed specification, you hand it to agents, you check the result against your acceptance criteria. One step short of the Level 5 promise, specification in, software out. Every spec-driven tool I have looked at assumes this order. Write the document, then generate from it.

The problem is that writing a good specification requires knowing things you only learn by building. Not by thinking harder. By building.

The blank page assumes you already have the answer

Try it on something real. Not a CRUD endpoint, where the spec is obvious because the pattern is already in your head from a hundred previous implementations. Try it on something where you do not yet know the shape of the answer.

You will write a page or two of confident prose, and every hard question will be phrased as an assumption. What happens when two of these arrive at once. What the identity of this thing is when it has been partially updated. Whether this operation can be safely retried. Those are the questions that determine whether the software works, and at the blank-page stage you do not have answers to them. You have guesses, written in the declarative voice, which is worse than having nothing, because the agent will implement your guesses faithfully.

This is the failure mode I flagged last month as specification debt: if your specs are wrong, the factory produces the wrong thing faster and more confidently than a human team would. What I did not say is where the wrongness comes from. It is not carelessness. It is that the spec was written at the moment of minimum knowledge about the problem.

The specifications you admire were excavated

SQLite has one of the most thorough specification and documentation sets in software. It describes file formats, transaction semantics, and behavior under partial failure with a precision most projects never approach.

It was not written first. It was extracted from a working implementation, over years, by people who had already hit the edge cases and needed somewhere to record what they had learned. The document is a fossil record of the build.

This is the normal case, not the exception. Read any specification you actually trust and ask when it was written relative to the code. HTTP was documented after servers existed. POSIX described what implementations already did. The specification is the crystallized residue of implementation experience. We then hand new people the crystal and tell them that is how the thing gets made.

For twenty years that was a harmless simplification, because a human reading a spec brings judgment to it, and fills the gaps from experience. An agent brings no judgment. It fills the gaps with the most plausible completion. Every unstated assumption in your spec becomes a decision that gets made without you.

Burn the prototype, keep the constraints

What has worked for me is inverting the order and treating the first implementation as research rather than as product.

The loop, roughly:

  1. Give an agent a thin, honest brief. Not a specification, a direction. Two paragraphs, and an explicit statement that this build is disposable.
  2. Let it build the whole thing badly and fast. Do not review the code. Reviewing disposable code is the most expensive mistake available here.
  3. Run it. Break it. Find the places where it made a decision you did not authorize.
  4. Write down only the constraints. Not the design. Every place the implementation surprised you becomes one line in a constraints document.
  5. Throw the implementation away. All of it.
  6. Repeat until the constraints document stops growing.

The output is not code. The output is a document that could only have been written by someone who had already built the thing once. That document is your specification, and it is worth an order of magnitude more than the one you would have written on day one, because every line in it was purchased with a surprise.

The cost of this changed recently in a way that matters. Throwing away an implementation used to mean throwing away weeks of a person's life, which is why nobody did it, which is why we all pretended the first design was the real one and patched it forever. When a disposable build costs an afternoon of agent time, discarding it is no longer an act of institutional courage. It is just a step.

Knowing when you are done

The loop needs a termination condition or it runs forever, and the one I use is specific: hand the constraints document to a fresh agent with no memory of any previous attempt and no access to the discarded implementations. If it produces something that satisfies the constraints without asking clarifying questions, the document is complete. If it asks a question, the answer to that question was knowledge you were carrying in your head rather than in the document, and it goes in the document.

This is a better test than reading the spec yourself and judging whether it seems thorough. You cannot evaluate your own spec for completeness, because the gaps are exactly the things you know so well you forgot to write down. A contextless agent is a reliable detector for that particular blind spot. It is the only reader that shares none of your assumptions.

Where this argument is weak

It is more expensive in tokens, and I cannot yet tell you by how much. You are paying to build things you intend to destroy. My instinct is that it is cheaper than shipping the wrong architecture and living with it, but that is an instinct, not a measurement, and I am wary of anyone who claims precision here.

It also does not apply uniformly. For well-understood work, authentication flows, standard CRUD, a payment integration you have done before, the pattern is already excavated. It lives in your head or in a previous project. Writing the spec first is correct there, and the loop I described would be an expensive way to rediscover something you already know.

There is a stronger objection, which is that this looks like a rebranding of prototyping, and prototyping is not new. That is fair. What I think is new is the discard step being cheap enough to do honestly. Traditional prototypes almost never got thrown away; they got promoted to production with an apology. The economics have changed enough that the discard is now realistic, and the discipline only works if the discard is real.

I also cannot rule out that better models close this gap. If a model can reason its way to the edge cases without building, the excavation becomes unnecessary. I do not see that yet, and the failures I see are consistently failures of unstated assumption rather than failures of reasoning, but I would not bet heavily against it.

What this changes in my factory

I no longer write a specification as the first artifact for anything unfamiliar. The first artifact is a brief and a disposable build.

I keep a constraints document per subsystem, and it is append-only. When production surprises me, the surprise goes in the document rather than into a code comment, because the code will be regenerated and the comment will not survive.

I stopped reviewing throwaway implementations. This was harder to give up than it sounds. Twenty years of habit says that you read the code your system produces. When the code is scheduled for deletion, reading it is a way of feeling responsible without being responsible.

The acceptance criteria come out of the excavation, not out of the brief. Criteria written before the build test what I hoped would be true. Criteria written after test what actually breaks.

What to ask before you write another spec

  • Have I built anything resembling this before, or am I about to write confident prose about a problem I have not touched?
  • Which lines in this document are constraints I learned, and which are guesses in the declarative voice? Can I mark them differently?
  • If a fresh agent with no context implemented strictly from this document, which decision would it get wrong first?
  • Am I reviewing this generated code because it is going to production, or because reviewing code is what I know how to do?
  • When the implementation surprises me, where does that surprise get recorded so it survives the next regeneration?

The February piece said the constraint is clarity of thought. That holds. I would add that clarity of thought about an unfamiliar system is not available at the start. It is the thing you have at the end, and the specification is where you put it so it does not have to be bought twice.