Channel plugins (iMessage) start one instance per session, causing echo loops and runaway API spend
Summary
Channel plugins designed as "one listener only" (e.g. the official iMessage plugin) are started once per Claude Code session via enabledPlugins. Opening multiple sessions simultaneously spawns multiple plugin instances that all watch the same data source, creating echo loops that generate massive unexpected API costs.
What happened
Opening 2–3 Claude Code sessions in the morning (normal workflow — different terminal windows / projects) started 3 simultaneous iMessage plugin instances. Each instance watched the same chat.db. Any message or Claude response was seen by all three listeners simultaneously, each attempting to handle it. The cascade generated:
- 34.5 million cache-write tokens
- 51.8 million cache-read tokens
- ~$182 in API-equivalent cost
- Rate limit hit after just 2–3 conversation turns
This was invisible from the user's perspective — it looked like normal sessions.
Root cause
enabledPlugins starts the plugin process once per Claude Code session. Channel plugins like iMessage are designed to be singletons (the iMessage plugin README and system prompt both warn "one listener only"), but the plugin framework provides no architectural enforcement of this constraint. The warning exists; the guardrail does not.
Expected behavior
Channel plugins should either:
- Run as a single system-level daemon independent of individual Claude Code sessions (preferred), or
- Have the framework enforce singleton behavior — detect an existing instance and refuse to start a second one, rather than silently starting and causing loops
Workaround applied
- Disabled the iMessage plugin in
enabledPluginsuntil needed - Added a PID lock file to the iMessage
server.tsso a second instance detects a live first instance and exits immediately - Added an
flock-based singleton lock tocompile-session.py(Stop hook) which also spawnsclaude -pand was stacking on simultaneous session closes
Why this matters
The failure mode is silent and financially severe. A user doing nothing wrong (opening multiple terminal windows) can burn their entire daily rate-limit allowance in minutes with no warning. The "one listener only" note buried in a system prompt is not an acceptable substitute for architectural enforcement when the failure mode is runaway spend.
Environment
- Claude Code CLI
- macOS
- iMessage plugin:
imessage@claude-plugins-officialv0.1.0 - Plan: Max ($200/month)
This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗