Writing specs that AI coding agents can actually follow

How to write specs AI coding agents can follow: clear scope, verified names, checkable acceptance criteria, edge cases and a definition of done they can run.

By Hamza Ghouri

An AI coding agent will implement whatever your spec says, plus whatever it guesses the spec meant. The guessing is where things go wrong. Writing specs that AI coding agents can actually follow comes down to removing the room for guesses: every name verified, every rule checkable, every edge case written down before the agent starts.

I work spec-first with my team, and those specs are increasingly read by agents as well as people. A spec that works for an agent turns out to be a better spec for humans too. Here is the structure I use.

Why agents need a different level of precision

A human engineer reading "add export to the vehicles page" will ask which format, which columns, and whether it respects the current filters. An agent picks answers and keeps going. It will also happily call a helper function that sounds right and does not exist, or add a config key nobody defined.

So a spec for an agent has two extra jobs. It has to close the questions a person would have asked. And it has to anchor the agent to things that really exist in the codebase, so it builds on them and stops inventing.

Number it, and amend it when things change

Every spec gets a number. A new feature is a new spec. A change to a flow that already shipped amends the spec that owns it, keeping the same number, with the amendment written into the same document. The branch is named after the spec.

For an agent, this matters because the spec you hand it is the full, current story of that flow. If behavior was changed through scattered tickets, the agent reads an outdated spec and "corrects" the code back to old behavior. One owning spec with its amendments prevents that. I go into the wider workflow in Spec-Driven Development in the age of AI coding assistants.

The sections I include

These are the parts that earn their place:

  1. Goal. One or two sentences about the user-visible outcome. The agent uses this to break ties when details are unclear.
  2. Scope and out of scope. What this spec covers, and an explicit list of what it leaves alone. "Do not change the list endpoint's pagination" saves a surprising number of review comments.
  3. Existing code to build on. The real files, functions, tables and components involved, with names copied from the codebase. Check every one before writing it down.
  4. Behavior. The flow, step by step, in plain language.
  5. Data shapes. Request and response bodies, new columns, enum values. Exact field names, exact types.
  6. Edge cases. Empty states, permissions, concurrent edits, failures from external services.
  7. Acceptance criteria. Statements a person or a test can check as true or false.
  8. Definition of done. The commands that must pass and anything the agent must exercise by hand.

Acceptance criteria an agent can check

Vague criteria produce vague implementations. "The confirmation flow should feel natural" gives an agent nothing to verify. Here is the style I aim for, written around a flow from the in-app AI assistant in the Recond Flutter app, where the agent can propose creating a record and the user confirms or cancels:

  • When the assistant proposes a new record, the chat shows a create card with Confirm and Cancel actions.
  • Record cards in the chat have an Open button that jumps straight to that record.
  • Cancel marks the card as cancelled, and a cancelled card stays cancelled, including after the chat reloads.
  • While a card is rendering, a loader is shown in its place.

Each line is true or false. An agent can write a test for each one, and a reviewer can check each one in a minute. The "stays cancelled" rule is a good example of something worth spelling out: it is obvious to a person who has used the feature and easy for an implementer to miss.

Anchor the agent to reality

A very common agent mistake is a confident reference to something that does not exist. A spec can head that off.

  • List the real names. If the work touches a service, a table or a widget, name it exactly. If something has to be created, say so explicitly, so the agent knows that one is new.
  • Say where new code goes. Point at the folder or module that holds similar code.
  • Forbid shortcuts you would reject. No new dependencies without asking, no changes to shared config, no edits outside the listed files.
  • Tell it to ask when blocked. One concrete question at the point it is stuck beats a guess buried in the diff.

Team-wide rules belong elsewhere. On my team, conventions like branch naming, PR workflow and comment style are served to agents from a conventions server, an MCP server grouped by platform. The spec stays focused on this feature, and the conventions server covers how we build everything.

Make "done" something the agent can run

The last section is the one people skip, and for agents it matters most. Without it, "done" means "the code compiles".

A good definition of done lists commands: the test suite, the type checker, the linter, any migration check. For UI work, it also says what to exercise in the running app. Our conventions include Marionette, which lets an agent drive a Flutter app in debug mode, so a Flutter spec can say "open the chat, trigger a create card, cancel it, reload the chat and confirm it still shows cancelled". I cover that setup in testing Flutter apps with AI agents.

Then ask the agent to report what it ran and what it could not test. A clear "not verified" is far more useful than a confident claim that everything works.

Where I'd start

Take your next feature and write the spec with these eight sections, using names checked against the codebase and acceptance criteria that are true or false. Hand it to an agent with your team conventions and a runnable definition of done, then review the result against the spec. If you are new to the approach, start with why I adopted Spec-Driven Development.

Want this kind of work on your product?

Get in touch