How to write a design doc an agent can implement from

We have watched two engineers review the same design doc and reach different conclusions about what it asked for, then resolve the difference in four minutes over Slack. Neither of them thought the doc was unclear. It was unclear in one specific spot, they both noticed, and a question closed the gap before anyone wrote a line of code. That protection does not exist when the reader is an agent. The agent does not ask. It picks the most plausible reading and starts building on top of it, and by the time anyone notices, the gap has become behavior in released software.
That is the whole problem with using an old design doc format for AI-driven work. The format assumes a reader who can ask. Once the reader cannot, every place the doc was silent turns into a decision made by someone who was never part of the discussion about the trade-off.
Here is what has to change: three places a human-oriented doc stays vague on purpose, and what to write there instead.
Interfaces: state the exact format
A doc written for a colleague often says something like "the endpoint returns the user's order history." A person reads that, has a rough idea what an order history looks like, and if their guess is wrong, they ask before writing code.
An agent reads the same sentence and has to decide: which fields, in what order, paginated or not, what happens with zero orders, what status code, what happens on a malformed request. None of those questions are unreasonable. The doc just never answered them, so the agent answers them itself, consistently and confidently, and the answer it picks is whichever one is statistically the most common pattern in code it has seen before, not necessarily the one your system needs.
The fix is to write the interface as a precise set of rules instead of a description:
- The exact request format, including which fields are required and which are optional.
- The exact response format, field by field, including type and whether it can be null.
- The status code for the success case and for each failure case, named separately.
- One worked example: a real input and the exact output it produces. Prose can be read two ways. A concrete example can only be read one way, which is why it resolves ambiguity that a paragraph of description cannot.
This is more writing than "returns the user's order history." It is also the only version of that sentence that two different people, or two different agent runs, would implement identically.
Failure modes: name every case beyond normal use
Most design docs describe what the feature does when everything goes right, because that is the part everyone agrees on and the part that is interesting to design. What happens when it goes wrong gets a line or two, if it gets anything.
That gap matters more with agent-built code than it used to. Independent testing from Veracode's spring 2026 research, covering generated output from more than 150 models, found code compiling and running correctly over 95 percent of the time while being secure in only about 55 percent of generations. The failures are concentrated exactly where design docs say nothing: access control, input validation, and the paths that only run when something has already gone wrong. A doc that never names those paths gives an agent nothing to build against, so it either invents its own handling or skips it, and both are silent until something breaks in front of a real user.
A design doc that is agent-ready states, for every interface it defines:
- What happens on invalid input, and what the caller sees.
- What happens when a dependency the feature relies on is slow or unavailable.
- What happens if the same request arrives twice.
- What happens when the caller does not have permission to do this.
Writing these down gives you the same information a good test suite needs, stated at design time instead of discovered at review time. We have written before about turning exactly this kind of statement into something a machine can check for itself, in how to write an acceptance test a machine can run.
Non-goals: say what the change will deliberately not do
This is the piece a human-oriented doc almost never includes, because a human reviewer does not need it. If a colleague reads a spec for a search endpoint and it does not mention pagination, they assume pagination is out of scope for now, and if they are unsure, they ask.
An agent does not default to "out of scope." A spec that describes a feature in general terms looks more like a request to be thorough than a limit. Without stated limits, it is common for a generated implementation to add handling nobody asked for: retries around a call that was meant to fail immediately, caching that introduces a bug where old data is shown, or an extra parameter that quietly becomes something another part of the system starts depending on.
A non-goals section prevents that directly:
- "This endpoint does not support pagination in this version."
- "This change does not add retry logic. A failed call returns an error to the caller."
- "This does not change the existing rate limit."
Each line is short, and each one removes a decision the agent would otherwise have to make for itself. The rule for writing them is simple: if a competent engineer reading the doc might reasonably build more than what you intended, write the sentence that rules it out.
What this costs, and what it saves
Writing a design doc this way takes longer than writing one for a colleague who can fill gaps by asking. For a medium-sized feature, the exact interfaces, the failure modes, and the non-goals typically add an hour or two of writing time.
That cost does not disappear if you skip it. It comes later and is larger. A vague doc costs a Slack thread to clarify, then a wrong implementation built on the wrong reading, then a review cycle to catch it, then a rewrite. Every one of those steps is more expensive than the extra hour would have been, and unlike the extra hour, none of them is guaranteed to happen before the code is released.
This is also the same discipline that makes an eval suite, the set of automated checks a build has to pass before it is released, worth writing. A check can only test for a failure mode the doc actually named. A doc that never says what happens on a duplicate request gives the eval suite nothing to verify there, so the gap gets past both the design step and the testing step, and it is found in production.
What we have learned from doing this
This is a claim about who is responsible for resolving ambiguity. In the work we do, a design doc that reads clearly to the team writing it has passed an easier test than a design doc an agent can implement from without guessing, and the two get confused constantly because the first one feels like enough.
The two conditions are close enough to look the same until an agent is the one reading. A design doc is finished when nobody has to ask what it meant.
Sources
- Veracode, Spring 2026 GenAI Code Security update: across more than 150 models, generated code compiled and ran correctly in over 95 percent of cases while being secure in roughly 55 percent, with failures concentrated in access control and input handling.


