Plugin monitor notifications are re-delivered every turn (not once per stdout line)
Summary
A plugin monitor (declared in monitors/monitors.json) is documented to deliver
each stdout line from its command to the session as a notification. In practice, a
single stdout line is re-surfaced as a new Monitor event: notification on roughly
every turn for the lifetime of the session, regardless of whether the command produces
any further output.
The result: a monitor whose command emits at most one line every minute or two still
floods the transcript with many identical Monitor event: lines — because the
multiplication happens in the harness (re-delivery), not in the command's output.
There appears to be no setting/flag/env var to make a monitor's notification deliver
once per stdout line instead of being re-injected each turn, and no way to silence the
re-delivery without silencing the monitor's output entirely.
Environment
- Claude Code:
2.1.168 - OS: macOS 26.5.1 (Darwin)
Minimal reproduction
- Create a tiny plugin with a single one-shot monitor:
my-plugin/.claude-plugin/plugin.json
``json``
{ "name": "monitor-noise-demo", "version": "0.0.1" }
my-plugin/monitors/monitors.json
``json``
[
{
"name": "noise-demo",
"command": "bash -c 'echo \"monitor fired once\"; sleep 86400'",
"description": "Demo monitor that emits exactly one line, then sleeps"
}
]
The command writes exactly one stdout line for the entire session, then sleeps.
- Install/enable the plugin and start a session.
- Do a few turns of ordinary work (a handful of tool calls / messages).
- Watch the transcript.
Expected
The single stdout line (monitor fired once) produces one Monitor event:
notification. Nothing further appears, because the command never writes again.
Actual
Monitor event: "Demo monitor that emits exactly one line, then sleeps" reappears on
~every turn, many times over the session, even though the command emitted only one line.
Two details worth noting:
- The notification text shown is the monitor's
descriptionfield, not the actual
stdout content — so every re-delivery looks identical and carries no new information.
- In the session transcript (
.jsonl), these show up as repeated<task-notification>
entries that all share one task-id (the monitor task), interleaved with
queue-operation entries — i.e. the same pending notification is re-queued/re-injected
each turn rather than delivered once.
Measured (real-world, separate from the minimal repro)
In one ~69-minute session, a monitor whose command emits at most one line per ~90s
(and only on a state change, so just a few real emits the whole session) produced
362 identical Monitor event: notifications, all tied to a single monitor task-id —
a sustained ~5 notifications/minute, peaking at ~16/minute. The delivery rate tracked
session/turn activity, not the command's (near-zero) output rate.
Impact
- Long-lived monitors (the intended use — "watch X for the whole session") become
unusable for any human-visible notification, because a single legitimate event is
amplified into continuous transcript noise.
- The only workaround is to make the monitor command produce no stdout at all (e.g.
redirect to /dev/null or add a --quiet mode). That removes the noise, but also
removes the wanted one-notification-per-real-change — there is no way to keep the
former without the latter.
Requests (any one would resolve it)
- Deliver a monitor's notification once per stdout line, and do not re-inject a
prior notification on subsequent turns.
- And/or add a way to suppress/throttle monitor-event re-delivery (a setting,
a per-monitor field, or de-duplication of an already-shown notification) without
suppressing the monitor's output entirely.
Questions
- Is the per-turn re-delivery intentional, or a side effect of how pending
task-notifications are flushed into the conversation?
- Is there an existing/undocumented knob to control monitor-notification frequency?
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗