Channel events are never surfaced to the model in non-interactive (-p) sessions

Status Open
Reported on v2.1.233
Maintainer reply None cached
Activity 0 comments · opened Aug 17, 2026

Running a custom channel in a non-interactive session, channel events reach the channel server and are acknowledged by it, but never appear in the model's context. The same channel works correctly in an interactive session.

Environment: Claude Code 2.1.233, native Windows, session launched with --dangerously-load-development-channels server:<name> and -p.

Measurement, with the receiving session deliberately barred from calling any of the channel's tools:

  1. A session was started with the channel loaded and instructed to touch no channel tool and simply wait 150 seconds.
  2. An event was pushed 24 seconds into that wait, while the session's socket was attached and the session was actively running.
  3. The channel server received it and acknowledged delivery 67 ms after it was queued.
  4. The session reported that no <channel source="..."> block, notification, or event text appeared in its context for the entire 150 seconds.
  5. It saw the event only when it later called the channel's own read tool, 143.8 seconds after the event was queued.

The same behaviour appears when the event is queued before the session starts: the backlog is pushed on socket attach, the server records the delivery, and the model still sees nothing until it polls.

An interactive session on the same channel and the same build does receive the push: there, the server-side delivery and the model's own acknowledgement are two distinct measured events, 68 ms and 13,314 ms after queueing.

What the documentation says: /docs/en/channels supports channels in print mode and mentions -p once, about disabling tools that would wait for terminal input so the session never stalls. It does not say whether an event is surfaced to the model in that mode.

The plausible cause, offered as a guess rather than a claim: an event arrives as a new turn, and a -p session has exactly one turn before it exits, so there is no turn for the event to land in.

Three attempts to work around it from the channel side all failed, which is worth including because it narrows the cause:

  • Returning the waiting-message count from the channel's own connect tool does not help: a session whose task is something else never calls that tool.
  • Rewriting the MCP server instructions to say "call connect at the start, mail may be waiting, do this even when nothing appeared in your context" does not help either.
  • Nor does adding that the tools may be deferred and must be loaded first.

A direct probe showed why the third one still fails, and it rules out the obvious explanation: the session quoted the instructions back verbatim, so they are delivered. It also reported the channel's tools as deferred with schemas not loaded. Delivered instructions simply do not redirect a model that has been given a different task, and there is no channel-side lever left.

Either behaviour would be workable; the problem is that it is currently silent. A channel server in a -p session cannot tell that its push went nowhere, so it records a successful delivery. Documenting the limitation, or surfacing the event, or returning something that lets the server know the push was not delivered, would each resolve it.

View original on GitHub ↗