[BUG] `/goal clear` typed while the agent is working is treated as chat text and never executed

Status Open
Reported on v2.1.226
Maintainer reply None cached
Activity 0 comments · opened Aug 13, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code — the sessions analysed here ran on 2.1.226 and 2.1.228
Disclosure. This report was drafted by Claude Code (Opus 5) analysing its own session, at the user's request. The agent described below is the same one that wrote the first draft. A second Claude Code (Opus 5) agent, in a later session, re-read both JSONL transcripts independently, corrected several claims the first draft had got wrong, and co-wrote this version. Line numbers, timestamps, version data and command records are read directly from the transcripts rather than recalled — but the account of intent is necessarily self-reported, and should be weighted accordingly.

Related issues

This is one of three bugs found in the same session; each is filed separately per the issue template.

This bug and Bug 3 were initially thought to share a cause. They do not: in Session B below, /goal clear routed correctly and still answered No goal set. Bug 3 reproduces with this Bug absent.

Transcripts referenced

  • Session Ab828a4ef-3c8d-400a-ac9f-635ebed26a27.jsonl, the session this issue describes.
  • Session B3aa656a8-5291-4410-bdfc-f3a67dd7c661.jsonl, a later controlled reproduction.

All line numbers are 1-indexed into the raw JSONL.

What's Wrong?

Behaviour

Typing a slash command while the assistant is working does not execute it. The CLI enqueues it as an ordinary prompt and hands the raw text to the model; it never reaches the command handler. The UI shows Thinking… immediately, as though the command were accepted, and the user is given no indication that nothing happened — especially since "showThinkingSummaries": false is the default now.

The CLI records its own misclassification. Session A, L1096:

{
  "type": "queued_command",
  "prompt": [{ "type": "text", "text": "/goal clear" }],
  "source_uuid": "ce1d9b48-0e81-494a-aa0a-12bbf8f71a5a",
  "commandMode": "prompt",
  "origin": { "kind": "human" },
  "timestamp": "2026-08-11T15:08:59.994Z"
}

commandMode is "prompt". The field is populated correctly for other queue traffic in the same session — task-notifications carry "commandMode": "task-notification" (L129, L895, L975, L1123, L1132). A leading /goal clear was simply not detected as a command.

The queue log corroborates it: L1090 is an enqueue at 15:09:00.003, and L1095 is a remove at 15:09:40.703 — removed, never dequeued into a user turn.

Note for anyone grepping the transcript: queue-operation entries carry a content field only for task-notifications. Human-typed text is empty there and lives in the paired queued_command attachment. A naïve search of user messages finds nothing, which is what led the first draft to conclude there was no record.

The consequence is worse than a silent no-op: the agent falsely confirms success

| Line | Time (UTC) | Event |
| --------- | ------------------ | --------------------------------------------------------------------------------------------------------------- |
| L1096 | 08-11 15:08:59.994 | User types /goal clear while the agent is mid-turn → enqueued with commandMode: "prompt" |
| L1092 | 08-11 15:09:23 | Agent, not yet aware of it: _"Then it's yours to run — /goal clear. I won't run it myself; that's the rule."_ |
| L1093–94 | 08-11 15:09:36–40 | Agent runs a Bash call |
| L1095 | 08-11 15:09:40.703 | Queue entry removed; the raw text /goal clear surfaces to the model as an attachment |
| L1098 | 08-11 15:09:45 | Agent: "Goal cleared — thanks. That closes the stale condition for good." |

The agent read the literal string /goal clear as the user _reporting_ that they had cleared the goal, and confirmed it back. The goal was not cleared: the hook fired again at L1139 (15:13:55), L1192 (15:24:43) and L1219 (15:35:20), and the real /goal clear at L1234 (15:39:30) printed the full original condition (L1235).

So the user is not merely left without feedback — they receive a positive confirmation from the agent that the command worked. That is why the failure went unnoticed for half an hour, at exactly the moment the command was needed to escape the stuck Stop hook described in Bug 1.

The queue mechanism is fine — only command detection on the way in is broken

Session A L232 is the other human queued_command in the session, with the same commandMode: "prompt" and origin: {kind: "human"}:

_"since there is no package.json in the root anymore [...]"_

That one is genuinely prose, and it was delivered correctly. The queue path works. What is missing is command detection.

Boundary condition: "actively working", not merely "not idle"

Session B is a controlled reproduction in which the session was waiting — a pending ScheduleWakeup (L23–24) — rather than actively working. There, /goal clear routed correctly: real <command-name>/goal</command-name><command-args>clear</command-args> blocks at L31 and L36, each with a local_command stdout entry (L32, L37). Session B contains zero queued_command attachments.

The swallow therefore requires the agent to be actively working. A merely non-idle session — waiting on a scheduled wake-up or a background subagent — dispatches slash commands normally.

Only /goal clear was observed. Other slash commands were not tested and may also be affected.

What Should Happen?

Execute the command in the background and notify the agent after the current turn, or queue the command and run it after the current turn, or reject it visibly and tell the user to stop first. Silently reinterpreting it as chat is the one behaviour the user cannot detect — and, as shown above, it can produce an affirmative false confirmation.

Possible enhancement

Separately from fixing the misclassification, an active goal is currently invisible unless the user remembers to run /goal and the status happens to be accurate (see Bug 3. An indicator in the UI would reduce reliance on typed commands at exactly the moment they're least reliable: show a goal indicator in the UI next to the mode picker which indicates a running, finished, or prematurely stopped goal _(see Bug 1's "What Should Happen?" section)_ in a distinct color (e.g. blue), whenever a /goal Stop hook is armed. The UI could look like this: (🚀 Goal ..., 🚀 Goal ✅, 🚀 Goal 🛑). Clicking it would open a small popup to clear the goal, or to configure a max-turn / time limit for it directly from the UI.

This matters more given Bug 3: both commands that can _report_ goal state go through a read path that returns No goal set while the hook is still armed, and the one command that keeps working (/goal <condition>) cannot tell the user anything. An indicator reading hook state directly would have shown the armed goal throughout.

Steps to Reproduce

  1. /goal <a condition that will not be met>.
  2. Ask for something that takes a while, and let the agent start working.
  3. While it is actively working, type /goal clear. → UI shows Thinking…; goal not cleared; hook keeps firing. In the transcript the input appears as a queued_command with commandMode: "prompt" and no <command-name> block.
  4. Interrupt manually, wait for the idle prompt, type /goal clear again. → executes correctly, prints Goal cleared: ….
Claude Model

Opus

Is this a regression?

I don't know

Claude Code Version

2.1.226 (Session A). Session B, which establishes the "actively working" boundary, ran on 2.1.228.

Platform

Anthropic API

Operating System

Windows

Terminal/Shell

VS Code Extension

View original on GitHub ↗