[BUG] Long-CI-wait + Monitor: every poll forces an assistant response, turning the chat into a wall of '·' (compounding #50258 / #55400)
Preflight Checklist
- [x] Searched existing issues; this is a concrete reproducer that compounds #50258 and #55400
- [x] Single bug report
- [x] Latest Claude Code (v2.1.144)
What's Wrong?
When using Monitor to watch a long-running external job (e.g. ~13 min GitHub Actions CI run) with a 20–30 s poll interval, every tick fires a <task-notification> that is treated as a user turn the model must respond to. The chat becomes dominated by ~30 notification blocks plus ~30 assistant responses, even though only the start, step transitions, and completion convey real signal. The intermediate ticks are noise that the model cannot suppress.
The combinatorial UX failure mode of #50258 (Monitor floods) + #55400 (harness blocks can't be hidden) + this turn-structure forcing:
- Monitor emits one stdout line per poll → one
<task-notification>per tick (#50258). - The notification is rendered as a chat-bubble in the UI with no collapse option (#55400).
- Each notification is fed to the model as a fresh user turn — the model has no "no response needed" marker, so it produces something. Either:
- Echoes the status (annoying repetition that drowns out real updates)
- Sends a placeholder like
·(looks broken / the model "ignoring" the user) - Fabricates a
Human:turn (#60360 — model fills the gap)
End user perception: the assistant looks frozen / unresponsive / spammy for 5–15 minutes at a time, even though everything is technically working. Forces the user to type "watch it run" repeatedly just to keep the assistant engaged, which itself adds turns to the transcript.
What Should Happen?
Any of the following would close the gap. They are listed in order of expected effort/impact:
Monitorshould accept anotify: \"on_completion\" | \"on_change\" | \"every_line\"parameter (defaulton_change), so polling loops naturally emit only step transitions instead of every iteration.<task-notification>should support asuppress_assistant_turn: truemode for streaming-status events. The notification gets logged into the transcript for context but does not consume a turn. Model only responds when there is something to respond to (e.g. error, completion, threshold trip).- At the CLI/UI layer, add a
settings.jsontoggle (per #55400) that visually collapses<task-notification>bubbles into a single rolling status line. Even without (1) or (2), this drops the visual noise.
Today there is no notify-style knob and no UI suppression, so the polling pattern is structurally noisy.
Concrete Reproducer
# Wait for a GitHub Actions CI run (~13 min)
Monitor({
description: \"CI run X\",
timeout_ms: 1_500_000,
persistent: False,
command: '''
while true; do
s=$(gh run view 12345 --json status,conclusion,jobs)
ts=$(date -u +%H:%M:%SZ)
step=$(echo \"$s\" | jq -r '.jobs[].steps[]? | select(.status==\"in_progress\") | .name' | head -1)
echo \"[$ts] CI=$(echo \"$s\" | jq -r .status) step=$step\"
[ \"$(echo \"$s\" | jq -r .status)\" = \"completed\" ] && break
sleep 20
done
'''
})
The user sees ~40 nearly-identical notification bubbles in the transcript with ~40 model responses, of which only the first/last/step-transition ones are useful. The intermediate 30+ responses are repetition that the user reads as 'broken'.
Workaround Today
Skip Monitor entirely. Use ONE Bash with run_in_background: true running the whole pipeline (poll → react → next-stage) and write structured output to a logfile. Then Read the logfile only when needed. The trade-off is no streaming visibility, which is exactly the use-case Monitor is supposed to serve.
System Info
- Claude Code v2.1.144 (Linux x64 musl)
- Session: long-running iteration on a live trading bot, CI + restart + verify pipeline
- Related open: #50258, #55400, #60360, #58852
Self-Reported Friction
A real session of ours just spent ~90 minutes of user-perceived dead air across two CI rounds (~13 min each plus a 3rd ~13 min retry after a CI hotfix), because every 20-30 s monitor tick consumed a turn. Filing this so other users hitting the same pattern can find it.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗