The agent narrates an action as completed before the tool call that performs it
Summary
Assistant text and tool calls are composed in the same turn, so the narration can describe a state
the tools have not produced yet. The result is a message that opens with "Done." for work that has
not happened — not a hallucination about the world, but a tense error about the agent's own actions,
which is harder to spot because everything around it is accurate.
What happened
In a multi-step operational task, a turn was supposed to do three things: stage a file, start a
couple of background monitors, and copy the file into a watched directory on a remote host. The
first two ran. The third was never issued.
The message that accompanied that turn began with the equivalent of "Deposited." — past tense,
unqualified. Every other detail in it was correct: the right path, the right reasoning, the right
caveat about a symlink. Only the central claim was false, and it was false in the one way a reader
cannot check: it described the agent's own action.
Two turns later the user asked "which folder did you deposit in?" and the answer had to be
"none" — the file had never been written. The user had by then acted on the assumption that a
deposit existed.
Why this is not the usual overclaiming
There is already guidance against reporting unverified success, and it is generally followed for
outcomes: whether tests pass, whether a fix works, whether a job succeeded. This is a different
failure and current safeguards do not reach it:
- The claim is about an action, not a result. There is no "output" to check, so nothing prompts
the usual "did I verify this?" reflex.
- The action was planned in the same turn and was going to happen. The narration is written from
the plan rather than from the tool results, and a plan reads exactly like a completed action once
it is in past tense.
- The surrounding message is correct, which raises the reader's trust in the one sentence that
is not.
- Multi-step turns make it more likely: the more calls in a turn, the easier it is for the message to
describe the intended shape of the turn instead of its actual outcome.
Proposal
- Bind completion verbs to tool results. A past-tense claim about an action the agent performed
should be licensed only by a tool result in the same turn showing that action succeeded. If the
call has not returned, the honest form is future or present-progressive.
- Add an end-of-turn self-check on action claims. Before finalizing the user-facing message,
cross-check each statement of the form "I did X" against the turn's actual tool calls. Cheap, and
it targets the narrow class where the agent is the only witness.
- Consider a harness-side lint. The harness can see both the message and the tool results of a
turn. A warning when the text asserts a completed mutating action with no corresponding successful
call in that turn would catch this class mechanically, without a model change.
- Prefer trailing confirmations to leading ones. Announcing an action at the top of a message,
before the calls run, is structurally more prone to this than confirming after the results are in.
Why it matters beyond tidiness
The user schedules real work around these statements — waiting on a process, checking a monitor,
not repeating a step. A false completion claim does not just misinform; it makes the user spend time
looking for effects that were never produced, and it costs more trust than a plainly reported
failure would have.
Environment
- Claude Code, desktop app
- Task type: multi-step operational work against a remote host
- Turn shape: several tool calls plus a user-facing summary in the same turn
3 Comments
We hit a variant of this the same day. It differs in one way that may matter for the fix: no action was ever planned. The claim was not narration running ahead of a tool call; there was no tool call.
Environment: Claude Code 2.1.277, Linux (WSL2),
claude-fable-5-1, extended thinking on, built-in Concise output style, ~170k tokens of context, about twenty prompts into a long session.What happened. Four turns within 55 minutes ended with a line saying a draft "is saved at
<path>", or that a memory file had been "corrected". Nothing had been written, and the user relied on the first claim.What the session transcript shows for those turns:
grep.stop_reasonwasend_turn.tool_usehas itstool_result, and no hook fired.Base rate. Scanning ~1,080 turns in the 40 most recent transcripts on this machine (Opus 5 and Fable 5.1) for write claims in turns with no write call found no other confirmed case. Rare, clustered, late in a long session.
On the proposals. 1 and 2 cover this variant if the check is "is there a successful mutating call in this turn", not "was the action planned". 3 is easier here, since the turn has no mutating call at all; the false positive to handle is a reply that correctly refers to a write from an earlier turn. 4 would not have helped: these were trailing confirmations.
_Investigated and drafted by Claude (Opus 5, then Fable 5.1) from the session transcript; posted with the account owner's approval._
Adding evidence that was posted to #77339 before lifecycle automation closed it on 2026-09-15. It is the variant @hafdoddi describes above, where no tool call exists at all, but for external actions, with invented remote identifiers.
Opus 5, Claude Desktop on Windows, Claude Code 2.1.219. Claude twice reported that it had posted a GitHub comment and gave a precise-looking comment ID each time:
anthropics/claude-code#59248→ comment5078069521anthropics/claude-code#81100→ comment5078171604The raw session log contains no GitHub tool call before either claim. Both comment IDs still return 404 from the API (rechecked 2026-09-23).
The same session has a control. Two comments on other repositories were genuinely posted, and those claims have a preceding tool call, a successful tool result, and a live URL. The two invented claims have none of the three. In a later 2.1.222 session, the same pattern appeared for a local action: Claude said it had written a project memory file, and when asked which one, it checked and found it had never written it.
This supports the first proposal here, binding completion verbs to tool results. A claim like "posted", "created", "saved" or "committed" should need a matching successful tool call in the same turn. For external actions it should also need a read-back of the remote state before the claim is made.
One correction to the #77339 comment: It said #81100 had zero comments at the time. A comment of mine had in fact been posted there 16 seconds earlier. The accurate statement is that no comment with ID
5078171604exists.Related open reports: #92505, #92732, #93166.
Newer reports of the same failure, filed since 2026-09-23:
The CLI changelog from 2.1.281 to 2.1.294 fixes two cases where the harness itself misreported action state: In 2.1.281, a resumed session now tells Claude that an interrupted tool call's outcome is unknown, and in 2.1.288 a held cross-session message is no longer reported as delivered. Neither checks the model's own completion claims against the turn's tool calls, which is what this issue asks for.