[BUG] CronCreate: recurring ticks queue during busy REPL turns, then flush as duplicates on idle
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?
When the REPL is busy on a long-running tool call (e.g. a multi-minute Bash invocation), each CronCreate tick that comes due during that busy window gets queued instead of dropped. When the REPL finally goes idle, the harness flushes all of the queued ticks as separate user prompts in a single turn — so a recurring cron with a 10-minute interval can deliver 5–13 identical prompts stacked back-to-back if a Bash call took ~50–130 minutes.
The CronCreate tool description says: "Jobs only fire while the REPL is idle (not mid-query)." I read that as "missed ticks while non-idle are dropped". The observed behavior is closer to "missed ticks are queued and flushed on next idle". One of those is a docs bug; the other is a scheduler bug.
Related but distinct from #56108 ("CronCreate: one-shot prompts silently queue for hours when session idle") — that issue covers an idle session with no current turn (queue drains only on external wake event). Mine is a busy session whose backlog flushes immediately when the current turn ends. The underlying flush mechanism is the same (per #56108's empirical section: "ALL queued prompts (including any recurring cron fires that were also queued) deliver into the session simultaneously"), but the trigger and remediation are different — recurring jobs benefit from coalescing missed ticks; one-shot jobs benefit from drain-on-idle.
What Should Happen?
For recurring cron jobs, missed ticks during a busy turn should coalesce. If N consecutive queued ticks have identical prompt text, fire only the latest (or fire one and discard the rest). Stacking is never the intent for a polling/babysit pattern — each fire is idempotent and only the most recent observation matters.
For one-shot crons, the current queue-and-replay-on-idle behavior is probably correct (the user asked for that prompt to fire even if delayed) — and is already covered by #56108.
A coalesceMissed: true (default true for recurring, false for one-shot) flag on CronCreate would let edge cases opt out.
Error Messages/Logs
No error — the symptom is a single user-turn with 13 duplicated cron-prompt blocks stacked into one message. The agent processes the first one normally; the remaining 12 are no-ops in practice because each cycle is idempotent, but they cost real tokens to ingest.
Steps to Reproduce
- Schedule a recurring cron with a short interval:
````
CronCreate({cron: "*/10 * * * *", prompt: "Check PR status briefly.", recurring: true})
- Run a long-running
Bashthat occupies the REPL for >60 minutes — e.g.Bash("sleep 4500; echo done")(75 minutes). - Wait for the Bash to complete. The REPL goes idle.
- Observed: the next user turn arrives with ~7 stacked copies of "Check PR status briefly." (one per missed 10-minute tick), all delivered as a single message.
- Expected: a single fire (the latest tick), or zero fires (if cron strictly only fires while REPL was idle at tick time).
Claude Model
- Opus
Is this a regression?
- I don't know
Last Working Version
(empty)
Claude Code Version
2.1.153 (Claude Code)
Platform
- Anthropic API
Operating System
- macOS
Terminal/Shell
- iTerm2 (zsh)
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗