[BUG] /loop dynamic-mode termination doesn't cancel pending ScheduleWakeup fires; loop reactivates after declared stop
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
- Invoke
/loop <some long-running task>in dynamic mode (no fixed interval) - Across multiple turns, the assistant calls
ScheduleWakeuprepeatedly as fallback heartbeats while batches run - Eventually the assistant declares completion in prose: "Loop terminates. Stopping without ScheduleWakeup."
- The most recently scheduled wakeup (from a prior turn) is still queued
- ~N seconds/minutes later it fires
- 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:
- Spec gap. The
/loopskill 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.
- No cancel mechanism.
ScheduleWakeupdocuments adelaySecondsarg but no inverse cancel. The assistant has no tool to unqueue a pending fire even if it wanted to.TaskListmay surface pending wakeups; killing them isn't documented as a path.
- 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.
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗