Subagent spawns inherit enabledPlugins with no per-spawn exclusion; each spawn's copy of a single-consumer channel plugin takes over the resource and the parent session's plugin is never respawned

Open 💬 0 comments Opened Jul 11, 2026 by greghughespdx

Summary

For plugins that hold a single-consumer external resource (Telegram's one-getUpdates-
poller-per-token is the canonical case), the current settings-inheritance model makes
subagent use and channel use mutually destructive: every Agent-tool subagent or teammate
spawned in the project loads the plugin, the plugin's own startup logic takes over the
single resource (SIGTERM to the incumbent poller, by design - see plugin server.ts
stale-PID handling), and when the subagent exits, its poller exits with it. The parent
session's poller was already killed at spawn time and is never respawned, so the channel
goes silently deaf. The user sees nothing until messages stop arriving.

This is NOT the 409/competing-poller symptom as filed in earlier reports: since telegram
plugin v0.0.6 the takeover is an orderly single-token handoff, so no 409 fires and the
outage surfaces at subagent EXIT, not spawn. Reproduced 3-for-3 on 2026-07-11: each
approved subagent termination was followed within one probe interval by zero live pollers.
Mid-session process-table check showed the live Telegram poller parented by a spawned
teammate claude process rather than the orchestrator session that owns the channel.

Why configuration cannot solve this today

  • enabledPlugins supports per-plugin false overrides with scope precedence

(managed > local > project > user) - but a spawned subagent reads the SAME settings
files as its parent, so no scope can express "this session but not its spawns."

  • Subagent/agent frontmatter supports model, tools, disallowedTools, mcpServers,

hooks, etc. - but nothing for plugins.

  • --channels plugin:x only opts a session into event delivery; plugin loading (and the

background poller) is controlled solely by enabledPlugins. So the flag cannot express
"orchestrator only" either.

Net: the only two reachable states are "orchestrator and every spawn load the plugin"
(spawns break the channel) or "nobody loads it."

Requested

Any one of these resolves the class:

  1. Honor per-plugin false overrides at spawn granularity: an agent-definition

frontmatter field (plugins: [] / disabledPlugins: [...]) or an Agent-tool
parameter, so a spawn can be launched without channel plugins; or

  1. A settings scope or key that excludes Agent-tool spawns from inheriting a named

plugin (e.g. enabledPlugins: {"x": "session-only"}); or

  1. Treat channel plugins as session-singular: if the parent session already runs the

plugin's MCP server, spawns skip starting a second instance; and/or

  1. Respawn: if a session's channel-plugin MCP child exits while the session lives,

restart it (today the session stays deaf until a manual /reload-plugins).

Items 1-3 prevent the takeover; item 4 is the safety net that would also cover every
other way a poller dies mid-session.

What we run today to work around this

The scale of the workaround illustrates the cost of the gap. To keep one Telegram channel
alive on an orchestrator session that also uses subagents, we operate:

  • an external launchd watchdog that probes channel liveness every 5 minutes and, when the

poller is gone, types /reload-plugins into the live session via tmux send-keys -
keystroke injection into an interactive session as a recovery mechanism (it fired 3
times in one afternoon of normal subagent use);

  • a second probe layer with state-transition alerting and debounce, because the

reload-recovery cycle itself produces false outage alarms;

  • a guarded self-heal layer in a separate inbox monitor (idle-gated, once per episode,

escalates to a human on failure), built to replace the raw keystroke injection;

  • a launch-time verifier that fails loudly when the channel workers are missing.

All of this exists solely because a spawn takes the poller and nothing restores the
session's own after the spawn exits.

Prior art (same class, unresolved)

  • #36960 "support singleton mode for plugins that can't run multiple instances

(e.g. Telegram polling)" - proposed excluding spawned subprocesses; stale-closed
2026-04-20, never addressed.

  • #36800 "duplicate channel plugin instances mid-session, 409 Conflict and tool loss" -

8+ corroborating reports (Telegram, WhatsApp, Discord, custom plugins); stale-closed
2026-06-14; only the plugin-side v0.0.6 takeover patch shipped, which changed the
symptom (no more 409) without fixing the inheritance/no-respawn root.

  • #66106 "[plugin: telegram] server.ts spins at 100% CPU when multiple sessions run

concurrently - PID_FILE assumes single writer" - open, tagged stale.

Environment

Claude Code CLI v2.1.207 (2026-07-11), macOS, telegram@claude-plugins-official 0.0.6;
orchestrator launched via --channels, subagents via the Agent tool in the same project;
plugin enabled in project .claude/settings.local.json.

View original on GitHub ↗