# Goals

A Goal keeps Qwen Code working across turns until a stated condition is met. Set one with `/goal <objective>`, and the session keeps going on its own. When the model proposes that the objective is complete or blocked, an independent verifier judges that proposal from the most recent part of the Goal's transcript. The session stops when the verifier accepts, or when the Goal is paused, cleared, or stopped by a limit.

## Commands

| Command                  | Behavior                                                      |
| ------------------------ | ------------------------------------------------------------- |
| `/goal`                  | Show the current Goal and its status.                         |
| `/goal <objective>`      | Create a Goal, or replace the active one.                     |
| `/goal set <objective>`  | Same as above, explicit form.                                 |
| `/goal edit <objective>` | Revise the active Goal's wording without starting over.       |
| `/goal pause` / `resume` | Stop or continue the loop without losing the Goal.            |
| `/goal clear`            | Remove the Goal.                                              |
| `/goal-draft <intent>`   | Have the objective written for you before you set it (below). |

Creating, editing, or resuming a Goal requires a trusted workspace (`/trust`). A session recorded before Goal state was journaled (Qwen Code releases before 2026-07-29) resumes with no Goal: the `/goal` cards in its history are shown as history, `/goal` reports that no Goal is set, and `/goal set` starts it again. In the Web Shell and other daemon clients, a trailing card after the replayed history says the old Goal is not being driven. Headless usage is covered in [Headless Mode](./headless.md#run-a-persistent-goal).

Once a Goal has billed a turn, the footer pill and every status card show what it has spent against the window it is allowed, as `1.2k/30.0m`. The figure counts the model calls in the Goal's own turns, its direct foreground subagents, and its verifier checks. Nested and background subagents, unrelated side queries, cron turns, and notification turns are excluded. A failed check that returns no usable result cannot be counted. Restoring already recorded usage does not count it again. The window is set by [`model.goalTokenBudget`](../configuration/settings.md); resuming a Goal that has spent its window grants another one on top of what it has already spent, so the figure reads `30.0m/60.0m` rather than starting over. A Goal with no budget shows only what it has spent. A Goal that has not billed a turn yet shows no figures at all.

When turn or active-time budgets are configured, status cards also show the corresponding usage against its budget, for example `3/20 turns` and `12m 3s/30m`. Headless text spells these out as `3 of 20 turns` and `12m 3s of 30m active`. Zero usage remains hidden, and paused or stopped Goals retain these figures.

Two more windows are available and off by default: [`model.goalMaxTurns`](../configuration/settings.md) caps how many turns a Goal may finish, including user-driven Goal turns, and [`model.goalMaxActiveMinutes`](../configuration/settings.md) caps wall time while it remains active in a running process, including waits and idle time between turns. Time while the Goal is paused, blocked or stopped does not count against the second one, nor does downtime across a restart; a process that is merely suspended is still charged. Whichever window runs out first, the Goal gets the same single wind-down turn to hand off and then stops until you resume it, and resuming authorizes another window on top of what has already been used. Only the window that ran out moves; the others stay where they were, and the `-1` opt-out likewise only takes a ceiling off a Goal that has already spent it. The time window is read between turns rather than enforced by a timer, so a Goal can run well past it before it stops: a turn already running is never interrupted, and a window that runs out while no turn is running is not noticed until the next turn ends. Active time is counted between recorded transitions, so time in a turn a restart interrupted is not charged. Changes to either setting take effect after restart. Both windows arm only on a Goal created after the change, so bounding a Goal already on the record means replacing it with `/goal set` -- a new Goal at revision 1, with its turn, token and active-time meters reset and its evidence window starting at the replacement, so evidence the old Goal recorded is no longer citable -- or clearing it and starting again. A resume or an edit never adds a ceiling that was not armed at creation.

Each turn the session takes on its own reports what the Goal has spent so far, how many turns are behind it, and — unless the Goal runs unbounded — the window it is allowed. Every such turn except the final wind-down hand-off also carries standing instructions to re-check the workspace rather than trust earlier turns' reports, to work toward the end state the objective asks for, to do something different when the previous turn changed nothing (from the second turn on, once there is a previous turn to judge), and to prove every requirement with a recent tool result before proposing that the Goal is done.

Goals no longer compress recorded evidence into checkpoint claims between turns: the verifier reads the transcript directly, so there is nothing for a checkpoint to feed, and the side-model check that used to run at the end of long turns, together with its stall limit, does not run. The `model.goalCheckpointTimeoutSeconds` setting is deprecated: the key is still accepted so that existing settings files load, and its value is ignored. The footer pill, the status cards, headless `/goal` output, the Web Shell status strip and Goals dialog, and `get_goal` no longer show a checkpoint line or stall count, including for a session recorded by a build that still ran checkpoints; that Goal's stop reason still says why it stopped.

## Interrupting a Goal

Cancelling a Goal turn pauses the Goal. Press Esc while the model is answering or while its tools are still running, and the turn stops, the Goal moves to `paused`, and the card and `/goal` both say why it stopped. Nothing continues until you run `/goal resume`.

Typing a message while a Goal is active does not pause it. Your message runs as the next Goal turn, so use it to steer the work; use `/goal pause` or `/goal clear` to stop it.

Every pause states its reason: that you interrupted it, that you ran `/goal pause`, that the session token limit blocked the next model request, that the turn failed, that the verifier could not judge a proposal (it timed out, its model call failed, or the objective left it no room for evidence), or that three turns in a row recorded nothing the verifier could judge and no proposal — Goal bookkeeping reads (`get_goal`, `update_goal`) do not count as progress. A Goal stopped by a limit keeps the reason for that limit instead.

## How a Goal is judged

The verifier never runs commands or reads files on its own. It only sees what is already in the transcript: the records of this Goal, read from the most recent one backwards until the request is full (256 000 bytes, with any single record cut in the middle past 8 000). A short closing turn leaves room for the turns before it; a long one fills the request by itself, and the verifier is told how many older records were left out and rejects a proposal whose proof may sit among them:

- Visible assistant output, tool results, and your own messages count as evidence. The objective text and the model's hidden reasoning do not. A check that ran long before completion is proposed may have dropped out of view and has to run again.
- Printed text proves only that text was printed. A claim that tests pass, a file changed, or a remote is updated needs the corresponding tool result in the transcript.
- A claim that you confirmed, chose, or approved something needs a real message from you; the verifier rejects proposals that assume it.
- When evidence is missing the verdict is "not yet", not "done". A condition nobody can evidence keeps the loop running until a limit stops it.

So the objective has to make the agent produce evidence when it proposes completion: run the named check and show the decisive output.

## Writing a good objective

Put these into the objective, in this order:

| Part         | What to write                                                                                                                                                                             |
| ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `Outcome:`   | One sentence: what is true when this is done.                                                                                                                                             |
| `Done when:` | Numbered, binary checks. At least one names a command and its expected exit code or output line, and asks for that line to be pasted.                                                     |
| `Must not:`  | Files not to touch, tests or thresholds not to weaken, irreversible actions (push, delete, publish) not to take.                                                                          |
| `Budget:`    | Advisory model instruction for when to give up, such as "stop as blocked after 20 turns". To enforce one, set `model.goalMaxTurns` or `model.goalMaxActiveMinutes` in settings, not here. |
| `On block:`  | What to report when stuck, and which decision a human must make.                                                                                                                          |
| `Context:`   | Only facts the agent cannot find in the workspace: branch, environment, earlier decisions.                                                                                                |

Keep it to one objective. `/goal set` and `/goal edit` accept any length, but stay roughly under 1,200 characters: the objective is re-sent on every Goal turn. An objective the model proposes through `propose_goal` is capped at 1,500 characters. Both commands collapse newlines to spaces, so number the items rather than relying on line breaks.

`Budget` is an instruction to the model about when to stop and report a blocker; the model may or may not honour it. To make the runtime itself stop at a turn count or a duration, set [`model.goalMaxTurns`](../configuration/settings.md) or [`model.goalMaxActiveMinutes`](../configuration/settings.md). Writing either into the objective does not configure those, and does not change the Goal's token budget.

| Weak                       | Why it fails                                                | Stronger                                                                                                                                                                                                                                                                                                         |
| -------------------------- | ----------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| make checkout faster       | No threshold, no check.                                     | `Outcome: checkout p95 is below 250 ms. Done when: 1) npm run bench:checkout exits 0 and prints p95 < 250 (paste the line); 2) npm test exits 0. Must not: change the benchmark or skip tests. Budget: as model guidance, stop as blocked after 20 turns. On block: report the measured p95 and what blocks it.` |
| clean up the auth module   | "Clean" has no evidence.                                    | Ask what would be observable: zero lint warnings in `src/auth`, a coverage threshold, a file count.                                                                                                                                                                                                              |
| ship the release           | Irreversible, and needs a human decision.                   | Narrow to a checkable pre-release state (tag exists, `npm run release:dry-run` exits 0) and put "do not publish" in `Must not`.                                                                                                                                                                                  |
| after I confirm the design | The verifier cannot see a confirmation that never happened. | Move it to `On block:` as the decision a human must make.                                                                                                                                                                                                                                                        |

## Let `/goal-draft` write it

`/goal-draft <what you want done>` is a bundled skill that does the above for you. It reads only enough of the workspace to establish the scope and real verification commands, without running tests, building, installing dependencies, or starting services. It asks at most one round of questions when essential choices are unclear, then writes a compact objective, usually with 3–5 completion checks (fewer when enough). Explicit requirements are preserved; it does not add checks just to reach a count.

For an audit, completion means covering the agreed scenarios and reporting evidence, including reproduction steps for confirmed defects. Finding no defects is a valid result. The draft should not invent a minimum number of scenarios, evidence files, exploration rounds, or defects.

If a success criterion, command, input path, or essential decision cannot be established, the skill returns a draft marked "Needs clarification" with `<TODO: …>` items. It does not offer that draft for approval or print a runnable `/goal set` or `/goal edit` command. Nonessential defaults are marked `[ASSUMPTION]`; they do not stand in for missing success criteria.

Once the objective is ready, an interactive terminal or Web Shell session can show the `propose_goal` approval dialog described below. Clients without Goal proposal support, headless runs, sessions with the tool disabled, and sessions with an active Goal receive a command to run manually instead. The hand-off says that the draft has not been applied. The skill never starts the work itself, and nothing is set without your approval.

Pass an existing objective to tighten it: `/goal-draft all tests pass and the lint is clean`. For an active Goal, an explicit request to tighten it produces `/goal edit`; a replacement uses `/goal set`. If the intended operation is unclear, the skill includes that choice in its single round of questions.

### Approve a Goal the model proposes

In an interactive terminal or a Web Shell turn with an attached client, the model has a `propose_goal` tool. When `/goal-draft` finishes, or when you ask for an outcome that spans several turns, it can propose the objective instead of printing a `/goal set …` line for you to copy. The proposal appears as an approval dialog showing the full objective. Approving it sets the Goal exactly as `/goal set` would, the moment the current turn ends (the model acknowledges and stops; the first Goal turn then starts on its own), and declining sets nothing — the model sees only that the tool call was not allowed, and its instructions tell it not to ask why and not to propose the same objective again. The approval is bound to the turn that asked for it: if that turn is cancelled or otherwise never reaches its end, the approval is dropped rather than applied under a later message or an automated turn. No permission rule or approval mode (including YOLO) skips this dialog, and the tool refuses while another Goal is active, in plan mode, and in untrusted folders; subagents are never offered it. Web Shell uses its existing Allow/Reject permission panel. A stopped Goal can be replaced only if it still matches the version shown for approval; changing it invalidates the proposal. Headless runs, Web Shell channel deliveries and automatic turns, and ACP clients without the required approval and turn-lifecycle support retain the printed `/goal set` hand-off.

Turn it off with `goals.modelProposed: "disabled"` in your user settings. Because the setting decides whether the model may ask you to start an autonomous loop, it is honored only from user and system scope; a workspace `.qwen/settings.json` value is ignored with a warning.

The skill is instructed to be read-only, and only its non-mutating tools are auto-approved (`get_goal`, `read_file`, `glob`, `grep_search`). `ask_user_question` is deliberately not auto-approved, so its question dialog is shown before the skill drafts from your answers. Like other bundled skills, a project or personal skill named `goal-draft` overrides it, and `skills.disabled` can turn it off. See [Skills](./skills.md) for how bundled skills are discovered.

## Telemetry

Goal transitions are reported through two independent settings: [telemetry](../../developers/development/telemetry.md) enables OpenTelemetry events and metrics, while `privacy.usageStatisticsEnabled` controls usage statistics and is on by default. The OpenTelemetry event is named `qwen-code.goal_state`; usage statistics report the same transition data without the Goal id.

Reported transitions are set, replace, edit, pause, resume, clear, verifier rejection, completion, blocking, and usage limits. Events carry turn count, token spend, active time, and any configured budgets. A `clear` event identifies only the removed Goal and its revision, with no usage figures. A `replace` event describes the new Goal, not the removed Goal's final spend. User pauses and automatic no-progress pauses share the same `pause` cause; events include the raw no-progress streak when available. Only completion, blocking, and usage limits contribute to the outcome histograms. A resumed session does not re-report the transition its Goal was recovered from. A new stop committed during recovery is reported normally.

The Goal event itself contains no objective text or stop reasons, only the objective's length in code points. Other telemetry can contain that text: tool-call telemetry records the arguments of `propose_goal` and `update_goal`, including the objective or model-authored reason, even when `telemetry.logPrompts` is off.
