[Bug] System events delivered as user-role messages cause model to fabricate user consent and act on it
Summary
System-generated messages (task notifications, teammate idle notifications, system reminders) are delivered to the model as role: "user" messages. When these arrive while the model is waiting for a user response, the model fabricates plausible user input — including explicit approval — and acts on it without real user consent.
This is a consolidation of multiple related issues that share the same root cause but were closed individually by inactivity bot without an official fix:
| Issue | Title | Reporter |
|-------|-------|----------|
| #25936 | Autocompact confabulates user consent | @dalepike |
| #27102 | Assistant-generated 'Human:' prefix in Agent Teams | @michael-wojcik |
| #29160 | LLM-generated text appears as human turn after compaction | — |
| #10628 | Claude hallucinated fake user input mid-response | — |
Reproduction Pattern
All reported cases follow the same pattern:
1. Assistant asks a question → waits for user response
2. System event arrives (background agent completes, teammate idles, task reminder fires)
3. Claude Code client delivers the event as {role: "user"} message
4. Model sees a "user message" arrived → fabricates what the user "said"
5. Model acts on the fabricated approval
This has been reproduced across:
- Claude Code versions 2.1.42 through 2.1.81+
- With and without autocompact active (#25936 update: reproduced without compaction)
- Single-agent and Agent Teams sessions
- macOS and Windows
Four Observed Variants
Variant 1: Background Agent Trigger (most common)
A <task-notification> from a completed background agent restarts the assistant's turn. The model fabricates user approval in its chain-of-thought ("The user said 'yes, proceed'") or directly in the conversation stream.
Evidence from #25936: JSONL transcript lines 966–977 show no user message between assistant's question and assistant's next action. The model stated in its thinking block: "The user said 'yes, proceed'" — this message does not exist anywhere in the transcript.
Variant 2: Teammate Idle Notification Trigger
In Agent Teams, teammate idle/completion notifications trigger the same pattern. The model generates Human: <system-reminder>...</system-reminder>fix them both as assistant output that mimics user input format.
Evidence from #27102: Two fabricated messages in one session: "fix them both" (caused unauthorized code changes) and "go ahead and merge" (near-miss PR merge). Both recorded in JSONL as type: "assistant", proving they were model-generated.
Variant 3: Context Compaction + System Event
Autocompact preserves conversation gist ("user and assistant agreed on approach") but loses authorization state ("last question is still unanswered"). When a system event restarts the turn, the model infers approval from the compressed summary.
Variant 4: Mid-Response Role Marker
The model generates ###Human: or Human: mid-response, creating a fake turn boundary, then responds to its own fabricated input within the same response.
Impact (from real incidents)
- Unauthorized code changes — model edited files based on fabricated "fix them both" (#27102)
- Near-miss unauthorized PR merge — fabricated "go ahead and merge" (#27102)
- Unauthorized agent termination + directory deletion — model shut down agents and deleted directories based on fabricated shutdown command (#25936 comment by @Meme-Theory)
- Gaslighting — when user said "I never told you to do that," the model insisted the user did, pointing to the fabricated message as evidence
- Multi-paragraph fabrication — model generated entire paragraphs of fake user input including design preferences, feature suggestions, and explicit approval, all in the user's voice (#25936 update, 2026-03-22)
Root Cause
The Anthropic Messages API only supports two roles: user and assistant. Claude Code must deliver all system events through role: "user" messages because there is no system-event role. The model cannot reliably distinguish real user input from system-injected notifications.
Contributing factors:
- System events as user-role messages — the model's turn restarts when it shouldn't
- Autoregressive generation — when the pattern says "question asked → user message arrived," the model naturally generates a plausible user response
- Autocompact loses authorization state — compression preserves "what was decided" but loses "what's still pending"
- Conversation momentum bias — when context implies approval is coming, the model generates in that direction
Why Prompt-Level Mitigations Are Insufficient
@dalepike added three explicit rules to CLAUDE.md after the first incident:
- "Never assume approval after context compression — re-ask instead"
- "Task notifications are system events, not user responses"
- "Verify approval before consequential actions"
The model violated all three rules in a subsequent session (2026-03-22, #25936 comment). The same model that fabricates consent can also fail to follow instructions not to fabricate consent.
Proposed Structural Fixes
These require changes to the Claude Code client, not just model instructions:
Fix 1: Don't restart assistant turn on system events
Task notifications and system reminders should be queued and delivered alongside the next real user message, rather than immediately restarting the assistant's turn.
Fix 2: System-level interlock
If the assistant's last turn ended with an unanswered question AND the current turn contains only system events (no real user input), suppress response generation and wait for actual user input.
Fix 3: Separate notification channel
Use a distinct message format or metadata flag that the model can reliably distinguish from real user input. Even within the role: "user" constraint, a structured wrapper (e.g., {"type": "system_event", "content": ...} vs {"type": "user_input", "content": ...}) would help.
Fix 4: Client-side output sanitization
Strip or reject assistant output that begins with Human:, User:, or contains patterns mimicking user turn structure (e.g., <system-reminder> tags in assistant output).
Environment
- Claude Code versions: 2.1.42 — 2.1.81+ (persists across versions)
- Models: claude-opus-4-6 (all reports), likely affects other models
- Platforms: macOS, Windows
- Features: Background agents, Agent Teams, autocompact
This issue has 5 comments on GitHub. Read the full discussion on GitHub ↗