Working toward a goal with /goal
Give Claude Code a completion condition and let it keep taking turns until a separate evaluator confirms the condition holds.
Normally Claude finishes a turn and hands control back to you, even when the job is plainly half done. /goal changes that. You state the end condition once, and after every turn a separate model checks whether it holds. If not, Claude starts another turn on its own. The loop ends when the condition is met, when the evaluator decides it can never be met, when a turn hits an error only you can fix, or when you clear it.
It suits large jobs with a checkable finish line:
- Porting every caller of a deprecated client to the new SDK until the build passes.
- Working through a design doc until each acceptance criterion is demonstrably true.
- Breaking a 3,000-line module into files under a size budget.
- Emptying a labelled issue queue.
/goal versus /loop versus a Stop hook
All three keep a session moving without you typing. They differ in what triggers the next turn and what ends it.
| Next turn begins | Ends when | |
|---|---|---|
/goal | As soon as the previous turn ends (plus, interactively, idle check-ins and automatic retries) | The evaluator says met or impossible, a turn fails on an error you must fix, or you run /goal clear |
/loop | A time interval passes | You stop it, or Claude decides it is finished |
| Stop hook | The previous turn ends | Your own script or prompt decides |
/goal is essentially a Stop hook you set by typing, scoped to the current session. A Stop hook in settings applies to every session in its scope and can be a deterministic script.
Auto mode is a different axis. It approves tool calls inside a turn but never starts a new turn; Claude stops when it thinks it is done. /goal adds an independent judge after each turn, so "done" is decided by a fresh model rather than the one doing the work. Used together, auto mode removes the per-tool prompts and /goal removes the per-turn ones. See permission modes and auto mode configuration.
For work that should run without any open session (nightly checks, morning triage), look at routines and desktop scheduled tasks.
Using the command
There is one goal per session, and /goal does everything depending on its argument.
Setting a goal
/goal every file under src/legacy/ imports from @acme/http instead of axios, `pnpm build` exits 0, and no test file is modified
Setting a goal immediately starts a turn using the condition as the instruction; you do not need a separate prompt. A new goal replaces any existing one. While it is active, a ◎ /goal active indicator shows the elapsed time.
/goal does not touch your permission mode. In manual mode Claude still asks before tool calls your rules do not already allow (like pnpm build above), so for an unattended run switch to auto mode first.
Each evaluator verdict appears in the transcript; press Ctrl+O for the reasoning. The status view also shows the latest reason, which tells you what Claude is aiming at next.
Writing a condition that works
The evaluator only reads the conversation. It does not run commands or open files itself. So phrase the condition as something Claude's own visible output can prove. "Tests pass" works because Claude runs them and the result lands in the transcript.
Good conditions usually include:
- A single measurable end state: an exit code, a test summary, a count, an empty list.
- How to prove it: "
cargo testexits 0", "git status --porcelainprints nothing". - Guard rails: things that must not change on the way, such as "no public API signatures change".
You can write up to 4,000 characters. To cap the effort, add a limit to the condition itself, for example ... or stop after 25 turns. Claude reports progress against that clause and the evaluator judges it like everything else.
Tip: I always include the proving command in the condition. Without it, Claude sometimes claims success in prose and the evaluator has nothing concrete to check.
Checking status
Run /goal with no argument. For an active goal you see the condition, running time, number of turns evaluated, token spend so far and the evaluator's latest reason (the last two appear after the first evaluation). If nothing is active but a goal was achieved earlier, you see that goal with its duration, turns and spend.
Clearing
/goal clear
Claude Code prints Goal cleared: and the condition, or No goal set. stop, off, reset, none and cancel are accepted in place of clear. Running /clear also drops the goal.
Resuming
An active goal comes back when you resume the session by any route: --continue, --resume with an ID, name or transcript path, or the session picker (before v2.1.239 the claude --resume picker was the exception). The condition carries over but the turn count, timer and token baseline reset. Achieved or cleared goals are not restored. See sessions.
Headless use
/goal works in non-interactive mode, the desktop app and Remote Control. With -p the whole loop runs in one invocation:
claude -p "/goal docs/api.md documents every exported function in src/sdk/index.ts" \
--output-format stream-json --verbose
With default text output nothing is printed until the end, which can look like a hang on a long goal; stream-json with --verbose shows each message as it happens. Ctrl+C stops it early.
How the evaluator decides
Under the hood /goal is a session-scoped prompt-based Stop hook. After each turn, Claude Code sends the condition plus the conversation to your configured small fast model, which returns a verdict and a short reason:
- Not yet met: Claude carries on and uses the reason as guidance.
- Met: the goal clears and an achieved entry is written to the transcript.
- Impossible: the goal clears and a failed entry with the reason is written. No action needed from you.
If Claude keeps replying to the evaluator without doing anything (no tool calls for several turns running), Claude Code breaks the loop, warns you and returns control with the goal still set. Evaluation resumes after your next prompt. This is the Stop hook block cap described in the hooks guide.
When a turn fails
Errors you must fix clear the goal. Claude Code prints a warning beginning Goal cleared after an unrecoverable error and ending Run /goal again to continue. These are:
- Authentication failure when Claude Code manages its own credentials. (When a host such as the desktop app or a cloud session manages them, the goal stays because the host restores access.)
- Credit balance exhausted.
- A context overflow that auto-compaction could not resolve.
- The model is unavailable.
Other errors leave the goal set. Interactively, on v2.1.269 or later, Claude Code also says what happened and either:
- Retries after transient failures such as an overloaded server or dropped connection, with a
Goal still activenotice showing the wait. After three automatic retries it pauses instead. - Pauses when retrying would just repeat the failure: an API rate limit, a claude.ai usage limit (see errors), or a hook ending the turn. The notice starts
Goal paused. If the session is set to continue when a usage limit resets, work on the goal resumes then.
Sending any message starts the next turn straight away.
Background work and check-ins
If a subagent or background shell command is still running when a turn ends, that turn is not evaluated. Evaluation happens at the end of the next turn that finishes with nothing running in the background, and when background work completes its result is delivered to Claude as a new turn automatically.
If background work keeps the goal waiting for 30 minutes, a check-in is due: Claude Code lists running tasks and asks Claude to read their output, keep waiting if they are progressing, and fix or stop anything stuck. Later check-ins back off, doubling each time up to four times the first interval, so with defaults: 30 minutes, then 1 hour, then every 2 hours.
Delivery:
- At the end of a turn that finishes with work still running. This is the only route in non-interactive sessions.
- While idle, interactively, Claude Code starts a turn itself. If the background work stopped without reporting, it asks Claude to continue toward the goal. At most three idle check-ins happen between your prompts; the third says idle check-ins are paused until you write again. (Idle check-ins need v2.1.236+, were uncapped before v2.1.246, and before v2.1.239 only idle check-ins backed off.)
Check-ins need v2.1.234 or later. CLAUDE_CODE_GOAL_CHECKIN_MINUTES replaces the 30-minute starting interval and scales the later ones; 0 turns off both check-ins and automatic retries. See environment variables.
Evaluator model and cost
The evaluator uses the small fast model for your provider. Evaluation tokens are billed on that model and are usually negligible next to the main turns. It never calls tools, so it can only judge what is already in the conversation.
To change it, set ANTHROPIC_DEFAULT_HAIKU_MODEL.
Warning:
ANTHROPIC_DEFAULT_HAIKU_MODELis not specific to/goal. It also changes what thehaikualias resolves to and which model runs background work such as conversation summarisation. See model configuration and costs.
When /goal is unavailable
Because the evaluator is part of the hooks system, /goal follows the same workspace-trust rule as hooks in settings files. It is also unavailable when disableAllHooks resolves to true after settings precedence, or when allowManagedHooksOnly is set in managed settings. In each case the command says why rather than silently doing nothing.