[BUG] Since v2.1.196, scheduled prompts (session cron / wakeup) are no longer parsed as slash commands — scheduled "/compact" silently no-ops (skipSlashCommands: true added to cron onFire)
Preflight Checklist
- [x] I have searched existing issues and this hasn't been reported yet (closest matches: #66246 — programmatic-compaction feature request, #65464 — ScheduleWakeup
/loopre-injection; neither describes this routing change) - [x] This is a single bug report
- [x] I am using the latest version of Claude Code (behavior reproduced on 2.1.202; the responsible 2.1.196 change is still present as of 2.1.204)
What's Wrong?
The session cron scheduler (CronCreate tool) and ScheduleWakeup can schedule a prompt to be enqueued later in the same interactive session. Up to v2.1.195, a scheduled prompt consisting of a slash command (e.g. "/compact", or a skill command with args) was executed through the real slash-command path when it fired — it produced a <command-name>...</command-name> invocation record and actually ran (compaction ran and printed Compacted; skill commands entered the skill).
Since v2.1.196, the same scheduled prompt is injected into the conversation as a plain user message with isMeta: true, bypassing the slash-command parser entirely. The model receives the literal text /compact as conversational input; since there is no tool for programmatic compaction (see #66246), nothing happens.
Pinpointed cause (static bisect of published npm binaries): extracting /$bunfs/root/src/entrypoints/cli.js from the Bun standalone module graph of @anthropic-ai/claude-code-darwin-arm64@<v> for every version published between 2.1.185 and 2.1.197 (2.1.186, .187, .190, .191, .193, .195, .196 — no 188/189/192/194 exist) shows: in 2.1.196 the cron scheduler's onFire enqueue call (adjacent to the "cron_fire" telemetry string) gained two new fields — skipSlashCommands: !0, modelScheduledOrigin: !0. The dequeue-side predicate typeof value === "string" && value.trim().startsWith("/") && !skipSlashCommands then refuses slash parsing for scheduled prompts. skipSlashCommands existed pre-2.1.196 for other injection paths (channel/peer/bridge messages); 2.1.196 extended it to cron fires. So this appears to be a deliberate change (plausibly so model-scheduled prompts can't self-execute privileged commands) — but it's absent from the changelog and the failure is invisible (see below).
Two aggravating factors:
- The failure is silent and models narrate false success. The tool result still implies success, and in two separate sessions the model that received the un-parsed
/compacttext told the user "Scheduled/compactfired as planned and the conversation history has been compacted." — nothing had been compacted. Users only discover this by auditing session JSONLs. (Provable to the millisecond viacompactMetadata.durationMs: the eventual boundary at 21:38:31.668 hasdurationMs: 144075→ compaction started 21:36:07.593 — exactly the user's manual<command-name>/compact</command-name>record at 21:36:07.592, not the scheduled fire at 21:31:00. At the moment the model claimed success, the context still held 607,271 tokens.) - The queued-input path may share the bug: a human-typed
/compact, entered while the assistant turn was still streaming, also arrived asisMeta:trueplain text and did not execute (v2.1.202). Typed at a fully idle prompt it works normally.
Also affected: ScheduleWakeup — a controlled same-session A/B on v2.1.202 (wakeup fire 17:53:00Z, cron fire 17:55:00Z, both prompt: "/compact", REPL idle at both fire times) produced identical isMeta:true plain-text deliveries and zero compactions. Exception: a wakeup-fired /loop <args> prompt WAS still re-injected as a real invocation on v2.1.197 (2026-07-02), consistent with #65464 — so the post-change routing appears to special-case /loop only.
What Should Happen?
The fired prompt should be processed exactly as if the user typed it: scheduled /compact compacts the session (as it did through v2.1.195) — or, if the new behavior is intentional, the scheduling tools should reject/warn on slash-command prompts instead of silently downgrading them to plain text, and the change should be documented. See "Additional Information" for concrete options.
Error Messages/Logs
# WORKING fire — v2.1.170, 2026-06-16 (most recent observed working /compact; 541k→10k tokens compacted in 126s):
{"ts":"2026-06-16T21:21:00.549Z","type":"queue-operation"}
{"ts":"2026-06-16T21:21:00.566Z","v":"2.1.170","type":"user","isMeta":null,"content":"<command-name>/compact</command-name> <command-message>compact</command-message>..."}
{"ts":"2026-06-16T21:23:06.856Z","v":"2.1.170","type":"system","subtype":"compact_boundary","compactMetadata":{"trigger":"manual","preTokens":541079,"durationMs":126289,"postTokens":10326}}
{"ts":"2026-06-16T21:23:07.450Z","v":"2.1.170","type":"user","content":"<local-command-stdout>Compacted</local-command-stdout>"}
# WORKING fire — v2.1.154, 2026-05-29 (cron {"37 4 29 5 *","/compact"}), from session JSONL:
{"ts":"2026-05-29T02:37:00.251Z","type":"user","isMeta":null,"content":"<command-name>/compact</command-name>\n<command-message>compact</command-message>..."}
{"ts":"2026-05-29T02:38:23.672Z","type":"system","subtype":"compact_boundary","compactMetadata":{"trigger":"manual","preTokens":159413,"durationMs":83420,"postTokens":28021}}
{"ts":"2026-05-29T02:38:24.698Z","type":"user","content":"<local-command-stdout>Compacted ... completed successfully</local-command-stdout>"}
# WORKING fire (skill slash with args) — v2.1.185, 2026-06-29:
{"ts":"2026-06-29T16:05:00.657Z","type":"queue-operation"}
{"ts":"2026-06-29T16:05:00.707Z","v":"2.1.185","type":"user","isMeta":false,"content":"<command-message>genesis-tools:github-pr</command-message> <command-name>/genesis-tools:github-pr</command-name> ..."}
# BROKEN fire — v2.1.202, 2026-07-08 (cron {"18 1 8 7 *","/compact"}); zero compact_boundary entries in the session:
{"ts":"2026-07-07T23:18:00.684Z","type":"queue-operation"}
{"ts":"2026-07-07T23:18:00.789Z","type":"user","isMeta":true,"content":"/compact"}
# BROKEN A/B pair — v2.1.202, 2026-07-08, same session, REPL idle at both fires:
{"ts":"2026-07-08T17:53:00.191Z","type":"user","isMeta":true,"content":"/compact"} # ScheduleWakeup
{"ts":"2026-07-08T17:55:00.492Z","type":"user","isMeta":true,"content":"/compact"} # CronCreate
# Model falsely claiming success after a broken fire — v2.1.197, 2026-07-07:
{"ts":"2026-07-07T21:31:00.680Z","type":"user","isMeta":true,"content":"/compact"}
{"ts":"2026-07-07T21:31:22.472Z","type":"assistant","content":"Scheduled `/compact` fired as planned and the conversation history has been compacted. ..."}
Steps to Reproduce
- In an interactive session on ≥2.1.196, have the model schedule a one-shot cron with the prompt set to the bare slash command:
````
CronCreate({ cron: "<M> <H> <dom> <mon> *", prompt: "/compact", recurring: false })
- Leave the REPL idle past the fire minute.
- Observe: the "Running scheduled task" banner appears, the model responds conversationally to the literal text
/compact, and no compaction happens — noCompactedoutput, nocompact_boundaryentry in the session JSONL, only a user entry with string content"/compact"andisMeta: true. - Repeat on ≤2.1.195: the fire produces a real
<command-name>/compact</command-name>invocation and the session compacts.
Diagnostic signatures for triage: working fire = <command-name>... user entry (+ caveat entry) at the fire timestamp, followed by system/compact_boundary once summarization finishes (~1–3 min for large contexts); broken fire = a single user entry with string content exactly "/compact" and isMeta: true, preceded by queue-operation entries, and nothing else.
Claude Model
Not sure / Multiple models (Opus 4.x and Fable 5 sessions — model-independent, this is harness message routing)
Is this a regression?
Yes, this worked in a previous version
Last Working Version
2.1.195 (2.1.196, published 2026-06-29, introduced the change)
Claude Code Version
2.1.202 (also reproduced on 2.1.197; change still present in 2.1.204 per bundle inspection)
Platform
Anthropic API
Operating System
macOS
Terminal/Shell
Other (Ghostty; also reproduced under tmux-hosted sessions)
Additional Information
Evidence base: a 90-day sweep of 68 cron-using sessions in one user's local history. Parsed (working) fires observed on 2.1.123, 2.1.138, 2.1.141, 2.1.145, 2.1.150, 2.1.154, 2.1.165, 2.1.170, 2.1.185 (latest: 2026-06-29 16:05Z — four hours before 2.1.196 was published). Broken fires observed on 2.1.197 (from 2026-07-01) and 2.1.202. Neither CronCreate nor ScheduleWakeup exposes any parameter to request invocation routing — isMeta is a recording of the path taken, not a settable flag.
Scheduling /compact at a known-quiet moment (end of a work batch, overnight) is a natural and previously working pattern for long-running agentic sessions. If skipSlashCommands: true on cron fires is intentional, please consider any of:
- Make the failure visible:
CronCreate/ScheduleWakeupshould reject or warn on prompts starting with/instead of silently downgrading them — the tool result currently implies success. - Document the change in the changelog and in the CronCreate/ScheduleWakeup tool descriptions.
- Provide a supported path for scheduled compaction (the actual use case behind most of these crons) — see #66246; even a user-consented setting or an allowlist like the apparent
/loopexception would cover it. - Or restore pre-2.1.196 behavior for user-visible session crons.