--- name: schedule license: MIT description: >- Manages recurring and one-off scheduled tasks. Session-scoped scheduling via CronCreate/CronDelete/CronList. Documents the cloud path for tasks that need to survive machine sleep or network drops. user-invocable: true auto-trigger: false trigger_keywords: - schedule - recurring - every N minutes - cron - set a reminder - run periodically last-updated: 2026-03-26 --- # /schedule — Task Scheduling ## Orientation **Use when:** scheduling a recurring or one-off remote agent run (cron-style, outside the current session). **Don't use when:** repeating work within the current session (use /loop); continuous unattended campaigns (use /daemon). ## Default execution path (READ FIRST) **`/schedule add` does NOT call `CronCreate` by default.** It shells out to `node scripts/local-schedule.js` which installs a native OS entry (Windows Task Scheduler or Unix cron). Only pass `--remote` to use Anthropic's routine system, and only after explicit user confirmation. **Why:** `CronCreate` counts against the account-wide **15 routine runs / 24h** cap; every fire of the scheduled task counts. See [docs/ROUTINE-QUOTA.md](../../docs/ROUTINE-QUOTA.md). ### Default flow — `/schedule add "" ""` (no `--remote`) Run: ```bash node scripts/local-schedule.js add "" "" --confirm ``` Before running, show the cadence, project, prompt and persistence and obtain approval to create the OS task. Normal Claude permissions remain enabled. Do not add a bypass flag to make unattended execution succeed. Then report the returned ID and the removal command. This survives session end, machine reboot, and consumes zero routine quota. Use `/schedule list` and `/schedule remove {id}` (which also shell out to `local-schedule.js`) by default. Remove tasks before uninstalling. New jobs require their `.citadel/schedules/.json` record; deleting it disables execution but leaves an inert OS entry. Existing jobs retain their old bypass flags until explicitly removed and recreated. See [runner safety and migration](../../docs/ISSUE-278-SECURITY.md). ### Codex automation lane When running in Codex and the user wants the schedule to survive the current terminal session, create a Codex Automation plan instead of a local OS entry: ```bash node scripts/codex-automation.js plan --type schedule --cadence "" --command "" --write ``` Give the returned `prompt` to the Codex app automation surface and keep the generated `.planning/codex-automations/{id}.json` as the durable Citadel record. If `.planning/` does not exist, create it before writing automation state. ### Opt-in routine flow — `/schedule add --remote ...` Only when `--remote` is explicitly passed: 1. Confirm: "This will use `CronCreate`, which counts against your 15 routine runs / 24h quota and is cleared at session end. Continue? (y/N)" 2. On confirmation, run the `CronCreate`-based flow documented below. The rest of the protocol documents the full `CronCreate` flow for reference and for `--remote` invocations. ## When to Route Here - "run pr-watch every hour" - "check my PRs automatically" - "schedule a thing" - "remind me to run tests every 30 minutes" - "set up a recurring task" - "list my scheduled tasks" - "cancel the PR check" - Any mention of "schedule", "recurring", "every N minutes/hours", "cron" ## Protocol ### /schedule list List all currently scheduled tasks using CronList. Output format: ``` Active schedules (N): [id] {description} — {cron expression} — next run: {time} No schedules active. ``` If CronList is not available: output a helpful error (see Fringe Cases). --- ### /schedule add "{description}" {/skill-or-command} Create a recurring task. Steps: 1. Parse the user's description to extract: - Natural language interval: "every 30 minutes", "hourly", "every day at 9am" - The skill or command to run: `/pr-watch`, `/do status`, etc. 2. Convert natural language to a cron expression (see Conversion Table below) 3. Confirm with user: "I'll run `{command}` {natural-language-interval} (cron: `{expression}`). OK?" 4. If confirmed: call CronCreate with the expression and command 5. Output: "Scheduled. ID: {id}. Use `/schedule remove {id}` to cancel." **Cron Expression Conversion Table:** | Natural Language | Cron Expression | |---|---| | every minute | `* * * * *` | | every 5 minutes | `*/5 * * * *` | | every 15 minutes | `*/15 * * * *` | | every 30 minutes | `*/30 * * * *` | | every hour / hourly | `0 * * * *` | | every 2 hours | `0 */2 * * *` | | every 6 hours | `0 */6 * * *` | | every day / daily | `0 9 * * *` (default 9am) | | every day at {H}am/pm | `0 {H} * * *` | | every weekday | `0 9 * * 1-5` | | every Monday | `0 9 * * 1` | If the user provides a raw cron expression directly, use it as-is without converting. Validate it has 5 fields before accepting. --- ### /schedule remove {id} Remove a scheduled task by ID using CronDelete. If the user doesn't know the ID: run `/schedule list` first, show the list, and ask which one to remove. Output: "Removed schedule {id} ({description})." --- ### /schedule status Show all active schedules and their next run times. Equivalent to `/schedule list` with additional context about what each task does and when it last ran (if available). --- ## Session-Scoped vs. Cloud-Persistent Scheduling ### Session-Scoped (CronCreate) CronCreate schedules tasks that run during the **current Claude Code session only**. When the session ends (Claude Code closes or the conversation is reset), all session-scoped schedules are cleared. **Use session-scoped when:** - Running checks during an active work session ("remind me every 30min to commit") - Polling for PR feedback while you're at the computer - Triggering skill runs during a long coding session ### Cloud-Persistent (RemoteTrigger) For tasks that need to survive machine sleep, network drops, or session restarts, use **RemoteTrigger** — a one-off cloud trigger that fires from Anthropic's infrastructure rather than your local session. **Use cloud-persistent when:** - The task needs to run overnight or while you're away - You want notifications when you return to your machine - The interval spans multiple days or calendar dates **How to set up a one-off cloud trigger:** 1. Call RemoteTrigger with the desired delay and the command to run 2. Claude Code registers the trigger in Anthropic's cloud scheduler 3. When the trigger fires, it wakes a new Claude Code session and runs the command 4. Results are delivered as a notification **Note:** RemoteTrigger requires Claude Code with cloud features enabled (Pro or Team plan). CronCreate works on all plans but is session-scoped only. --- ## Fringe Cases **CronCreate not available:** Output error; suggest OS cron/Task Scheduler. Never fail silently. **Ambiguous interval:** Ask for clarification before proceeding. **Raw cron expression:** Accept without conversion; validate 5 fields. **Every-minute schedule:** Warn about 60 fires/hour; suggest 5m or 15m instead. **No schedules when listing:** "No active schedules. Use `/schedule add` to create one." **Pause requested:** Explain pause isn't supported; remove and recreate instead. --- ## Contextual Gates **Disclosure:** "Creating schedule: `{command}` at `{cron expression}`. OK?" **Reversibility:** amber — creates OS cron entries or CronCreate sessions (side effects outside the repo); undo with `/schedule remove {id}` **Trust gates:** - Any: confirms before creating; shows cron expression before accepting ## Quality Gates - Always confirm before creating (CronCreate is a side effect) - Always show the cron expression alongside the natural-language description - Always provide the ID after creation so the user can remove it - Never leave a user unable to remove a schedule they created ## Exit Protocol /schedule does not produce a HANDOFF block. After each action, output a concise confirmation or list and wait for the next command. - After `add`: "Scheduled. ID: {id}. Use `/schedule remove {id}` to cancel." - After `remove`: "Removed schedule {id}." - After `list` or `status`: the active schedule list (or "No active schedules.") - After any error: a clear message and actionable suggestion.