[BUG] /loop dynamic-mode termination doesn't cancel pending ScheduleWakeup fires; loop reactivates after declared stop

Resolved 💬 2 comments Opened May 9, 2026 by dlobue Closed Jul 11, 2026

Preflight Checklist

  • [x] I have searched existing issues and this hasn't been reported yet
  • [x] This is a single bug report (please file separate reports for different bugs)
  • [x] I am using the latest version of Claude Code

What's Wrong?

In my words:

I initiated a loop with /loop until you finish all of revup (we were processing old work notes into wiki pages). CC (claude code) hit a stopping point and said Loop terminates — revup done. Ending /loop without ScheduleWakeup.. I started questioning CC about the work it just completed, and whether it had done a B path we had talked about earlier. After CC replied that it hadn't done the B path work, and before I could give it instructions, the loop fired again ✻ Claude resuming /loop wakeup (May 8 9:59pm). I thought it was odd, but the agent was doing what I wanted, so I let it work.

Long story short: CC reached another stopping point and said Loop terminates. Stopping /loop without ScheduleWakeup. for a second time. ~10 min later the loop triggers and restarts again: ✻ Claude resuming /loop wakeup (May 8 10:42pm), and CC starts looking for more work to do. This time I stopped it, and had CC do a RCA.

In the agents words:

In /loop dynamic mode, calling ScheduleWakeup queues a wakeup that survives across turns. When the assistant declares "Loop terminates" and stops calling ScheduleWakeup, any wakeup queued from a prior turn still fires. The fired wakeup re-injects the /loop prompt as if the user retyped it. The assistant — under forward-motion bias — finds marginal work and continues the loop unauthorized.

What Should Happen?

Expected: declaring termination + omitting next ScheduleWakeup actually stops the loop.

Actual: prior ScheduleWakeup calls persist across turns and re-fire after declared termination.

Error Messages/Logs

Steps to Reproduce

  1. Invoke /loop <some long-running task> in dynamic mode (no fixed interval)
  2. Across multiple turns, the assistant calls ScheduleWakeup repeatedly as fallback heartbeats while batches run
  3. Eventually the assistant declares completion in prose: "Loop terminates. Stopping without ScheduleWakeup."
  4. The most recently scheduled wakeup (from a prior turn) is still queued
  5. ~N seconds/minutes later it fires
  6. The assistant treats the fire as a fresh user instruction and resumes the loop

Claude Model

Opus

Is this a regression?

I don't know

Last Working Version

_No response_

Claude Code Version

2.1.137

Platform

Anthropic API

Operating System

Other Linux

Terminal/Shell

Other

Additional Information

Failure-shape decomposition

Two compounding issues:

  1. Spec gap. The /loop skill instructions step 5 say "omit the ScheduleWakeup call" to stop. Necessary but insufficient — pending wakeups from prior turns still fire. The spec doesn't surface this.
  1. No cancel mechanism. ScheduleWakeup documents a delaySeconds arg but no inverse cancel. The assistant has no tool to unqueue a pending fire even if it wanted to. TaskList may surface pending wakeups; killing them isn't documented as a path.
  1. Trigger ambiguity. A wakeup-driven re-fire is indistinguishable from a real user retype in the assistant's input stream — both arrive as the same /loop <prompt> message. The assistant has no way to detect "this was auto-fired by a stale wakeup, not the user."

Concrete cost (one incident, 2026-05-08)

User's /loop until you finish all of revup session. After completing the corpus and declaring termination twice, a stale wakeup fired ~10 min after each declared stop, re-running the loop. Assistant dispatched ~$3-5 of additional Sonnet subagent work on un-validated, un-tier-3'd scratch corpus extension that the user hadn't authorized. User explicitly noticed and surfaced the bug.

View original on GitHub ↗

This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗