Model occasionally emits or fabricates `Human:` turns when woken by Monitor task-notifications with no fresh user input
Summary
In long-running Claude Code sessions that use the Monitor tool (background process watching), task-notification wake-ups occasionally cause the assistant turn to either (a) echo the <task-notification> block back as text prefixed with Human:, or (b) confabulate an entirely fake user message that the user never wrote.
Both manifestations are caused by the same wake-up condition: the model is invoked with no fresh user prompt — only a <task-notification> event embedded in the conversation — and the response slot is filled by "continuing the transcript template" instead of producing a normal reply.
Environment
- Claude Code CLI on Linux (Linux Mint 22.3)
- Long-lived session (~24h, thousands of turns) using
mcp__remote-triggerMonitor tool to watch CI runs - Multiple notifications fired within minutes of each other while the user was AFK
Manifestation A: echoed notification framing (frequent, harmless)
Assistant turn text literally begins with:
Human: <task-notification>
<task-id>bh03td5se</task-id>
<summary>Monitor event: "PR #86 Phase A CI"</summary>
<event>Go security audit: pass</event>
...
</task-notification>
This renders in the TUI as a compact H: header followed by the task-id, which looks confusing and produces no useful output for that turn. Observed 18 times in a single session, all triggered by Monitor <task-notification> events.
Manifestation B: hallucinated fake user message (rare, concerning)
Once in the same session, after a Monitor notification fired with the message "stream ended," the assistant generated a turn whose text began Human: followed by a multi-sentence fabricated user message on an unrelated topic (a fictional anecdote about installer permissions and being locked out of a family member's account). The user had not typed or spoken any of that content, and nothing similar appeared anywhere earlier in the conversation.
This is concerning because:
- The fake turn looks like the user said something they didn't.
- A subsequent agent reading the transcript could treat it as a real instruction and act on it.
- It could leak plausible-sounding but invented "user context" into downstream tools, summaries, or memory.
In the observed case, when the user returned and resumed the conversation, the model correctly self-flagged the prior turn ("the content doesn't match anything we've been doing... I treated it as untrusted — didn't act on it, didn't change any state") — so the in-conversation resilience worked. But that's not guaranteed in every session, and the artifact still persists in the saved transcript.
Reproduction conditions
- Session uses the Monitor MCP tool with background streams
- Multiple
<task-notification>events fire while the user is not actively typing - Notification arrives without a fresh user prompt; model wakes and fills the assistant slot with transcript-template continuation rather than a reply
Suggested mitigations
- Harness side: strip or refuse to display assistant output beginning with
Human:/Assistant:chat-template markers, since these are never legitimate model responses. - Prompt side: the wake-up template for Monitor notifications could include a stronger instruction not to generate user-turn-shaped text, or could provide a more structured response slot (e.g., "Acknowledge the notification or take action; do not echo it").
- Persistence side: when an assistant turn looks like a regenerated user turn, mark it in the
.jsonltranscript so downstream replay/audit can detect it.
Evidence available
I have the raw .jsonl turns (timestamps, surrounding context, recovery message) for both manifestations and am happy to share via email if helpful — they contain project identifiers I'd rather not paste publicly.
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗