[BUG] Foreground `sleep` block fires constantly — model polls background tasks the harness already promised to notify about
Preflight
- [x] I have searched existing issues and this hasn't been reported yet
- [x] This is a single bug report
- [x] I am using the latest version of Claude Code
Related but distinct: #90475, #87920, #86085 and #90930 are all about what the block message recommends next (unbounded until-loops, Monitor when Monitor is disabled, subagent lifecycle). This issue is about how often the block fires at all — the model reaches for foreground sleep reflexively, including in cases where there is nothing to wait for.
What's Wrong?
The Bash tool description already states the rule up front:
run_in_backgroundruns the command detached: it keeps running across turns and re-invokes you when it exits. No&needed. Foregroundsleepis blocked; use Monitor with an until-loop to wait on a condition.
Despite that, the model composes a foreground sleep anyway, and the guidance only lands as a rejection after the call. In this session it happened one tool call after the harness had explicitly said no waiting was needed.
The sequence:
- Started a long eval run with
run_in_background: true. The tool result said:
> Command running in background with ID: bvnm1qqbz. Output is being written to: …/tasks/bvnm1qqbz.output. You will be notified when it completes.
- Next tool call, the model issued
sleep 90; tail -c 1500 …to poll that same task.
- Blocked:
> Blocked: sleep 90 followed by: tail -c 1500 … To wait for a condition, use Monitor with an until-loop (e.g. until <check>; do sleep 2; done). To wait for a command you started, use run_in_background: true. Do not chain shorter sleeps to work around this block.
The block was correct. The poll was also entirely unnecessary — the task had already promised a completion notification, so the right action was to do nothing. The model still spent a round-trip on it.
The user's report, verbatim: "you hit this a lot, like A LOT." This is not a one-off; it recurs across sessions.
Why this is worth separating from the existing reports
The four related issues assume the block is a fine outcome and argue about the replacement advice. This one is that the block fires far too often to be a good signal:
- Every occurrence costs a full round-trip and pollutes the transcript with a rejection.
- The rule is already in the tool description, so restating it in the rejection is not changing behavior.
- The most common trigger appears to be polling a task the harness has already committed to notifying about — a wait that should never have been composed, and which no
until-loop or Monitor call improves either.
Suggestions
Either would help; they are not exclusive.
- Make the pending-notification state visible at composition time — e.g. keep a short "N background tasks running; you will be notified" line in context — so polling reads as redundant rather than as the obvious next move.
- Treat the frequency itself as a model-behavior regression rather than something the rejection message can fix. The instruction exists and is not being followed.
Environment
- Claude Code 2.1.266
- macOS (Darwin 25.6.0), zsh
- Model: Claude Opus 5