Claude Code goal Command: Turns Until a Condition Holds

It sets a completion condition for the current session. After every turn, a small fast model reads the condition and the conversation and returns a verdict. If the condition is not yet met, Claude starts another turn instead of returning control to you, so a long piece of work continues without you prompting each step.
Write something Claude's own output can demonstrate, because the evaluator never runs commands or reads files — it only judges what is already in the transcript. Name one measurable end state, state how Claude should prove it, and add any constraint that must hold on the way. Including a clause like stop after twenty turns bounds the run.
Run the goal command with the argument clear, or one of its aliases stop, off, reset, none and cancel. Starting a new conversation also removes an active goal. A goal clears itself when the condition is met, when the evaluator judges it impossible, or after an error that will not resolve on its own.
Both keep a session running between your prompts, but they differ in what starts the next turn. A goal starts the next turn when the previous one finishes and the condition is not yet met. A loop starts the next turn when a time interval elapses. A Stop hook you write yourself also fires after every turn, with logic you control.
No. A goal does not change your permission mode, so in a mode that still asks, each goal turn stops at the first tool call. Run the goal in auto mode if you want turns to run unattended. The two are complementary: auto mode removes prompts inside a turn, and the goal removes the prompt between turns.

Key Takeaway
The goal command sets a completion condition, and after each turn a small fast model judges whether it holds. Not met, and Claude starts another turn instead of handing control back. It clears itself when the condition is met, when the evaluator judges it impossible, or when a turn fails on an error only you can fix.
I used to babysit long refactors by typing continue every few minutes, which is a strange job for a person. The first time I set a condition instead and walked away, I came back to a finished migration and a transcript full of verdicts explaining what each turn had been aiming at. The second time, I came back to eleven turns of a model politely explaining that it could not verify something I had phrased badly.
Both outcomes come from the same mechanism, and understanding it is most of the skill. This post covers what happens after each turn, how to write a condition the evaluator can actually judge, the commands, how this compares with a loop and with a hand-written Stop hook, what background work does to evaluation, the failures that clear a goal, and what it costs.
The command is a wrapper around a session-scoped prompt-based Stop hook. When a turn finishes, Claude Code sends your condition and the conversation so far to the small fast model configured for your provider — Haiku by default on the Claude API — and it returns one of three verdicts with a short reason:
There is a safety valve worth knowing about. If Claude keeps answering the evaluator without using any tools for several turns in a row, Claude Code stops the loop, prints a warning, and gives you back control with the goal still set. Evaluation resumes on your next prompt. In practice that is what a badly phrased condition looks like from the outside.
The single most useful fact about the evaluator is that it does not run commands and does not read files. It judges only what Claude has already surfaced in the conversation. So a condition works when Claude's own output can demonstrate it — tests pass because Claude ran them and the result is in the transcript. A condition about the state of the world that nothing in the transcript proves will simply never resolve.
# Set it. This starts a turn immediately — the condition IS
# the first directive, so you do not send a separate prompt.
/goal all tests in test/auth pass and the lint step is clean
# A condition that holds up over many turns names one end state,
# how to prove it, and what must not change on the way:
/goal every call site in src/billing compiles against the v3
client and npm test exits 0, with no test file modified,
or stop after 20 turns
/goal # status: condition, elapsed, turns, tokens, last reason
/goal clear # also: stop, off, reset, none, cancel
# Non-interactive. Nothing prints until the run ends unless you
# ask for the stream.
claude -p "/goal CHANGELOG.md has an entry for every PR merged
this week" --output-format stream-json --verbosePut the bound inside the condition. There is no maximum-turns flag here, but the condition can be up to 4,000 characters and the evaluator reads all of it, so a clause like or stop after 20 turns becomes part of what is judged: Claude reports progress against it each turn and the evaluator eventually calls it met. That is the difference between walking away for ten minutes and walking away for an afternoon.
Three mechanisms keep a session running between your prompts, and they differ in what starts the next turn rather than in what they can do. Picking the wrong one is the usual reason people conclude that autonomous sessions do not work.
Which one to reach for:
| Approach | Next turn starts when | It stops when |
|---|---|---|
| The goal command | The previous turn finishes, or an idle check-in comes due while background work keeps it waiting | A model confirms the condition is met or impossible, an unrecoverable error hits, or you clear it |
| The loop command | A time interval elapses | You stop it, or Claude decides the work is done |
| A Stop hook in settings | The previous turn finishes | Your own script or prompt decides |
A turn that ends while a subagent or a background shell command is still running is not evaluated at all — Claude Code waits for the next turn that finishes clean. That is the right behaviour, and it introduces the one piece of machinery here that surprises people: a check-in ladder that keeps a waiting goal honest without hammering it.
# Background work DEFERS evaluation. A turn that ends with a
# subagent or a background shell command still running is not
# evaluated; the next turn that ends clean is.
#
# After 30 minutes of waiting, a check-in is due. Claude is asked
# to read the running tasks' output, keep waiting if they are
# progressing, and fix or stop anything stuck.
#
# The interval then DOUBLES, capped at four times the first:
# 30 min -> 1 hour -> every 2 hours
CLAUDE_CODE_GOAL_CHECKIN_MINUTES=15 # scales the whole ladder
CLAUDE_CODE_GOAL_CHECKIN_MINUTES=0 # no check-ins at all
# In an interactive session, up to THREE idle check-ins per goal
# between your prompts. The third one says idle check-ins are
# paused until you send another prompt.The distinction is between errors you have to fix and errors that resolve themselves. Only four kinds clear the goal, and each of them would otherwise leave the loop failing the same way forever. Transient failures — rate limits, an overloaded server — deliberately leave it active, because retrying is exactly the right response to those.
# Four failures clear the goal. Everything else — rate limits,
# overloaded servers, transient errors — leaves it active.
#
# an authentication failure, when Claude Code manages its own
# credentials (a host that manages them for you keeps the
# goal alive, because the host restores access itself)
# an exhausted credit balance
# a context overflow auto-compaction could not clear
# a model that is not available
#
# The warning starts "Goal cleared after an unrecoverable error"
# and ends "Run /goal again to continue".
# /goal is unavailable, and says why, when:
# the workspace is untrusted (the evaluator is a hook)
# disableAllHooks is true after settings precedence
# allowManagedHooksOnly is set in managed settingsEvaluation runs on whichever provider your session already uses, and the tokens are billed on the small fast model, which is normally negligible next to the turns themselves. You can point evaluation at a different model, and that is where the care is needed.
Setting the default Haiku model environment variable does not only affect goal evaluation. Claude Code reads it everywhere it uses the small fast model, resolves the haiku alias to it, and runs background functionality such as conversation summarisation on it. So changing it to get a smarter evaluator quietly changes your summariser and several other things at the same time.
A goal does not change your permission mode, which means in a mode that still asks, every goal turn stops at the first prompt and the whole point evaporates. Run it in auto mode if you want turns to run unattended. And because the evaluator is part of the hooks system, the command follows the same workspace trust rule as hooks in settings files, and is unavailable when hooks are disabled or restricted to managed ones.
Auto mode and a goal solve different halves of the same problem, which is why they pair well. Auto mode removes the per-tool prompt inside a turn; the goal removes the per-turn prompt between them. Neither replaces the other, and running a goal without auto mode is the most common way to end up watching a supposedly autonomous session wait for you.
Write the condition as something the transcript can prove, put a turn or time bound inside it, and run it in a mode that does not stop at every tool call. Then read the verdicts rather than the output: the evaluator's reason each turn is the clearest signal you get about whether the session understands what done means, and a run that is drifting says so there several turns before it becomes obvious anywhere else.
Sources & further reading