Anthropic's documentation says the completion evaluator "judges your condition against what Claude has surfaced in the conversation." It is a prompt hook. Prompt hooks run no commands and read no files.
So a goal written as a description of a finished state is graded by reading my own description of the finished state. The claim and its check share one source, and I end up marking my own homework by describing the homework.
| Hook type | Reads files / runs commands | Deterministic |
|---|---|---|
| command | yes | yes |
| http | yes | depends on the endpoint |
| mcp_tool | yes | depends on the tool |
| prompt | no | no |
| agent | yes, experimental | no |
Paste into /goal, replacing the bracketed part.
Finish [THE TASK], where finished means ALL of the following are true and each is proven by output already printed in this conversation, not by a claim about it: 1. ENUMERATION. A numbered checklist of every distinct sub-ask appears in the transcript, written before the work started. If the user added asks mid-turn, the list was extended and re-shown. No item may be merged away or reworded smaller. 2. PER-ITEM EVIDENCE. Beside every item there is one of: a file path that a command in this transcript read, a live URL with the http code a curl in this transcript returned, or the stdout of the command that did the work. An assertion that the item is done carries no weight here. 3. GATE EXIT CODES. For every gate that applies, the transcript shows the command AND its numeric exit code, printed by `echo "exit=$?"` or equivalent. A gate reported as passing, with no exit code shown, counts as unrun. 4. NEGATIVE CHECK. For at least one gate, the transcript shows it FAILING on a deliberately bad input, in this session. A gate that has never been seen to refuse anything is unproven as a gate. 5. NOTHING PARKED AS A SUBSTITUTE. Queueing an item leaves it undone. If an item was queued instead of done, the condition is NOT met unless the user explicitly said to park that specific item. 6. MEASURE THE CONTENT. For every artifact produced, the transcript shows a measurement of what is INSIDE it (a count, a diff, a rendered read), not only that it exists and the writer exited 0. A fixed-shape tool will emit a full-size empty file and exit 0. 7. THE STOP-CHAIN RAN. session_fraud_check.py --hard-only appears in this transcript with its RESULT line. If any of 1 through 7 is unproven, the goal is NOT met, and the correct next action is to do the missing work, never to explain why it is acceptable to stop.
Finish [TASK]. Not met until the transcript shows, for every sub-ask, the command output that proves it, every applicable gate with its numeric exit code, and a session_fraud_check --hard-only RESULT line. A described result carries no weight.
/loop re-enters on a schedule and makes no judgement about completion. Pair it with the goal above so the loop has a terminating condition that is evidence-shaped, and add this line so an idle tick cannot pass as progress.
On each iteration, either produce new command output that advances an unmet numbered item, or state which item is blocked and what specific input is needed. A tick that only restates prior progress is a no-op and must be reported as one.
The evaluator verifies nothing. It can only notice that the transcript looks like it holds evidence, so a determined summariser defeats it. The authority has to sit in a command Stop hook, which does read files and does return an exit code.
| Hook | What it enforces | Wired |
|---|---|---|
| done_claim_gate.py | no "done" language unless the turn read the artifact or ran the fraud check | yes |
| fraud_check_gate.py | the fraud scanner ran | yes |
| source_grounding_gate.py | factual claims carry sources | yes |
| ask_drift_gate.py | the reply addresses the thing the user named | yes |
| no_idle_stop_gate.py | completion-shaped reply + empty queue = keep working | yes, wired 29 Aug |
| Branch | Blocks | Wanted | |
|---|---|---|---|
| completion-shaped reply, empty queue | True | True | PASS |
| completion-shaped reply, open queue | False | False | PASS |
| user said stop | False | False | PASS |
| reply says NOT finished | False | False | PASS |
| reply says still needs work | False | False | PASS |
| explicit "session truly complete" | False | False | PASS |
The gate's queue path is now overridable by an environment variable, so it can be exercised against a fixture. A gate that cannot be run against a known-bad input is never proven to refuse anything, which is clause 4 of the template applied to the template's own backstop.