Claude / Operating Manual · Topics
Loops & Autonomy
Make Claude Code run itself. In-session orchestration, self-paced multi-turn loops, scheduled cloud routines, and spec-driven autonomous runs. When to reach for which, and the cadence math nobody tells you.
GA · updated 2026-06-14
"Loops" is not one feature. It is the whole family of ways to make Claude Code keep working without you driving every turn. The community has a name for the skill now: loop engineering, the shift from typing prompts into an agent to writing the program that prompts the agent for you. As one widely shared post put it, "stop prompting your agent, start building loops." A loop is just a recursive goal: you define a purpose and the agent iterates until it is met.
The mechanisms sit on a spectrum, from inside a single response to fully detached from any session. Picking the right one comes down to two questions: how long is the gap between iterations, and who decides when the next one runs.
The five loop shapes
| Shape | Mechanism | Gap between iterations | Who paces it | Reach for it when |
|---|---|---|---|---|
| In-session orchestration | Workflow tool (while / pipeline / parallel) | ms to seconds | the script | fan out many agents in one turn; loop until done / dry / budget |
| Self-paced multi-turn | /loop (no interval) + ScheduleWakeup | seconds to minutes | the model | a task needing several turns at a cadence the model judges |
| Fixed-interval | /loop 5m /cmd | exactly N | you (the interval) | the same check on a clock (poll a deploy every 5 min) |
| Scheduled / detached | /schedule, Cron tools | minutes to days | a cron, no session open | recurring jobs that run whether or not you are around |
| Spec-driven autonomous | Ralph (prd.json), /goal | until done | the spec / goal | grind a whole backlog to completion, unattended |
Most people babysit one agent at a time. The real gain is in the lower rows: handing a whole workflow to a running loop and walking away.
Anatomy of a loop that actually works
Recent write-ups converge on the same five parts. A loop missing the last two either spins forever or declares fake victory:
- Goal. The purpose the loop iterates toward.
- Step. The unit of work done each firing (a prompt, a command, a workflow).
- State. Memory that survives across firings. For detached loops this is a real file
on disk (a
state.jsonthe loop reads at the top and writes at the bottom), because a fresh firing starts with no conversation history. - Verifier. How the loop knows progress is real (tests pass, CI is green, the item is gone from the queue), not just that a turn happened.
- Stop condition. The exit. "Until the PR is green," "until the backlog is empty," "after N idle rounds." Without it you have a runaway.
Verification, cost, and a stopping criterion are the three things that separate a loop you can leave alone from one you have to watch.
The building blocks
Background tasks. Bash(run_in_background: true) detaches a command. It keeps running
across turns and re-invokes you when it exits. You do not poll it; the harness wakes
you. Foreground sleep is blocked on purpose; to wait on a condition, use a Monitor with
an until loop. This is the primitive everything else is built on.
See Background tasks.
Monitor. Streams events from a long-running script: every stdout line becomes a notification. Three patterns, by how many notifications you want:
- one notification ("tell me when the build is done") → Bash background with an
untilloop that exits; - one per occurrence, forever ("every ERROR line") → Monitor with
tail -f/while true; - one per occurrence until a known end ("each CI step, stop when the run completes") → Monitor with a command that emits then exits.
/loop. A built-in skill that runs a prompt or slash command repeatedly. Give it an
interval (/loop 5m /babysit-prs, units s / m / h / d) for clockwork, or omit
the interval to let the model pace itself turn to turn. Default interval if you say
nothing is about 10 minutes. It is session-scoped: it lives and dies with the session.
ScheduleWakeup. The pacing engine behind self-paced /loop. You pick delaySeconds
(clamped to 1 minute up to 1 hour) and pass the same prompt forward so the next firing
repeats the task. Short waits while a build finishes, long waits when nothing is pending.
The non-obvious part is cost. See the next section.
Cron tools and /schedule. For work that should run with no session open.
/schedule creates cloud routines; the Cron tools (CronCreate / CronList /
CronDelete) schedule programmatically using standard 5-field cron expressions
(*/15 * * * *, wildcards, ranges, steps, lists). One-time future runs are supported too.
Safety rails: recurring tasks auto-expire after a bounded window (docs and community cite
about 7 days, after which it fires one last time and deletes itself), and a session caps
at around 50 scheduled tasks, so a forgotten loop cannot run forever. (Verify the exact
current numbers in the docs; they have moved.)
Workflows. Deterministic in-session fan-out. Scripts persist at
.claude/workflows/<name>.js, are invoked by name with args, compose one level deep,
and are cron-schedulable, which is how an in-session orchestration loop becomes a
detached recurring one. See Workflows.
Ralph / /goal. Spec-driven autonomous runners. Convert a PRD to prd.json (/ralph)
and the agent loops the backlog until it is done; /goal runs until a stated goal is met.
The in-session cousins are the Workflow tool's loop-until-dry and loop-until-budget patterns.
Wake-up cadence and the prompt cache
When you self-pace with ScheduleWakeup, delaySeconds is not just "how long to wait." The
Anthropic prompt cache has a 5-minute (300s) TTL. Sleep past it and the next wake-up
re-reads your whole conversation uncached: slower and more expensive. So there are only
two sensible bands:
- 60 to 270s (cache stays warm). Use only when you are actively polling external state the harness cannot notify you about: a CI run, a deploy, a remote queue.
- 1200s or more (one cache miss buys a long wait). Use for idle ticks, or as a long fallback heartbeat when something else is the real wake signal.
Never pick 300s. It pays the cache miss without amortizing it. If you are tempted to "wait 5 minutes," drop to 270s (stay warm) or commit to 1200s and up (amortize the miss).
And the trap that wastes the most money: do not poll for work the harness already
tracks. A run_in_background task or a workflow re-invokes you automatically when it
finishes, so a short wake-up just to "check on it" is wasted. Schedule a long fallback
(1200s or more) as a safety net and let the notification do the waking.
Decide: which loop do I reach for?
- All inside one response (fan out agents, retry until clean)? → Workflow tool loop.
No
/loop, no scheduling. - Needs several turns, but only while I'm in the session?
- same action on a fixed clock →
/loop <interval> <cmd> - cadence the model should judge →
/loopwith no interval (self-paced)
- same action on a fixed clock →
- Should run when no session is open? →
/schedule(cloud routine) orCronCreate(programmatic), recurring or one-time. - "Grind this whole backlog to done, unattended"? → Ralph /
/goal. - Just waiting on one background thing to finish? → don't loop at all. Fire it with
run_in_background(or a workflow) and let the auto re-invoke wake you; add one long ScheduleWakeup fallback only as insurance.
The three that get confused are /loop (repeat in-session), Cron (schedule in-session
or programmatic), and /schedule (detached cloud routine). Rule of thumb: in-session and
rhythmic → /loop; survives the session closing → /schedule or Cron.
Recipes
1. Babysit a CI run (external state the harness can't see). The run is outside the harness, so you must poll. Keep the cache warm:
/loop # self-paced, no interval
→ poll `gh run watch` / the run status
→ still running: ScheduleWakeup delaySeconds: 270, reason: "watching CI run #1234"
→ done: report result, end the loop (omit ScheduleWakeup)
270s keeps you in cache across the roughly 8-minute run instead of paying a cache miss per tick.
2. Wait on a local build (harness-tracked): the anti-recipe.
Do not /loop and poll. Background it and get woken:
Bash(run_in_background: true): npm run build
# keep working; the harness re-invokes you when it exits
If you must guard a hang, add one ScheduleWakeup delaySeconds: 1800 fallback, not a 60s poll.
3. 24-hour autonomous run (detached, durable).
The community pattern: Claude Code plus CronCreate plus a state file on disk. The cron
fires the step, the step reads and writes state.json, the verifier gates each cycle, the
stop condition retires the cron.
/schedule (or CronCreate "0 * * * *") → step reads state.json → does work
→ verifier (tests/CI green?) → writes state.json → repeats
→ stop when goal met; recurring task also auto-expires as a backstop
4. Nightly portfolio sweep (recurring, no session open).
/schedule → cron "0 6 * * *" → run /content-sweep (or a custom routine)
Reports back when it runs; you read the result next time you're in.
5. Stream errors during a long local run (per-occurrence).
Monitor: tail -f dev.log | grep -E --line-buffered "ERROR|Traceback|FAILED|Killed"
One notification per matching line. Grep the failure signatures, not just success, or a crash looks identical to "still running."
6. Grind a backlog to done (autonomous).
/ralph → prd.json → loops until every task is complete
Best for well-scoped, verifiable work (migrations, broad refactors), not open-ended design.
Failure modes
- Polling harness-tracked work. A 60s wake-up to "check the background job" burns the cache several times before the job finishes, for nothing. Let the auto re-invoke wake you; schedule only a long fallback.
- The 300s cache cliff. A round "5 minutes" is the worst possible delay. 270s or 1200s and up, never 300.
- No stop condition means a runaway. A self-paced loop with no exit keeps firing. The
Workflow tool has a 1000-agent backstop and scheduled tasks auto-expire, but a bare
/looprelies on you defining the exit. State it up front, then end the loop by omitting the next wake-up. - No verifier means fake victory. A loop that checks "did a turn happen" instead of "did the test pass" will happily report a broken build as done. Gate on real signal.
- Loops run in isolation. A running loop has no built-in way to reach another loop, another agent, or your Slack. Cross-loop coordination is on you (shared state file, a queue, an external trigger), so don't assume two loops can talk.
- Cron without a cost cap. A detached recurring agent that calls a paid API spends while you sleep. Put the spending cap in the job, not in your intentions. (House rule: every paid API gets a daily cap.)
- Forgetting it's session-scoped.
/loopand Cron tools die when the session closes. If it has to survive that, it belongs in/scheduleor a cloud routine.
Quick reference
| You want | Reach for | Key form |
|---|---|---|
| Fan out + loop in one turn | Workflow tool | while (budget.remaining()...), parallel, pipeline |
| Same task every N min (in session) | /loop | /loop 5m /cmd |
| Model-paced multi-turn (in session) | /loop + ScheduleWakeup | omit interval; delaySeconds 270 or 1200+ |
| Wait on background work | run_in_background | no loop; auto re-invoke + 1800s fallback |
| Per-line event stream | Monitor | tail -f | grep --line-buffered |
| Recurring, no session open | /schedule / CronCreate | 5-field cron expression |
| Unattended backlog grind | Ralph / /goal | prd.json / goal statement |
Cadence cheat: poll external state → 270s. Idle tick → 1200 to 1800s. Never 300s.
The mechanics above have a quick-reference card at Scheduled tasks & /loop.
Related reference
- Scheduled tasks & /loopRun a prompt on a repeat or on a clock. /loop and the Cron tools schedule inside a session; /schedule runs detached cloud routines.
- Background TasksCoordinate long-running work across sessions, subagents, and context windows with a shared task list stored on disk.
- WorkflowsHave Claude orchestrate tens to hundreds of parallel subagents in the background, with verification.