Extend Soft Β· in-session, local GA v2.1.72+ ⓘ legend

Scheduled tasks (/loop)

Clock-driven repetition inside an open session. The /loop bundled skill re-runs a prompt on an interval — poll a deploy, babysit a PR, check back on a long build. It feels like cron because it is cron under the hood — but it runs a model that decides what to do each tick, not a fixed script.

Analogy β€” a kitchen timer wired to a cook. The timer rings every N minutes (the cron part); each time it rings, the cook looks at the current state of the kitchen and decides what to do next (the decision-maker part). Cron alone just rings a bell and runs the same script; /loop rings the bell and thinks.

It’s cron + a decision-maker — and it’s session-scoped Three things people conflate. OS cron runs a fixed shell script system-wide, forever — /loop runs a model and only while your session is open and idle. /goal is the condition-driven cousin (keep going until a check passes), where /loop is clock-driven (every N minutes). Routines are the cloud/unattended cousin that survive a closed laptop — /loop does not.

Mechanism β€” what you provide determines the mode

Both the interval and the prompt are optional, and what you give decides the behaviour:

interval + prompt
fixed cron
/loop 5m check the deploy β€” converted to a cron expression and scheduled
prompt only
Claude picks the delay
a dynamic 1-min–1-hour wait each iteration based on what it saw; may use the Monitor tool
nothing
maintenance prompt
a built-in upkeep prompt, or your .claude/loop.md if one exists
/loop 5m check if the deployment finished and tell me what happened   # fixed interval
/loop check whether CI passed and address review comments            # Claude-chosen interval
/loop 20m /review-pr 1234                                            # re-run a saved command each tick
remind me at 3pm to push the release branch                          # a one-shot, scheduled in natural language
The cron tools, jitter & expiry

Under the hood Claude uses CronCreate (5-field cron expression + prompt + recurs/once), CronList, and CronDelete (by 8-char ID). A session holds up to 50 tasks. The scheduler checks every second and fires a due prompt between your turns, never mid-response, at low priority. Jitter adds a deterministic offset (recurring tasks up to 30 min late) so every session doesn’t hit the API at once.

Tasks are session-scoped: starting a new conversation clears them; --resume/--continue restores any that haven’t expired. Recurring tasks auto-expire 7 days after creation (one final fire, then delete) — this bounds how long a forgotten loop can run. Press Esc while a /loop waits to stop it. Disable the whole scheduler with CLAUDE_CODE_DISABLE_CRON=1.

Customize the bare-/loop default with .claude/loop.md (project) or ~/.claude/loop.md (personal) — plain markdown, edited live between iterations.

When to reach for it

βœ“
You want to poll something on a cadence during dev — a deploy, a PR’s CI, a long build.
βœ“
You want a recurring upkeep pass while you work — bare /loop or a loop.md.
βœ“
You’ll keep the session open and want to stop it any time with Esc.

When not to

βœ•
You mean “keep going until a condition holds,” not “every N minutes” β†’ /goal.
βœ•
It must run with your laptop closed or survive a restart β†’ a routine (cloud) or Desktop scheduled tasks.
βœ•
You want to react to an event the moment it happens, not poll β†’ Channels (CI pushes the failure in) or a hook.

Best practices

β˜…
Prefer a dynamic /loop (prompt only) so Claude waits longer when nothing’s pending — cheaper and more responsive than a fixed tick.
β˜…
For a long-running process, let Claude use the Monitor tool instead of polling — it streams output and avoids re-running a prompt on a timer.
β˜…
Pick a fire minute that isn’t :00/:30 if exact timing matters — jitter offsets the round ones.
β˜…
Budget it: a fixed loop runs until you stop it or 7 days pass. Cap iterations and watch token spend — the loop, not the model, is the expensive part.
Session-scoped means it stops when you do Tasks fire only while Claude Code is running and idle. Closing the terminal stops them; there’s no catch-up for fires missed while Claude was busy (it fires once when idle, not once per missed interval). A new conversation clears all tasks. For anything that must run unattended, use Routines or Desktop scheduled tasks.

Sources