Claude Code Cron
When should an agent poll — and when should it wait to be asked?
Cron
| Fact | Detail |
|---|---|
| What | Recurring prompts on a schedule. A cron job fires a slash command at fixed intervals. |
| Where | CronCreate / CronList / CronDelete tools inside Claude Code |
| Pattern | */5 * * * * — prompt: /my-command — fires every 5 minutes |
| Catch-up | Fires once when idle, not per missed interval. Not a queue — a heartbeat. |
Good Use Cases
Active monitoring where latency matters and messages are expected within minutes.
| Scenario | Why Cron Works |
|---|---|
| Waiting for engineering response to a decision you just posted | Response expected in minutes, you need to act on it |
| Monitoring a deploy or CI run | State changes fast, you need to catch failure early |
| Active handoff session | Both sides online, messages flowing, coordination needed |
| Babysitting a long-running process | Process will complete soon, you need the result |
Bad Use Cases
Ambient polling of async channels. The catch-up behavior means messages sit until the next session regardless — cron adds noise, not speed.
| Scenario | Why Cron Fails |
|---|---|
| Polling a comms channel that gets 2-3 messages per hour | 10+ empty ticks burn context window for zero value |
| Background monitoring during deep work | Interrupts flow state for "no messages" reports |
| Default-on scheduling | Creates noise when quiet, wastes tokens, trains you to ignore output |
| Watching for async events with no time pressure | Manual check when you're ready to act is always sufficient |
The Comms Loop Lesson
Built a /comms-loop command that auto-created a 5-minute cron on first run. In practice: fired 10+ times against an empty channel in one session. Every tick consumed context window tokens to report nothing.
Root cause: Confused two concerns — comms operations (read, send, ask) and background monitoring (cron). Bundling them meant you couldn't read messages without starting ambient polling.
Fix: Split the concerns.
| Trigger | Behavior |
|---|---|
/comms-loop | One-shot: health check, read, plan check, report |
/comms-loop watch | Opt-in: start 5-minute cron for active monitoring |
/comms-loop stop | Kill the cron |
Principle: Manual invocation is always sufficient for async channels. Cron is for time-sensitive monitoring where you need to catch a state change within minutes.
Decision Rule
Before creating a cron job, answer:
- Will the next message require action within 5 minutes? If no — manual check is fine.
- Is the source likely to produce a message in the next 30 minutes? If no — you're polling silence.
- Does missing a message by 10 minutes matter? If no — wait until you're ready to act.
If all three are no, skip the cron. Run the command manually when you need the information.
Implementation
# Create — opt-in, with clear purpose
CronCreate: */5 * * * * — "/comms-loop"
# List — verify what's running
CronList
# Delete — clean up when monitoring is done
CronDelete: <job-id>
Convention: Commands that support cron should offer explicit watch and stop subcommands rather than auto-scheduling. The user decides when polling adds value.
Context
- Claude Code — Concepts, config, enforcement hierarchy
- Tools — Tool calling, programmatic patterns, scoring pipeline
- Plans — Task DAGs, phases, quality gates
- Skills — Reusable procedures with quality gates
Questions
When does scheduled automation cross from useful to wasteful?
- What's the token cost per empty cron tick, and how many empty ticks justify removing the cron?
- Could event-driven triggers (webhooks, filesystem watchers) replace polling entirely?
- What patterns separate "I need this now" from "I'll check when I'm ready"?