specshop.dev / Journal / Methodology
Methodology 9 min read Updated

How to write a spec for AI agents, with the template we use

How to write a spec for AI agents: 5 parts, outcome, constraints, examples, acceptance checks and must-nots, with a worked example and our template.

Anudi Imesha
Customer Success Manager · specshop.dev

How to write a spec for AI agents comes down to five parts: the outcome, the constraints, worked examples, acceptance checks the agent can run itself, and an explicit list of what it must not do. Those five fit inside 600 words for most features, and the part teams leave out is the last, which is why an agent that was never told what is out of bounds hands back something plausible, confident and wrong.

The five parts of a spec an AI agent can build from: outcome, constraints, examples, acceptance checks and must-nots
Figure 28. A spec an agent can build from has five parts. Source: the specshop.dev spec template, in the post.

Picture an engineer at a mid-sized product company. She is our invention, but her afternoon is not unusual. She gives her coding agent a two-line ticket: send reminders for overdue invoices, use the existing email service. Twelve minutes later she has a branch, passing tests, a tidy diff and a feature that emails a client the firm is in an active payment dispute with. The agent did nothing wrong. Nobody told it that clients can be in dispute, so the concept did not exist in the brief, and an agent will not invent a rule it has never seen.

Every US dollar figure below converts at LKR 328.75, the Central Bank of Sri Lanka’s indicative USD/LKR spot rate for 10 September 2026.

Why most specs fail an agent

Human-written specs are tuned for human readers, who arrive with context and, crucially, who interrupt. A developer reading “send reminders for overdue invoices” walks over and asks what happens to disputed clients. An agent does not ask. It resolves the ambiguity in silence, picks the most ordinary reading, and writes it up as though it were decided.

That is the whole problem, and it is old. Joel Spolsky wrote in 2000 that “the most important function of a spec is to design the program”, and that with one you “only have to communicate how the program is supposed to work once”. His argument was about saving human time. With agents it is narrower: the spec is the only place your intent exists in a form the builder can read. We made that case in The Spec Was Always the Product, and its consequences for your other documents in You Don’t Have an Architecture Problem. You Have an Artifact Problem.

Requirements for AI agents are not new in kind, and requirements engineering already knew the fix. The characteristics ISO/IEC/IEEE 29148 asks of a good requirement, summarised here, are that it be unambiguous, complete, singular and verifiable, and its line about subjective wording is the one to tape to your monitor: requirements “should not contain subjective language like ‘user-friendly’, which is not verifiable”. An agent cannot build “user-friendly”. It can build “the reminder shows the invoice number, the amount in LKR and the due date, in that order”.

Vendors agree. Anthropic’s Claude Code documentation on project memory tells you to “write instructions that are concrete enough to verify”, offering “Use 2-space indentation” instead of “Format code properly”. It also warns that “if two rules contradict each other, Claude may pick one arbitrarily”, the second failure mode after silence: a self-contradicting spec does not stop an agent, it makes the outcome a coin toss.

The five parts

SectionWhat goes inA bad exampleA good example
OutcomeWhat is true for the user after this ships, and what decision it changes“Improve invoice collection”“An unpaid invoice gets one reminder at 14 days overdue, so nobody chases by hand”
ConstraintsData it may touch, systems it may call, timing and volume limits, rules from law or policy“Follow our email best practice”“Send only 09:00 to 17:00 Colombo time on working days, one reminder per invoice per 7 days”
ExamplesThree real-shaped cases with inputs and exact expected output: normal, edge, do nothing“For example, overdue invoices”“INV-2291, LKR 185,000, due 22 July, unpaid, not disputed: send reminder text A”
Acceptance checksOne Given, When, Then per rule, plus the command that runs them“Make sure it works”“Given an invoice 14 days overdue and a client flagged disputed, When the job runs, Then no email is sent”
Must notActions that are wrong even when everything else passes, and what to do instead(usually absent)“Never email a client flagged as disputed. Queue it for review instead”

Two notes. Examples are the cheapest way to make a rule unambiguous: an agent that has seen three concrete cases generalises correctly far more often than one given a paragraph of prose. And must-nots do not duplicate the constraints. Constraints describe the box. Must-nots name the irreversible things, sending, charging, deleting, publishing, that you would rather the agent refused than guessed at.

A worked example: an invoice reminder rule

Take a six-partner accounting practice in Colombo 3, raising about 300 invoices a month, where one person spends two mornings a week chasing them.

Outcome. An unpaid invoice 14 or more days past its due date receives one reminder email, so the practice manager stops chasing by hand and reviews only exceptions.

Constraints. The rule reads the invoice ledger and writes only to a reminder log. It sends between 09:00 and 17:00 Colombo time on working days, at most one reminder per invoice per 7 days. Amounts appear in LKR as they were raised. It never sends to a client flagged as disputed and never changes an invoice’s status. Reminder text is one of two approved templates, and the agent edits neither.

Examples. One: invoice INV-2291, LKR 185,000, due 22 July, unpaid, 16 days overdue, client not disputed, no reminder logged; expected, send the first-reminder template and log it. Two: invoice INV-2304, LKR 42,500, 21 days overdue, client flagged disputed; expected, send nothing, add the invoice to the review queue with the reason “disputed”. Three: invoice INV-2310, LKR 96,000, 3 days overdue; expected, do nothing and log nothing.

Must not. Never email a client flagged as disputed. Never send a second reminder within 7 days of the first. Never mark an invoice paid, void or written off. Never send outside working hours. When any of these would trigger, stop and write a line to the review queue.

That is about 250 words, and it separates a feature the practice manager trusts on the first run from one she audits for a fortnight.

Acceptance checks the agent can run

Write the checks in Given, When, Then. The Cucumber Gherkin reference defines it precisely: “Given steps are used to describe the initial context of the system”, “When steps are used to describe an event, or an action”, and “Then steps are used to describe an expected outcome, or result”. You do not need Cucumber installed. The format forces one condition, one trigger and one observable result per line, which is how 29148’s singular and verifiable characteristics arrive through the back door.

For the reminder rule:

  • Given an invoice 16 days overdue and a client not flagged disputed, When the reminder job runs, Then exactly one first-reminder email is sent and one log line is written.
  • Given an invoice 21 days overdue and a client flagged disputed, When the reminder job runs, Then no email is sent and the invoice appears in the review queue with reason “disputed”.
  • Given an invoice 3 days overdue, When the job runs, Then no email is sent and no log line is written.
  • Given an invoice reminded 4 days ago, When the job runs, Then no email is sent.

Then name the command that runs them. A check the agent cannot execute is a wish; one it can execute is a gate, and it turns review from reading a diff into reading a result.

The template, in full

Copy this. It is the file we start every feature with, and it lives in the repository next to the code.

# Spec: name of the feature, one line

## Outcome
What is true for the user after this ships, and what task or
decision it changes. One or two sentences. Not how it is built.

## Constraints
Data it may read, and the single place it may write.
Systems it may call, and the ones it may not.
Timing, volume and cost limits, with numbers.
Rules from law, policy or contract, with the source named.
Decisions already made that are not up for debate.

## Examples
Three cases with real-shaped values, each with inputs and the exact
expected output: one ordinary, one edge case, one where the correct
behaviour is to do nothing.

## Acceptance checks
One Given, When, Then per rule, written so the agent can turn each
into a test and run it without asking a question.
The command that runs the suite.

## Must not
Actions that are wrong even if every check above passes.
Anything irreversible, chargeable or visible to a customer.
What the agent should do instead when it hits one.

## Open questions
Anything you could not answer. The agent stops here rather than
guessing. An empty list means the spec is ready to build.

Length is not the goal. The open-questions section is there so an unanswered question fails loudly instead of being resolved quietly by a model.

What the training adds

specshop.dev is an AI consultancy and AI agency in Colombo, Sri Lanka, led by Janaka Ediriweera, Principal AI and Product Management Consultant. A template gets you the shape, not the judgement about which ambiguity matters, and that only comes from watching specs fail.

Our AI training programme runs over two consecutive weekends, eighteen hours in total, at US$500 to US$2,000 a seat depending on the track, about LKR 164,375 to LKR 657,500. It opens with failure forensics, reading real agent output against the spec that produced it, because engineers learn a missing constraint faster from a wrong diff than from a checklist. It is application-gated: two years of experience and one feature already shipped with Claude Code, Cursor, Devin or Aider. The method behind it is set out in spec-first development, explained.

To see the artefact working inside your own repository instead, the delivery engineer is the senior post on the roster when you hire an AI agent, at US$3,000 a month, about LKR 986,250. It builds to a signed spec and opens the pull request. Your engineers review and merge against the spec, not the prompt.

What to do this week

Take one feature your agent got almost right. Open the diff and write down every decision it made that you never specified. That list is your missing constraints and, usually, your entire must-not section.

Then rewrite the ticket using the template above, delete the branch, and build again from the spec. Compare the diffs. If the second is boring, the spec worked.

Questions people actually ask.

What should a spec for an AI coding agent include?

A spec for an AI coding agent should include five sections: the outcome in user terms, the constraints on data, systems, timing and policy, three worked examples with exact expected outputs, acceptance checks written as Given, When, Then that the agent can run itself, and an explicit list of what it must not do. Add a sixth section for open questions, so that anything you could not answer stops the build rather than being guessed at.

How long should a spec be?

For a single feature, under 600 words is usually right, and anything over two pages is normally two features that should be specified separately. Length is the wrong measure: a spec is finished when every “what happens when” question a reviewer can think of has a written answer, not when it reaches a page count.

Can an AI write its own spec?

An agent is very good at drafting a spec from a conversation and excellent at finding gaps in one you wrote, so ask it to list the assumptions it would have to make. It should not sign the spec, because the decisions inside it, what the business will and will not do, are accountability rather than text generation, and an agent that invents a constraint will build to it just as confidently.

What is an acceptance check?

An acceptance check is a single testable statement of expected behaviour, written as one initial condition, one trigger and one observable result, in the Given, When, Then form that Cucumber’s Gherkin reference defines. The test of a good acceptance check is that the agent can convert it into an automated test and run it without asking you anything.

Where can I get a spec template?

The full template is printed in this post as a copyable block, with no download and no email gate, and you are free to paste it straight into your repository. Put it beside the code rather than in a separate documents system, so that it is reviewed, versioned and updated in the same pull request as the change it describes.

Sources

  1. How Claude remembers your project, Claude Code documentation, Anthropic, 2026 — guidance to “write instructions that are concrete enough to verify”, with “Use 2-space indentation” instead of “Format code properly” and “Run npm test before committing” instead of “Test your changes”, and the warning that “if two rules contradict each other, Claude may pick one arbitrarily”. Fetched 10 September 2026.
  2. Gherkin reference, Cucumber documentation, 2026 — “Given steps are used to describe the initial context of the system”, “When steps are used to describe an event, or an action”, “Then steps are used to describe an expected outcome, or result”. Fetched 10 September 2026.
  3. Painless Functional Specifications, Part 1: Why Bother, Joel Spolsky, 2000 — “the most important function of a spec is to design the program”, and that with a spec “you only have to communicate how the program is supposed to work once”. Fetched 10 September 2026.
  4. ISO 29148 explained, Modern Requirements, 2024 — summary of the ISO/IEC/IEEE 29148 characteristics of a good requirement, including unambiguous, complete, singular and verifiable, and the point that requirements “should not contain subjective language like ‘user-friendly’, which is not verifiable”. Fetched 10 September 2026.
  5. Daily Indicative USD/LKR Spot Exchange Rates, Central Bank of Sri Lanka, 2026 — the indicative rate of LKR 328.75 per US$1 on 10 September 2026, used for every conversion in this post.