Goal workflows with /goal in Claude Code
The /goal command in Claude Code sets a completion condition and keeps the session working turn after turn until a separate small fast model (Haiku by default on the Claude API) judges the condition met or impossible, or an unrecoverable error clears it. It suits migrations, acceptance criteria, and other work with a checkable end state.
This page is for developers who run long Claude Code sessions and for tech leads who want those runs to end in evidence rather than in “looks done”. The situation it solves: you are two hours into a migration, and your whole job has become typing “keep going” every time a turn ends. The work is clear and the finish line is obvious, yet every step waits on you.
What you’ll walk away with from goal workflows
Section titled “What you’ll walk away with from goal workflows”- A three-part condition template (end state, proof command, constraints) that the evaluator can actually judge.
- Four copy-paste goals for migrations, acceptance criteria, size budgets, and issue triage.
- An unattended
claude -precipe with a hard spending cap and a tool allowlist. - A verification routine that proves the result without reading every changed line.
- A failure table that maps each way a goal stalls or lies to its fix.
When is /goal the right way to keep Claude Code working?
Section titled “When is /goal the right way to keep Claude Code working?”Use /goal when the end state is checkable and the path to it is unpredictable. Four mechanisms keep a session moving without you, and they differ in what starts the next turn and what stops the run.
| Mechanism | Next turn starts when | Run stops when | Reach for it when |
|---|---|---|---|
/goal | The previous turn ends (plus automatic retries and idle check-ins in interactive sessions) | The evaluator returns met or impossible, an error you must fix occurs, or you run /goal clear | The finish line is a test result, exit code, count, or empty queue |
/loop | A time interval elapses | You stop it, or Claude decides the work is done | You poll external state on a cadence, such as CI or a deploy |
| Stop hook in settings | The previous turn ends | Your script or prompt decides | The check must be deterministic or apply to every session in a scope |
| Auto mode | Never; it works inside one turn | Claude judges the turn done | You want fewer permission prompts, not more turns |
Auto mode and /goal are complementary. Auto mode removes per-tool prompts; /goal removes per-turn prompts, and it hands the “am I done?” decision to a fresh model instead of the one doing the work. A goal run is an agentic workflow: the model works through the task turn after turn until a separate check says it is done. If the job is bigger than one session, such as hundreds of files split across agents, use dynamic workflows instead. If it must run on a schedule with no open terminal, use routines. If you want the loop to outlive the session, with state on disk and a fresh context each iteration, compare /goal with the Ralph loop in autonomous loops.
Run your first goal
Section titled “Run your first goal”-
Choose the permission mode first. A goal does not change your permission mode. In Manual mode, Claude still stops to ask before every tool call your settings do not allow, so an unattended goal stalls on the first
npm test. On v2.1.283 and later (thelatestrelease channel), interactive terminal and VS Code sessions start in auto mode on every plan, unless a settings file setsdisableAutoModeor the session runs on a model auto mode does not support, such as Haiku. On thestablechannel (v2.1.274 on 26 September 2026), start the session explicitly if your plan, provider and model support auto mode (see the permissions page linked below); otherwise allow the goal’s commands with explicit allow rules:Terminal window # Terminalclaude --permission-mode autoKeep your explicit
denyrules; auto mode still honours them. See permissions, sandboxes, and approval modes for the full matrix. -
Lock the checks the goal depends on. A goal that says “tests pass” rewards an agent that edits the tests. Add deny rules for the test tree to
.claude/settings.jsonbefore you walk away. A leading/anchors the path at the project root:{"permissions": {"deny": ["Edit(/tests/**)", "Edit(**/*.test.ts)", "Edit(/vitest.config.ts)"]}}Deny rules cover Claude’s file tools, not shell commands that write files. Protecting the oracle adds the sandbox and hook layers that close that gap.
-
Set the goal. Run
/goalfollowed by the condition, up to 4,000 characters. Setting a goal starts a turn immediately with the condition as the directive, so you do not send a separate prompt. A◎ /goal activeindicator shows how long it has run. One goal is active per session; a new/goalreplaces the old one. -
Watch the verdicts, not the diff. The transcript shows each verdict the evaluator returns; press Ctrl+O to see the reason behind it. Run
/goalwith no argument to see the condition, elapsed time, evaluated turns, token spend, and the most recent reason. -
Verify and close. When the evaluator returns met, Claude Code clears the goal and records an achieved entry. That verdict is a claim, not proof. Run the checks in How do you prove a goal’s result without reading every line? before you merge. To stop early, run
/goal clear(aliases:stop,off,reset,none,cancel);/clearalso removes the goal.
Copy-paste goals that hold up over many turns
Section titled “Copy-paste goals that hold up over many turns”Each goal below names one end state, the command that proves it, the constraints that must survive, and a stop clause. Paste them at the Claude Code prompt and change the paths.
The triage goal needs a tool that reads and writes issues. Add the GitHub MCP server once per project, following the GitHub MCP setup guide:
# Terminal. Single quotes keep ${GITHUB_PAT} unexpanded in .mcp.json.claude mcp add -s project --transport http github https://api.githubcopilot.com/mcp/ \ -H 'Authorization: Bearer ${GITHUB_PAT}'Because this goal closes issues unattended, make GITHUB_PAT a fine-grained personal access token limited to Issues: read and write on this one repository.
How do you write a condition the evaluator can judge?
Section titled “How do you write a condition the evaluator can judge?”The evaluator reads the conversation only. It does not run commands or open files, so a condition is only as good as the evidence Claude prints. Build every condition from three parts, then add a stop clause.
| Part | Weak | Strong |
|---|---|---|
| End state | “the migration is done” | “npm run db:status reports no pending migrations” |
| Proof shown in the transcript | “tests pass” | “npm test exits 0 and its summary line shows 0 failed and 0 skipped” |
| Constraints | none | “do not edit package.json, lockfiles, or tests/” |
| Stop clause | none | “stop after 25 turns and list what remains” |
Three rules follow from the evaluator’s design:
- Name the proof command in the condition. If Claude edits files but never runs the check, the evaluator has nothing to read and returns not yet met, turn after turn.
- Translate taste into a measurement. “The code is more readable” cannot be judged from a transcript. “Every file in
src/utils/is under 200 lines” can. - Treat the stop clause as soft. “Stop after 25 turns” is judged by the evaluator from the conversation, not enforced by a counter. Your hard limits are
/goal clearin a session and--max-budget-usdin aclaude -prun.
How does Claude Code decide a goal is done?
Section titled “How does Claude Code decide a goal is done?”/goal is a session-scoped, prompt-based Stop hook. After each turn, Claude Code sends the condition and the conversation so far to the small fast model. On the Claude API that model is Haiku; on Bedrock, Google Cloud, or Foundry, the provider’s default applies. The evaluator returns one of three verdicts, each with a reason:
- Not yet met. Claude starts another turn and uses the reason as guidance.
- Met. Claude Code clears the goal and records an achieved entry.
- Impossible. Claude Code clears the goal and records a failed entry with the reason.
Four behaviours change how a long goal runs:
- Stall detection. If Claude keeps answering the evaluator without using tools for several turns in a row, Claude Code stops the loop, prints a warning, and returns control with the goal still set. Evaluation resumes after your next prompt.
- Errors you have to fix clear the goal. An authentication failure (when Claude Code manages its own credentials), an exhausted credit balance, a context overflow that auto-compaction could not clear, or an unavailable model prints
Goal cleared after an unrecoverable error. Fix the cause, then set the goal again. - Other errors retry or pause (v2.1.269+, interactive). Transient failures such as an overloaded server retry automatically, behind a
Goal still activenotice; after three automatic retries the goal pauses instead. Rate limits, usage limits and a hook that ended the turn printGoal paused. - Background work defers evaluation. While a subagent or background shell command runs, evaluation waits. After 30 minutes of waiting, a check-in asks Claude to read the running tasks’ output and fix or stop stuck ones. Later check-ins back off to 1 hour, then every 2 hours, and an interactive session starts at most three idle check-ins per goal between your prompts.
CLAUDE_CODE_GOAL_CHECKIN_MINUTESchanges the first interval;0turns off check-ins and automatic retries.
To evaluate on a different model, set ANTHROPIC_DEFAULT_HAIKU_MODEL. That variable also changes the haiku alias and background tasks such as conversation summarisation, so set it deliberately. Evaluation tokens bill on the small fast model; see the models hub for current prices.
How do you prove a goal’s result without reading every line?
Section titled “How do you prove a goal’s result without reading every line?”An achieved verdict means a small model read a transcript and believed it. Treat it as the agent’s claim and verify it with evidence that does not depend on the transcript.
-
Re-run the decisive check outside the session. Push the branch and let CI run the same tests, type check, and lint. A green CI run on a clean checkout is the proof; the transcript is not.
-
Confirm the constraints held. Run
git diff --stat main...HEAD -- tests/ package.json(adjust the paths to your constraints). Empty output means the goal did not reach what it promised not to touch. -
Review by risk, not by line. Run
/code-reviewon the branch, then read only the files the review flags and anything that touches authentication, payments, or data deletion. -
Attach the evidence to the pull request. Paste the final
/goalstatus (condition, turns, token spend) and the CI link into the description. The evidence bundle defines the full contract.
Sign-off stays with the developer who set the goal: they own the condition, so they own the judgement that it described the right outcome. A tech lead standardising goals across a team should review the condition templates, not every diff they produce.
Run a goal unattended with claude -p
Section titled “Run a goal unattended with claude -p”/goal works in non-interactive mode, in the desktop app, and through Remote Control. With -p, the loop runs to completion in one invocation. A claude -p session starts in Manual permission mode, so allow exactly the tools the condition needs and cap the spend:
# Terminal or a trusted CI job on your own branchclaude -p "/goal CHANGELOG.md has an entry for every PR merged since the v4.2.0 tag, \as listed by 'git log v4.2.0..HEAD --merges --oneline'. Do not edit any other file. \Stop after 15 turns." \ --allowedTools "Bash(git log *)" "Read" "Edit(/CHANGELOG.md)" \ --max-budget-usd 5 \ --output-format stream-json --verbose--max-budget-usdis the hard ceiling that the turn clause is not; it works only with--print.- With the default text output, nothing prints until the run ends, so a long goal looks stuck.
--output-format stream-json --verboseemits each message as it happens. - Ctrl+C stops the run before the goal resolves.
- In a non-interactive session, check-ins arrive only when a turn ends; there are no idle check-ins.
Never run a goal against an untrusted ref, such as a fork’s pull request, while secrets are in the environment: project hooks and MCP servers run with the job’s credentials. CI/CD integration shows the safe checkout pattern.
A goal still active when a session ends comes back on every resume route: --continue, --resume with a session ID, name, or transcript path, and the session picker. The condition carries over; the turn count, timer, and token baseline reset. Achieved or cleared goals do not return.
What does /goal require?
Section titled “What does /goal require?”/goal arrived in Claude Code v2.1.139. Automatic retries need v2.1.269 or later, and idle check-ins v2.1.236 or later. Because the evaluator is part of the hooks system, /goal follows the same workspace trust rule as hooks in settings files. It is unavailable when disableAllHooks is true after settings precedence applies, or when allowManagedHooksOnly is set in managed settings. In each case the command says why instead of failing silently.
When /goal breaks in Claude Code
Section titled “When /goal breaks in Claude Code”| Symptom | Cause | Recovery |
|---|---|---|
| The goal never completes although the work looks done | Claude never printed the proof the condition names | Put the proof command in the condition: “npm test exits 0 and its summary line is shown” |
| The evaluator returns met after one green run | The condition accepts partial evidence | Require totals: “0 failed and 0 skipped across the whole suite” |
| Tests pass because tests changed | Nothing stopped the agent editing the oracle | Add deny rules for the test tree and a “do not edit tests/” constraint; check with git diff --stat |
| The goal is cleared as impossible | The condition contradicts a constraint, or the proof command cannot succeed in this environment | Read the recorded reason, run the proof command yourself, relax the conflicting constraint, and set the goal again |
Goal cleared after an unrecoverable error | Authentication, credit balance, context overflow, or model availability | Fix the named cause, then run /goal with the same condition |
Goal paused | A rate limit, a usage limit, a hook that ended the turn, or three failed automatic retries | Wait for the limit, or send a message to resume immediately |
| The goal sits idle while a subagent or background command runs | Evaluation is deferred until the background work finishes | Check /tasks, stop the stuck job, or lower CLAUDE_CODE_GOAL_CHECKIN_MINUTES; after three idle check-ins, Claude Code pauses them until your next prompt |
| The loop stops with a warning and the goal still set | Stall detection: several turns with no tool use | Send a prompt that names the next concrete step, or rewrite the condition |
| Token spend keeps climbing | No stop clause, or an unreachable end state | Run /goal to read the spend, then /goal clear; in -p runs, always pass --max-budget-usd |
/goal refuses to run | Untrusted workspace, disableAllHooks, or allowManagedHooksOnly | Accept the trust dialog, or ask whoever owns managed settings to allow hooks |