Scheduled tasks in Claude Code: automate the boring waits
You kicked off a deploy ten minutes ago. Now you’re cycling between your terminal and the Cloudflare dashboard, refreshing like it’s 2005. The build might take five minutes or fifty. You don’t know. So you keep checking.
Claude Code can do that for you. Its scheduled tasks feature lets you fire off a prompt on a recurring interval — or set a one-shot reminder — and get back to actual work while it watches the pot.
What scheduled tasks are (and aren’t)
Scheduled tasks are session-scoped cron jobs. They live inside your running Claude Code process, fire prompts on a cadence you define, and disappear the moment you exit. There’s no daemon, no persistence, no config file.
That scoping is deliberate. If you need automation that survives restarts and runs unattended, you want GitHub Actions with a schedule trigger, or the Desktop app’s scheduled tasks for a GUI setup flow. Session-scoped scheduling fills a different niche: the “keep an eye on this while I context-switch” workflow that would otherwise eat your attention in tiny, irritating chunks.
The /loop command
/loop is the primary interface. Give it an interval and a prompt, and Claude schedules a recurring job in the background.
/loop 5m check if the deployment finished and tell me what happenedClaude parses the interval, converts it to a cron expression, and confirms the cadence and job ID. Every five minutes, it runs your prompt as if you’d typed it yourself.
Interval syntax
You’ve got flexibility in how you specify the interval:
# Leading token — most common
/loop 30m check the build
# Trailing "every" clause
/loop check the build every 2 hours
# No interval — defaults to every 10 minutes
/loop check the buildSupported units are s (seconds), m (minutes), h (hours), and d (days). Since cron has one-minute granularity, seconds get rounded up. Intervals that don’t divide evenly — like 7m or 90m — get rounded to the nearest clean interval, and Claude tells you what it picked.
Real examples worth stealing
Monitoring a deployment is the obvious one, but /loop gets more interesting when you pair it with specific questions:
# Watch a PR for new review comments
/loop 15m check PR #342 for new comments and summarize anything I need to address
# Poll CI until it passes (or fails)
/loop 5m are the integration tests passing on the staging branch yet?
# Keep tabs on a long migration
/loop 30m check the database migration status and warn me if anything looks stuckThe prompt runs with full tool access, so Claude can actually go check GitHub, read logs, or inspect state — it’s not just echoing a string at you.
One-time reminders
Not everything needs a loop. For one-shot nudges, just write what you want in plain English:
remind me at 3pm to push the release branchin 45 minutes, check whether the integration tests passedClaude pins the fire time to a specific minute using a cron expression, confirms when it’ll fire, and auto-deletes the task once it runs. No cleanup needed.
This is genuinely useful for the “I’ll do that after lunch” class of tasks that usually end up forgotten in a Slack message to yourself.
Looping over other commands
Here’s where things get interesting. The scheduled prompt can itself be a command or skill invocation:
/loop 20m /review-pr 1234Every twenty minutes, Claude runs your PR review skill against that PR. If someone pushes new commits, you get a fresh review without lifting a finger. You could do the same with any custom skill you’ve built — linting, test runs, status checks, whatever.
Managing your tasks
Ask Claude in natural language:
what scheduled tasks do I have?cancel the deploy check jobIt works as you’d expect. Under the hood, three tools handle the mechanics:
| Tool | What it does |
|---|---|
CronCreate | Schedule a new task with a 5-field cron expression |
CronList | List all tasks with IDs, schedules, and prompts |
CronDelete | Cancel a task by its 8-character ID |
A session supports up to 50 concurrent tasks, which is more than anyone should reasonably need.
Under the hood
A few implementation details worth knowing.
Timing. The scheduler checks every second for due tasks and queues them at low priority. Prompts fire between your turns — never mid-response. If Claude is busy when a task comes due, it waits until the current turn ends. All times are local timezone, not UTC.
Jitter. To avoid every session hammering the API at the same wall-clock second, the scheduler adds a small deterministic offset. Recurring tasks fire up to 10% of their period late, capped at 15 minutes. An hourly job might fire anywhere from :00 to :06. One-shot tasks scheduled on the hour or half-hour fire up to 90 seconds early. The offset is derived from the task ID, so it’s stable — same task, same offset every time. If exact timing matters to you, schedule for an odd minute like :03 instead of :00.
Three-day expiry. Recurring tasks auto-delete after 3 days. This is a safety net — a forgotten /loop won’t poll indefinitely. If you need something longer, cancel and recreate it before expiry, or move to GitHub Actions for durable scheduling.
Watch your token burn rate
One thing the docs don’t emphasise: every loop iteration is a full prompt execution. A /loop 5m running for three hours is 36 invocations. On API billing, that adds up fast. A few guard rails worth adopting:
- Use the widest interval you can tolerate. If checking every 15 minutes is fine, don’t default to 5.
- Cancel loops when you’re done. It’s easy to forget a loop that’s quietly polling something you stopped caring about an hour ago.
- Lean on one-shot reminders for things that only need checking once. They auto-delete after firing.
The 3-day expiry caps the worst case, but a tight loop on an expensive prompt can still burn through usage before you notice.
Limitations
Session-scoped scheduling has real constraints, and it’s worth being upfront about them:
- Tasks only fire while Claude Code is running and idle. Close your terminal, and everything’s gone.
- No catch-up for missed fires. If Claude is busy on a long-running request when a task comes due, it fires once when Claude becomes idle — not once per missed interval.
- No persistence across restarts. Restarting Claude Code clears all scheduled tasks.
- One-minute granularity. Cron doesn’t do sub-minute scheduling.
You can also disable the feature entirely by setting CLAUDE_CODE_DISABLE_CRON=1 if scheduled tasks aren’t your thing or you’re in an environment where background prompts would cause problems. For enterprise teams, that flag doubles as a governance control — useful if you’d rather not have autonomous agents firing prompts on a schedule inside your infrastructure.
Practical takeaways
Start with /loop the next time you kick off a deploy or a long CI run. It’s genuinely one of those features that sounds minor but saves real attention. A few recommendations:
- Deploy monitoring is the killer use case.
/loop 5m check if the deploy finishedbeats refreshing a dashboard. - Natural language reminders are perfect for “I’ll do that later” tasks that usually get lost.
- Composing
/loopwith skills — like/loop 20m /review-pr 1234— is where the feature starts to feel like having a junior dev keeping watch. - Don’t fight the session scope. If you need durable, unattended scheduling, use GitHub Actions. Scheduled tasks are for active sessions where you just want to stop babysitting something.
The whole feature runs on standard 5-field cron under the hood, so if you already know cron, you already know how this works. And if you don’t, Claude will figure out the expression for you from plain English. Either way, your deploy dashboard can stop being your second monitor.