Hand a human engineer a ticket that says "the login should be more secure" and they will push back. They will ask what "more secure" means, what counts as done, and how anyone will know. Hand the same ticket to an AI agent and it will not push back. It will pick an interpretation, build something plausible, and hand you a pull request that satisfies a definition of done it invented on your behalf.
That is the core problem with turning loose requirements into agent work. A human fills the gaps with judgment and a hallway conversation. An agent fills them with a guess, and then writes code as if the guess were the spec. The fix is not a smarter agent. It is a spec the agent cannot misread, and that means writing acceptance criteria concrete enough to be tested rather than interpreted.
Why acceptance criteria are the spec an agent can test against
For a human team, acceptance criteria are a communication tool. For an AI agent, they are something stronger: the definition of done that a machine can actually check itself against. When you write acceptance criteria for an AI agent, you are not describing intent for a reader who will interpret it charitably. You are writing the conditions a verification step will evaluate literally.
This changes what "good" looks like. A criterion that reads well in a planning meeting can still be useless to an agent, because the agent cannot tell whether it passed. "The page loads quickly" is fine for a conversation and worthless as a check. Quickly how? Measured where? Under what conditions? If a criterion cannot be turned into something that returns true or false, the agent has no way to know when to stop, and neither do you.
The good news is that this is a solved problem in software, and the solution predates agents by years. It is called behavior-driven development, and its format was designed for exactly this: describing behavior precisely enough that it maps to an automated test.
What makes a criterion testable: Given, When, Then
The Given/When/Then structure, the backbone of Gherkin acceptance criteria, forces three things into the open:
- Given the starting state. The context that exists before anything happens.
- When the action. The single event that triggers the behavior.
- Then the expected outcome. The observable result, stated as something you could check.
The value of the structure is not the keywords. It is that each part is uncomfortable to leave vague. You cannot write a real "Then" clause without deciding what observable thing changes, and that decision is exactly the one loose requirements skip.
Compare two versions of the same requirement.
Weak, the kind an agent will guess at:
Users should be locked out after too many failed login attempts.
Testable:
Given a registered user on the login page, When they submit an incorrect password 5 times within 15 minutes, Then the account is locked for 30 minutes and the 6th attempt returns a "temporarily locked" error rather than "wrong password."
The weak version hides at least three decisions: how many attempts, over what window, and for how long the lockout lasts. An agent handed the weak version will invent all three, and it might invent three of them and lock out anyone. The testable version has no gaps to fill, and it doubles as the description of a test that either passes or fails.
How to write acceptance criteria an agent can verify
You do not need to be exhaustive. You need to be unambiguous about the things that matter. A few habits get you most of the way.
Name concrete values, not adjectives. Replace "fast," "many," "large," and "secure" with numbers, thresholds, and named limits. "Fast" is an argument. "Responds in under 300ms at the 95th percentile" is a check. If you do not know the exact number yet, that is a signal the requirement is not ready for an agent, not a detail to leave open.
State the observable outcome, not the implementation. A good "Then" clause describes what someone or something can observe from the outside: a status code, a visible message, a row in a table, a value in a response. Avoid prescribing how the code should achieve it. You are writing the test, not the solution. This also keeps you from accidentally locking the agent into a bad approach.
Cover the unhappy paths explicitly. The happy path is the one everyone writes and the one that rarely breaks. Failures, empty states, and boundaries are where agents guess worst, because the requirement usually goes silent there. Add criteria for what happens on invalid input, on a timeout, on the sixth attempt, on the empty list. Each one you write is a guess you are taking away from the agent.
Keep one behavior per criterion. A criterion that tries to describe three behaviors becomes a check that cannot tell you which part failed. Split it. Smaller criteria map to smaller, clearer tests, and a failing one points at exactly what went wrong.
Make each criterion independently checkable. If verifying one criterion requires assumptions about another, they are tangled. Each Given/When/Then should stand on its own, with its own starting state, so it can pass or fail in isolation.
The payoff: criteria that double as the test suite
Testable requirements for an AI agent do more than reduce guessing. They become the definition of done that a verification step can run against. When acceptance criteria are written as concrete Given/When/Then conditions, the gap between "the spec" and "the tests" nearly disappears. The criteria describe observable outcomes, and observable outcomes are what tests assert. You end up with a spec that a machine can grade instead of a paragraph a machine has to interpret.
This is the same discipline that makes an eval harness worth building. If you want to measure whether an agent's output is correct, you need a definition of correct that is not a vibe. Acceptance criteria are where that definition starts. (For the downstream half of this, see building an eval harness for a coding agent.)
The honest limitation
Testable acceptance criteria do not capture everything, and pretending otherwise sets you up to be surprised. Some requirements are genuinely hard to reduce to Given/When/Then: subjective quality, visual polish, "does this feel right." You can approximate them with proxies, but a proxy is not the thing, and an agent that passes every proxy can still produce something a human would reject on sight. Those cases are exactly why a person still signs off.
There is also an upfront cost. Writing criteria this precisely is more work than writing "make login secure," and it front-loads the thinking you would otherwise do later, usually while debugging. That is a real trade. The reason it is worth it is that the thinking has to happen somewhere, and doing it before an agent writes code is far cheaper than doing it after, once a wrong guess is buried in a diff.
At Loopsfinity, this is why we treat acceptance criteria as a first-class part of turning a plan into agent work rather than an afterthought. An agent is only as reliable as the definition of done it is measured against, which is the broader argument in how to make an AI coding agent reliable on a real codebase. Precise criteria are not bureaucracy. They are the difference between an agent that guesses what you meant and one that can prove it did what you asked.