Phantom skill invocation surfaces in post-compaction `<system-reminder>` and gets executed as a live task
Summary
After a context compaction in Claude Code (Opus 4.7), a <system-reminder> block listed a user-level skill under the "skills invoked EARLIER in this session" group, along with full skill content and an ARGUMENTS: section containing what looked like a live draft payload. The skill was never actually invoked in this session — the post-compaction summary, which lists every user message verbatim, contains no such request. The session was entirely about a different, unrelated task. The model treated the surfaced skill + args as actionable and executed it as live work (five subagent dispatches, six file writes) before the user pointed out there was no such task in the conversation history.
Expected
The "skills invoked EARLIER in this session" reminder should reflect skills that were actually invoked in the current session. The wrapper text on that block ("Do NOT re-execute these skills…") is intended to suppress re-firing of one-shot setup actions for skills that did run earlier in the session. It is not sufficient protection when the listed invocation never occurred at all and the model has no way to verify it against session history.
Actual
A skill not present in any user message in the current session appeared in the post-compaction reminder as if it had been invoked, with ARGUMENTS: and a draft payload that read as fresh input. The model interpreted this as an active task and executed the skill's pipeline.
Repro context
- Model:
claude-opus-4-7(Opus 4.7) - Surface: Claude Code CLI
- Trigger: long-running session that crossed the context-compaction threshold (post-compaction "This session is being continued from a previous conversation that ran out of context" banner present)
- Skill source: a user-level skill defined under
~/.claude/commands/(i.e.,userSettings:namespace) - The session in question contained only two real user messages, both about an unrelated topic. The phantom skill invocation surfaced only after compaction.
Hypotheses on root cause
- Independent storage: Skill-invocation tracking is keyed on something that survives compaction independently of the actual message stream, and a stale record leaked into the current session's "invoked earlier" list.
- Source mismatch: The compactor's session summary correctly omits the phantom invocation (because it didn't happen), but the reminder generator pulls from a different source that includes it.
- Cross-session attribution: A prior session's invocation of the same skill (with similar arguments) was incorrectly attributed to the current session — possibly because a fingerprint match on the user + skill + args attached the record to the wrong session ID.
Suggested fixes
- Make the "skills invoked earlier" reminder a derivative of the canonical message stream — the same source the summary is built from — not an independent store.
- Strip
ARGUMENTS:and any payload-shaped sections from the historical-context rendering of a skill block. The wrapper text says "context only," so the per-skill body should not include anything that looks like fresh input. - After compaction, cross-check the "invoked earlier" list against the summary's user-message log and drop entries that have no source message in the visible history.
Impact
Phantom work that burns API budget and wall-clock time. In this instance: five subagent dispatches, six file writes, ~5 minutes of wall-clock executing a task the user never requested. In a worse case the model could take a destructive or outward-facing action (commit, push, email, post) acting on phantom arguments that the user did not author and cannot see.
Mitigation suggestion for the model side
In the meantime, model instructions could be tightened to cross-check any reminder-surfaced "earlier invocation with ARGUMENTS" against the visible message history before acting — i.e., treat a skill invocation as live only if a corresponding user message can be located in the current session.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗