Why a verifiable loop beats a better prompt
By the end you can
- State what Claude uses as a stop signal when you supply no check
- Recognise a check as any signal Claude can read in the conversation
- Put verification criteria into the request instead of appending them afterwards
- Ask for evidence — output, exit code, screenshot — rather than a verdict
- Explain why a check closes a loop that a better-worded prompt leaves open
The run ends. The last message says the change is implemented and working. You read the diff, it looks reasonable, you commit it, and two days later somebody finds the case it does not handle.
Nothing went wrong that a better-worded request would have caught. What was missing is smaller and more mechanical than that: at the moment Claude decided it was finished, nothing in the session could have told it otherwise.
The signal you are replacing
Claude stops when the work looks done. Without a check it can run, "looks done" is the only signal available, and you become the verification loop: every mistake waits for you to notice it. — Best practices
Read the second half of that sentence as a job description, because it is describing your current job. If nothing in the session can fail, then the only component that can detect a failure is you, and it detects it whenever you next happen to look. Every mistake sits in the queue behind your attention.
That is the thing this level removes. Not by making the model better at judging its own work — by putting something in the session that is not the model.
What counts as a check
The bar is lower than "we have a test suite", and the definition is explicit:
The check is anything that returns a signal Claude can read in the conversation: a test suite, a build exit code, a linter, a script that diffs output against a fixture, or a browser screenshot compared against a design. — Best practices
Two words in there do all the work. Signal: something that comes back different when the work is wrong. Conversation: it has to land in the window, where Claude can read it, not on a dashboard you look at later.
| Kind of work | The check | What "fail" looks like |
|---|---|---|
| A function with known cases | The test suite | A named failing assertion |
| A change that must still build | The build | A non-zero exit code |
| Style and obvious defects | The linter | Reported findings |
| A transform with known output | A script that diffs output against a fixture | A diff |
| A UI change against a design | A screenshot compared to the original | A list of differences |
The last row is the one people rule out too early, and Lesson 5.3 is entirely about the cases where "there is nothing to run" turns out to be false.
The loop, closed
Give Claude something that produces a pass or fail, and the loop closes on its own. Claude does the work, runs the check, reads the result, and iterates until the check passes. — Best practices
Running the check is not an extra phase bolted onto the end. It is an ordinary tool call. Which tools get used is Claude's choice, made from your prompt and what it learns along the way — but the sequence the docs sketch for "fix the failing tests" has verification at both ends of it: run the suite to see what is failing, read the error output, search for the relevant source files, read them, edit them, run the tests again to verify. That is offered as what Claude might do, not as a guarantee, which is the point: nothing there is forced.
Each tool use gives Claude new information that informs the next step. This is the agentic loop in action. — How Claude Code works
So a check is not a new mechanism you are introducing. It is the loop from Level 1 with a rung that can return no. Without one, the session fills up with results that describe what the code says, and not one of them is a signal that can come back failing.
The everyday recipes are already built this way. The documented sequence for adding tests to a service runs: find the untested functions, generate the scaffolding, add edge-condition cases, and then —
run the new tests and fix any failures — Common workflows
The recipe ends on the check, not on the edit. That final step is the whole difference between a task that reports completion and a task that has been through something.
Putting the criteria in the request
The criteria have to be in the message that asks for the work. Appended afterwards, "did you run the tests?" is you doing the verification loop again, one turn later.
Three documented rewrites, each of which turns a wish into something with a result:
| Strategy | Before | After |
|---|---|---|
| Provide verification criteria | "implement a function that validates email addresses" | "write a validateEmail function. example test cases: user@example.com is true, invalid is false, user@.com is false. run the tests after implementing" |
| Verify UI changes visually | "make the dashboard look better" | "[paste screenshot] implement this design. take a screenshot of the result and compare it to the original. list differences and fix them" |
| Address root causes, not symptoms | "the build is failing" | "the build fails with this error: [paste error]. fix it and verify the build succeeds. address the root cause, don't suppress the error" |
Notice what the "after" column is not. It is not longer prose about quality, it is not a tone, and it does not describe the implementation. Each one adds two things: the cases that decide the answer, and the instruction to run them.
The same shape works on a bug report. The documented rewrite of "fix the login bug" names the symptom, points at the likely location, and then defines done:
write a failing test that reproduces the issue, then fix it — Best practices
Lesson 2.4 argued for reporting the symptom rather than your diagnosis. This is the other end of the same request: the symptom says what to look at, the reproducing test says what will prove it is gone. Lesson 5.4 takes that pattern on its own.
Ask for evidence, not a verdict
A check that ran and a check that is claimed to have run are indistinguishable in a summary. So ask for the artefact:
Have Claude show evidence rather than asserting success: the test output, the command it ran and what it returned, or a screenshot of the result. — Best practices
This costs you almost nothing and it is the only review that scales:
Reviewing evidence is faster than re-running the verification yourself, and it works for sessions you weren't watching. — Best practices
The habit generalises past Claude Code, but it bites hardest here, because a long autonomous run produces a great deal of confident prose and you will not read all of it.
Why this outranks a better prompt
The two are not competing for the same slot: the prompt aims the work, the check decides when it is over.
| A better prompt | A check | |
|---|---|---|
| Acts on | The first attempt | Every iteration |
| Detects a mistake | If you happen to read that part | When the signal comes back failing |
| Who closes the loop | You | The session |
| Works while you are away | No | Yes |
Which is why the official summary of this idea is framed as a change in what your session is, not in how well it is worded:
Give Claude a check it can run: tests, a build, a screenshot to compare. It's the difference between a session you watch and one you walk away from. — Best practices
Two boundaries before you go and rely on this. First, Claude's check passing is
not the end of your involvement — the guidance is to run /verify yourself
afterwards to confirm the change against the running app. Second, having a check
and enforcing it are different decisions; how hard the check gates the stop is
Lesson 5.2, and Lesson 5.5 covers the runs that end green with the check
unsatisfied.
For now, one habit. Before you send a request that will take more than a couple of minutes to satisfy, answer this: what, in this session, will come back failing if the change is wrong? If the answer is "I will notice", you have not written the request yet.
Checkpoint
-
You ask for a refactor of a module that has no tests, and get back a clean diff and the sentence "all existing behaviour is preserved". What exactly do you have, and what would you have to see for the claim to become evidence?
Show answerAnswer
You have an unverified change described confidently. That sentence contains no command, no output and no exit code — it is a claim in exactly the register of a result, which is why it gets read as one — and with no tests there was nothing in the session that could have come back failing. The loop never closed; you are still the component that detects the mistake, whenever you next happen to look.
For the claim to become evidence you need the artefact: the command that was run and what it returned, the test output, or a screenshot of the result. Scan upward for one, and if there isn't one the correct next move is to ask for the command and its output rather than to re-argue the design. "No suite" is not the same statement as "no signal" — a build exit code, a linter, or a script that diffs output against a fixture all qualify, which is Lesson 5.3 in full — and once something does pass, the guidance is still to run
/verifyyourself against the running app. -
Rewrite "speed up the search endpoint" into a request that closes its own loop. What is the signal, and what makes it readable in the conversation?
Show answerAnswer
Add the two things the documented rewrites add: the cases that decide the answer, and the instruction to run them. Something like: "the search endpoint is slow. run the benchmark for it and paste the number. then optimise it, run the benchmark again and paste that number. it passes at or below [an actual figure], measured on the same dataset, with the response shape unchanged." The benchmark command is whatever your repo already has; the shape of the request is the point.
The signal is the benchmark's own output measured against the named threshold — something that comes back different when the work is wrong. What makes it readable is that you asked for the run and the numbers, so the result lands in the conversation window where Claude can read it, not on a dashboard you look at later. The tempting near-miss is ending the request with "and confirm it's faster": that asks for a verdict, and a check that ran and a check that is claimed to have run are indistinguishable in a summary.
-
Two teammates each get the same task. One spends ten minutes wording the prompt; the other writes three example cases into it and says to run them. Both go to lunch. Whose session is in a better state when they get back, and why does the answer not depend on how good the first one's wording was?
Show answerAnswer
The second teammate's. The two are not competing for the same slot: the prompt aims the work, the check decides when it is over. A better prompt acts on the first attempt and surfaces a mistake only if you happen to read that part; a check acts on every iteration and surfaces the mistake when the signal comes back failing. So over lunch the second session can close its own loop — do the work, run the check, read the result, iterate until it passes — while the first has to end on "looks done", because with nothing to run that is the only signal available.
Wording cannot move the first session into the other column. However well phrased, the request still acts once, still cannot come back failing, and still leaves the person who wrote it as the only component able to detect a failure — and they are at lunch. That is the whole "works while you are away" row. It does not end the second teammate's involvement either: Claude's check passing is the cue to run
/verifyyourself against the running app, not the end of the story.