---
title: "Scheduled Tasks & /loop"
aliases: [loop, cron-tasks, session-scheduling]
tags: [claude-code, scheduling, cron, loop, automation]
sources: [raw/Run prompts on a schedule.md]
created: 2026-04-17
updated: 2026-04-17
---

# Scheduled Tasks & /loop

Run prompts automatically on a repeating interval or fire one-time reminders inside a Claude Code session. Requires **v2.1.72+** (`claude --version`).

Tasks are **session-scoped**: they live in the current conversation. `--resume` / `--continue` restores unexpired tasks; a fresh session clears them.

---

## Scheduling Options Compared

| | Cloud Routines | Desktop Tasks | `/loop` (session) |
|---|---|---|---|
| Runs on | Anthropic cloud | Your machine | Your machine |
| Machine must be on | No | Yes | Yes |
| Open session required | No | No | Yes |
| Persistent across restarts | Yes | Yes | Restored if unexpired |
| Local file access | No (fresh clone) | Yes | Yes |
| Min interval | 1 hour | 1 minute | 1 minute |

- **Cloud** → reliable unattended runs, no local machine needed
- **Desktop** → local files + tools, no open session needed
- **`/loop`** → quick in-session polling, simplest to start

---

## /loop — Quick Reference

| Command | Behavior |
|---------|----------|
| `/loop 5m check the deploy` | Fixed cron interval, your prompt |
| `/loop check the deploy` | Dynamic interval Claude chooses each iteration |
| `/loop` | Built-in maintenance prompt, dynamic interval |
| `/loop 15m` | Built-in maintenance prompt, fixed interval |
| `/loop 20m /review-pr 1234` | Re-run another skill on a fixed schedule |

### Fixed Interval
```
/loop 5m check if the deployment finished
```
- Units: `s`, `m`, `h`, `d` — seconds round up to nearest minute
- Non-clean steps (`7m`, `90m`) are rounded; Claude tells you what it picked

### Dynamic Interval
- Omit the interval; Claude picks 1 min–1 hour based on observed state
- Short waits when something is active; longer when idle
- May use the **Monitor tool** internally (streams background script output — more token-efficient than polling)
- Jitter rules don't apply; 7-day expiry does

### Built-in Maintenance Prompt (bare `/loop`)
Each iteration, in order:
1. Continue unfinished work from the conversation
2. Tend to the current branch's PR (review comments, failed CI, merge conflicts)
3. Run cleanup passes (bug hunts, simplification) when nothing else is pending

Irreversible actions (push, delete) only proceed if already authorized in the transcript.

### Customize with `loop.md`
Replaces the built-in prompt for bare `/loop` calls:

| Path | Scope |
|------|-------|
| `.claude/loop.md` | Project-level (takes precedence) |
| `~/.claude/loop.md` | User-level fallback |

- Plain Markdown, no required structure
- Edits take effect on the next iteration — refine while running
- Max 25,000 bytes (content beyond is truncated)
- Ignored when you supply a prompt on the command line

---

## One-Time Reminders

Describe in natural language — Claude creates a single-fire task that self-deletes after running:

```
remind me at 3pm to push the release branch
in 45 minutes, check whether the integration tests passed
```

---

## Managing Tasks

Natural language works:
```
what scheduled tasks do I have?
cancel the deploy check job
```

Underlying tools:

| Tool | Purpose |
|------|---------|
| `CronCreate` | Schedule a task (5-field cron, prompt, recurring flag) |
| `CronList` | List tasks with IDs, schedules, prompts |
| `CronDelete` | Cancel task by ID |

- Each task has an **8-character ID** (used with `CronDelete`)
- Max **50 scheduled tasks** per session

---

## How Tasks Fire

- Scheduler checks every second; tasks enqueue at **low priority**
- Fires **between 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
- Recurring: fires up to 10% of period late, capped at 15 min (e.g. hourly → `:00`–`:06`)
- One-shot at `:00` or `:30`: fires up to 90 s early
- Offset is deterministic from task ID → same task, same offset
- To avoid jitter: pick a non-`:00`/`:30` minute (e.g. `3 9 * * *`)

### Seven-Day Expiry
- Recurring tasks auto-expire 7 days after creation; fire once more then self-delete
- To extend: cancel and recreate, or switch to Routines / Desktop tasks

---

## Cron Expression Reference

5-field format: `minute hour day-of-month month day-of-week`

| Expression | Meaning |
|------------|---------|
| `*/5 * * * *` | Every 5 minutes |
| `0 * * * *` | Every hour on the hour |
| `7 * * * *` | Every hour at :07 |
| `0 9 * * *` | Daily at 9am local |
| `0 9 * * 1-5` | Weekdays at 9am local |
| `30 14 15 3 *` | March 15 at 2:30pm local |

- `0`/`7` = Sunday through `6` = Saturday
- Supports: `*`, single values, steps (`*/15`), ranges (`1-5`), lists (`1,15,30`)
- No extended syntax: `L`, `W`, `?`, name aliases (`MON`, `JAN`) not supported
- If both day-of-month and day-of-week are set, a date matches if **either** matches (vixie-cron semantics)

---

## Disable Scheduling

```bash
CLAUDE_CODE_DISABLE_CRON=1
```

Disables the scheduler entirely. `CronCreate`, `CronList`, `CronDelete`, and `/loop` become unavailable; already-scheduled tasks stop firing.

---

## Limitations

- Tasks only fire while Claude Code is **running and idle** — closing the terminal stops them
- **No catch-up** for missed fires (fires once when Claude goes idle, not per missed interval)
- Fresh conversation clears all tasks; `--resume`/`--continue` restores unexpired ones
- Background Bash and monitor tasks are **never restored** on resume
- On Bedrock / Vertex AI / Microsoft Foundry: dynamic `/loop` falls back to a fixed 10-min schedule; bare `/loop` prints usage instead of starting maintenance loop

---

## Key Takeaways

- `/loop` is the fastest way to poll during a session — interval optional, prompt optional
- Omitting the interval gives Claude adaptive waits (short when active, long when idle)
- Bare `/loop` runs a built-in PR/CI maintenance loop; `loop.md` customizes it per project
- One-time reminders need no special syntax — just describe them in natural language
- Session tasks expire after 7 days; use [[wiki/claude-code/overview|Routines or Desktop tasks]] for durable scheduling
- The `CronCreate` / `CronList` / `CronDelete` tools are what `/loop` calls under the hood
- Disable entirely with `CLAUDE_CODE_DISABLE_CRON=1`

---

## Related

- [[wiki/claude-code/channels|Channels]] — push events into a session reactively instead of polling
- [[wiki/claude-code/headless-cli|Headless CLI]] — run Claude Code non-interactively with `-p`
- [[wiki/claude-code/overview|Claude Code Overview]] — full feature surface including Routines and Desktop tasks
- [[wiki/claude-code/skills|Skills]] — package reusable workflows that `/loop` can call (e.g. `/loop 20m /review-pr`)

---

## Sources

- `raw/Run prompts on a schedule.md` — clipped from https://code.claude.com/docs/en/scheduled-tasks
