[MODEL] Opus 5 re-reads background task status ~25 times in one turn instead of ending the turn and waiting for the notification

Status Open
Reported on v2.1.220
Maintainer reply None cached
Activity 0 comments · opened Jul 28, 2026

Preflight Checklist

  • [x] I have searched existing issues for similar behavior reports
  • [x] This report does NOT contain sensitive information

Type of Behavior Issue

Other unexpected behavior

What You Asked Claude to Do

Finish a code change, push it, and confirm the CI run on the pushed commit went green before reporting back. CI here is a single GitHub Actions workflow with three jobs on a self-hosted runner that runs jobs serially, so the full run takes about 12 minutes.

What Claude Actually Did

The push and the code work were correct. The waiting is the problem.

  1. Armed a Monitor on the workflow's job outcomes.
  2. Armed four separate Bash background commands, each an until loop that exits when the run completes.
  3. Then, for the next 14 minutes, called gh api .../jobs and Read on the watcher output files roughly 25 times, with a one-line "Waiting." message between almost every call.

It never stopped. The watchers it had already armed were going to deliver exactly the same information, and two of them did fire correctly during that window. The polling added nothing.

The tell is in its own text. It wrote "I'll stop polling and wait for the background watchers to report", then issued another status read on the very next call. It did that at least six times, each time stating the correct action and then not taking it.

Expected Behavior

After arming a watcher, end the turn with plain text and let the notification resume the session. That is what the Monitor tool description tells the model to do ("Keep working - do not poll or sleep"), and the notification machinery works, so nothing was broken except the model's own choice.

Concretely it should have been one watcher, one closing sentence, and then silence until the run concluded.

Permission Mode

Accept Edits was ON (auto-accepting changes)

Can You Reproduce This?

Sometimes (intermittent)

Claude Model

Opus

Relevant Conversation

Verbatim from the session, condensed. Each line is a separate assistant turn or tool call:

Lint green, project-checks red on pre-existing doc debt, test still running.
  Read 1 file
Waiting.
  Read 1 file
Waiting for the test job to conclude before writing the handoff.
  Read 1 file, ran 1 shell command
I'll wait for the background watcher to report instead of polling.
  Read 1 file, ran 1 shell command
Waiting on the test job.
  Read 1 file, ran 2 shell commands
Waiting for the run to conclude.
  Read 1 file
Still waiting on the test job.
  Read 1 file, ran 1 shell command
Waiting for the run to finish.
  Read 1 file
Waiting for the background watcher to report the run's conclusion.
  Read 1 file, ran 1 shell command
I'll wait for the watcher.
  Read 1 file, ran 1 shell command
The suite is running. Waiting.

The Read calls hit the same watcher output file over and over. The harness started answering them with "Wasted call - file unchanged since your last Read", which the model read and then ignored.

Impact

Medium - Extra work to undo changes

Claude Code Version

2.1.220 (Claude Code)

Platform

Anthropic API

Additional Context

Closest prior report is #51673, closed as inactive. That one covers a model writing filesystem poll loops that stall past completion. This is a different shape and arguably worse: the model set up the correct notification-driven waiting, understood it, said so out loud, and polled anyway.

One thing that may explain the pull toward polling, from the model's side: ending a turn while background work is pending looks identical to ending a turn because the work is finished. There is no way to signal "park me until the watcher fires", so every stopping point feels like a premature report. A yield primitive, or a line in the Monitor and Bash docs stating plainly that ending the turn with pending background tasks is correct and the notification will resume it, would remove the ambiguity.

View original on GitHub ↗