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 safety net 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 a shipped behavior.
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 in the room when the tradeoff was discussed.
Here is what has to change: three places a human-oriented doc stays vague on purpose, and what to write there instead.
Interfaces: say the exact shape, not the intent
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 the way you would write a contract, not a description:
- The exact request shape, including which fields are required and which are optional.
- The exact response shape, 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 path that is not the happy one
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 concentrate exactly where design docs go quiet: 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 is not extra caution for its own sake. It is 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 reads less like a boundary and more like an invitation to be thorough. Left unconstrained, it is common for a generated implementation to add handling nobody asked for: retries around a call that was meant to fail fast, caching that introduces a staleness bug nobody scoped for, or an extra parameter that quietly becomes something another part of the system starts depending on.
A non-goals section closes that off 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 moves later and grows. 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 ships.
This is also the same discipline that makes an eval suite, the set of automated checks a build has to pass before it ships, 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 survives both the design step and the testing step, and it is production that finds it.
What we have learned from doing this
None of this is a claim that agents cannot be trusted with ambiguity. It is a claim about where the responsibility for resolving that ambiguity sits. In the work we do, a design doc that reads clearly to the team writing it is not the same test as 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 not finished when your team understands it. It 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.


