The Goal Prompt That Does Not Let Me Stop

Why a goal condition alone cannot hold, and what has to sit under it
7evidence clauses
6 / 6gate branches proven
1gate found unwired
1defect fixed in it

Why a goal condition alone cannot hold

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 typeReads files / runs commandsDeterministic
commandyesyes
httpyesdepends on the endpoint
mcp_toolyesdepends on the tool
promptnono
agentyes, experimentalno

The rule the prompt is built on

Write every condition so the only way to satisfy it is to paste a command's output. A condition a sentence can satisfy will be satisfied by a sentence.

The template

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.

The one-line version, for small tasks

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.

For /loop

/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 executable backstop

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.

HookWhat it enforcesWired
done_claim_gate.pyno "done" language unless the turn read the artifact or ran the fraud checkyes
fraud_check_gate.pythe fraud scanner ranyes
source_grounding_gate.pyfactual claims carry sourcesyes
ask_drift_gate.pythe reply addresses the thing the user namedyes
no_idle_stop_gate.pycompletion-shaped reply + empty queue = keep workingyes, wired 29 Aug
The gap this pass found. The one gate aimed squarely at stopping too early, no_idle_stop_gate.py, was written and left out of settings.json. It had never fired. It is now wired, and the merge added exactly one line: every other hook event and top-level key is byte-identical to the backup.
A defect fixed before wiring it. Its completion regex matched the bare word "finished", so the reply "I have not finished" counted as a completion claim and the gate fired on honest in-progress replies. That is how a gate gets switched off. A negation guard now suppresses the match, and the branch is covered by a test.

Proof, all six branches

BranchBlocksWanted
completion-shaped reply, empty queueTrueTruePASS
completion-shaped reply, open queueFalseFalsePASS
user said stopFalseFalsePASS
reply says NOT finishedFalseFalsePASS
reply says still needs workFalseFalsePASS
explicit "session truly complete"FalseFalsePASS

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.