AI Coding

How Much of the Spec an Agent Needs Before It Writes Code

A coding agent handed a one-line ticket will produce something. That much is guaranteed. What it produces tends to be a plausible, confident, slightly wrong interpretation of the ticket, and the correction cycle costs more than the spec would have. The interesting question is not whether a spec is needed. It is where the line sits between a spec thin enough to be useful and thick enough to be worth writing.

Most teams guess at that line and guess badly. They either dump a forty-page requirements doc on the agent and watch it drown in contradictory detail, or they hand over a sentence and then act surprised when the agent invents a schema, a naming convention, and an error-handling philosophy that nobody asked for. The productive zone sits between those extremes, and it is narrower than most people expect.

The agent fills every gap with a default

An agent reading a spec is doing something close to what a new contractor does on the first day: scanning for the things that must be decided before work can start, and deciding them silently when the spec is quiet. The difference is that a human contractor will often ask. An agent rarely asks. It picks the most statistically ordinary answer and moves on.

That default is usually fine. It is also usually invisible until review. A spec that says "add a retry to the upload call" leaves the agent to choose the retry count, the backoff curve, whether retries are idempotent, and whether the failure surfaces to the caller or gets swallowed. Four decisions, zero of them mentioned, all of them now baked into a diff that looks reasonable.

The cost of a missing decision is not the decision itself. It is the review comment, the round trip, and the second diff. Multiply that by every silent choice in the file and the spec starts to look cheap.

What the spec actually has to pin down

Four categories carry most of the weight. The first is the boundary of the change: which files, which modules, which surfaces are in scope, and which are explicitly out. An agent given no boundary will wander. It will refactor a helper it found on the way, rename a variable for consistency, and touch three files nobody wanted touched.

The second is the contract. What goes in, what comes out, what happens on the unhappy path. A function signature in the spec is worth a paragraph of prose, because it removes ambiguity the agent would otherwise resolve by guessing. The third is the shape of the data: the fields, their types, which are optional, which are required, which are nullable. An agent that has to invent a schema will invent one that compiles and does not match the database.

The fourth is the constraint that is not obvious from the code. Maybe a particular endpoint has a rate limit. Maybe a migration must run before a deploy. Maybe a downstream service returns 200 with an error body, a fact no amount of reading the local codebase will reveal. Constraints that live outside the repository have to be written down, because the agent cannot discover them.

The parts that can be left out

A surprising amount of the standard spec template is dead weight for an agent. Style and formatting rules mostly get handled by linters and formatters, and restating them in prose just gives the agent two sources of truth to reconcile. Naming conventions, import ordering, comment style: these belong in config, not in the ticket.

Implementation steps are another candidate for omission, at least in most cases. Telling an agent "first create the interface, then the implementation, then the tests" is often telling it something it would have done anyway, and the imposed order can push it toward a structure that does not fit the codebase. The spec should describe the destination and the constraints on the route, not the route itself.

Long motivational context is also mostly wasted. A paragraph on why the feature matters to the business does not change the code the agent writes, and it competes for attention with the parts that do. The agent is not a stakeholder who needs to be persuaded. It is a worker who needs to be pointed.

Acceptance criteria are the load-bearing wall

If one section earns its space more than any other, it is the list of things that must be true when the work is done. A short, concrete, testable list of conditions beats a page of narrative description, because the agent can check its own output against it and the reviewer can check the diff against it.

Good acceptance criteria look like statements a test could assert. The endpoint returns 422 when the payload is missing a required field. The retry stops after three attempts and surfaces the last error. The migration runs cleanly against a database with existing rows. Bad ones look like "the feature works correctly" or "the code is clean," which assert nothing and give the agent nothing to aim at.

The criteria do double duty. They constrain the agent during generation, and they give the reviewer a checklist that does not depend on reading the whole diff line by line. A spec with sharp acceptance criteria and a vague body will usually produce better code than the reverse.

A worked example of the same ticket at three lengths

Consider a ticket to add a soft-delete flag to a users table. At the thinnest, the spec says "add soft delete to users." The agent will pick a column name, a type, a default, decide whether existing queries filter on it, and possibly add a migration with no backfill. Half of those choices will be wrong for reasons the agent could not have known.

At a workable length, the spec names the column (deleted_at, nullable timestamp), states that reads must exclude soft-deleted rows by default, states that the admin listing is the one exception, and lists the three queries that need to change. It notes that the migration must not lock the table for more than a second because the table is large in production. That is maybe eight sentences, and it removes almost every place the agent could go wrong.

At an excessive length, the same spec adds a history of soft-delete patterns at the company, a comparison of soft delete versus hard delete, a paragraph on the philosophy of data retention, and a step-by-step implementation plan. None of that makes the code better. Some of it makes the code worse, because the agent now has more surface area to misread.

When the spec should get longer

There are cases where the thin spec is a mistake. Work that touches money, authentication, permissions, or anything with a regulatory footprint deserves a fuller spec, because the cost of a wrong default is not a review comment. It is an incident. The same goes for changes that cross service boundaries, where the agent cannot see the other side of the contract.

Legacy code deserves more too. An agent dropped into a fifteen-year-old module will pattern-match against whatever it finds, and what it finds may be a convention that was abandoned in 2014 but never removed. A sentence or two pointing at the current convention is cheaper than a rewrite.

There is also a category of work where the spec is the deliverable and the code is downstream. A migration plan, a schema change, an API version bump: these are decisions first and implementations second, and the spec has to make the decisions before the agent can make the code.

The review is where the real spec gets written

Here is the part most teams miss. The first draft from an agent is a form of feedback on the spec. Every place the agent guessed is a place the spec was silent. Every wrong turn is a missing constraint. A team that treats the first diff as a draft to be corrected will keep writing the same thin spec forever. A team that treats the diff as a diagnostic will watch its specs get shorter and sharper over time, because the recurring guesses become the obvious things to write down.

That is the real economy of the thing. The goal is not a longer spec. The goal is a spec where every sentence is doing work, and the way to get there is to let the agent's mistakes teach the team which sentences were missing. After a few cycles, the spec for a typical ticket settles into a shape: a boundary, a contract, a data shape, the non-obvious constraints, and a short list of things that must be true. Everything else gets cut.

The spec an agent needs is smaller than the one a junior engineer needs, and larger than the one a senior engineer needs, because the junior will ask and the senior will know and the agent will quietly guess. The size of the gap between what is written and what must be decided is the size of the risk being taken. Writing just enough to close that gap, and no more, is the whole skill.

Leave a Reply

Your email address will not be published. Required fields are marked *

Back to top button