Build the system that drives the agent — loops that run while you sleep
6 lessons2026-08-06AI-generated
1Overview
In this chapter you move beyond writing specifications and learn how to construct the autonomous loop that keeps your agent running for hours without manual input. You’ll assemble a ladder of concrete patterns—including the closed loop, a perpetual fresh‑agent loop, Claude Code’s /loop, /goal and /batch commands, headless execution with claude -p, as well as stop‑conditions and maker/checker verification—using a ready‑to‑copy cheat sheet, three fully worked examples, and video walkthroughs that show each step in action.
1.1After this chapter you can
→Close the loop: make the agent verify its own work (tests, /goal) before it stops
→Run a loop unattended — a fresh-agent forever-loop, anchor files, and headless `claude -p`
→Always give a loop a way to stop: iteration caps, no-progress and budget limits
→Scale up safely with /batch worktrees, maker/checker subagents, and scheduled routines
1.2How can I run agents nonstop?
Use a forever-loop such as `while :; do cat PROMPT.md | claude-code; done` to keep the agent executing without manual input, letting it operate while you sleep.
1.3What tools manage loop stop‑conditions?
Claude Code provides /loop, /goal, and /batch commands plus headless `claude -p`, which let you define when a loop should pause or end based on outcomes or external checks.
1.4How do I verify loop outputs safely?
Implement maker/checker verification inside the loop so each iteration’s result is validated before proceeding, ensuring reliable execution and preventing error propagation.
1.5The moves — weak → strong ladder
1Close the loop with a real check
2Give it a goal it can verify — /goal
3Babysit a task on an interval — /loop
4Run the agent over and over in a simple loop (the "Ralph loop")
5Anchor files are the loop's memory
6Run it headless — claude -p
7Always give it a way to stop
8Split the maker from the checker
9Fan out repetitive work — /batch
10Put the loop on a schedule — /schedule
2Techniques
Learn
The closed loop
Make it check its own work
Close the loop with a real checkAn open loop writes until it claims "done"; a closed loop verifies after every change. Only the closed one is safe to leave running.
✕Instead of
Build the feature and tell me when you're done.
✓Try this💬 AI chat
After every change, run `npm test`. Only stop when the suite is green; if it fails, read the error and fix it, then run the tests again.
Why it works: A model asked "are you done?" will say yes. A test suite that has to pass is a signal it cannot talk its way past — that feedback is what makes a loop trustworthy.
Give it a goal it can verify — /goalClaude Code's `/goal` keeps working across turns until a condition holds, re-checked by a fast model each turn.
✕Instead of
Keep going until the code is good.
✓Try this💬 AI chat
/goal every test in src/ passes and CHANGELOG.md has an entry for each PR merged this week
Why it works: A vague goal never resolves. A concrete, checkable condition gives the loop an exit signal — and `/goal` re-evaluates it after each turn so the agent self-terminates.
Babysit a task on an interval — /loop`/loop [interval] [prompt]` re-runs a prompt on a schedule; omit the interval and Claude self-paces (1m–1h).
✕Instead of
I'll keep refreshing the PR to see if CI passed.
✓Try this💬 AI chat
/loop 10m review PR #123 — if CI is red, fix it; if there are review comments, address them in a worktree; stop once it's green and approved
Why it works: Polling by hand wastes your attention and stalls the moment you step away. A `/loop` watches for you and acts each time the state changes.
Run unattended
forever-loops, headless & budgets
Run the agent over and over in a simple loop (the "Ralph loop")The simplest way to run an agent unattended: a one-line shell loop feeds the same instructions to a brand-new agent over and over, until you stop it. Each pass starts with a clean slate and does ONE small piece of work. ("Ralph loop" is just the nickname for this pattern.)
✕Instead of
Paste the next task into the chat each time the agent finishes one.
✓Try this💬 AI chat
while :; do cat PROMPT.md | claude-code ; done
# PROMPT.md: "read fix_plan.md, do the single most important item, run tests, commit, exit."
Why it works: A long conversation rots as the context fills. Resetting every iteration and keeping progress in git (not the chat) lets the loop grind through a backlog overnight without drift.
Anchor files are the loop's memoryBecause each pass forgets the last, durable state lives in a fixed set of files the loop reloads every time.
✕Instead of
Re-explain the project and what's left to do at the start of every run.
✓Try this💬 AI chat
Keep PROMPT.md (the instruction), fix_plan.md (priority-sorted todo), AGENT.md (how to build/test), and specs/. Each pass reads them fresh; the agent updates fix_plan.md as it goes.
Why it works: External memory survives the context reset. The files are the source of truth across iterations — the same "keep a living spec" move from PRD engineering, now driving an autonomous loop.
Run it headless — claude -pPrint mode (`claude -p`) runs non-interactively in a script. Pre-approve tools so it never blocks on a prompt.
✕Instead of
claude -p "fix the failing test" --dangerously-skip-permissions
✓Try this❯_ Terminal
claude -p "fix the failing test" --allowedTools "Read,Edit,Bash" --permission-mode acceptEdits
Why it works: There is no `--dangerously-skip-permissions` flag — it just errors. Scope what the loop may do with `--allowedTools` / `--permission-mode` instead: unattended, but not unbounded.
Always give it a way to stopAn unattended loop needs hard stops: a max-iteration cap, a no-progress detector, and a token/dollar budget.
✕Instead of
while :; do cat PROMPT.md | claude-code ; done # runs forever
✓Try this💬 AI chat
for i in $(seq 1 10); do cat PROMPT.md | claude-code; grep -q "BLOCKED" fix_plan.md && break; grep -q "[ ]" fix_plan.md || break; done
Why it works: Without a give-up condition a stuck loop burns money forever on the same error. A cap plus a no-progress/BLOCKED exit turns a runaway into a bounded, reviewable attempt.
Orchestrate
Many agents, on a schedule
Split the maker from the checkerNever let the agent that wrote the code be the one that approves it — a separate reviewer (or the tests) is the gate.
✕Instead of
The coding agent reviews its own diff and merges if it likes it.
✓Try this💬 AI chat
One subagent implements; a separate reviewer subagent (fresh context) critiques against the spec. The loop merges only if the reviewer AND the tests pass.
Why it works: A maker grading its own work rubber-stamps it. An independent checker is the single biggest guard against a loop confidently shipping broken code.
Fan out repetitive work — /batch`/batch <instruction>` decomposes a big job into 5–30 independent units and runs one background subagent per unit, each in its own git worktree.
✕Instead of
Migrate all 30 components from Solid to React, one chat at a time.
✓Try this💬 AI chat
/batch migrate src/ from Solid to React
# each unit: its own worktree → implement → run tests → open a PR
Why it works: Independent work shouldn't run serially. `/batch` parallelises it across isolated worktrees so the units can't collide, and each comes back as a testable PR.
Put the loop on a schedule — /scheduleFor recurring work, a cloud routine runs on Anthropic's infrastructure — no open session, no machine left on.
✕Instead of
Remember to run the issue-triage prompt every morning.
✓Try this💬 AI chat
/schedule a daily routine: triage new issues, label and prioritise them, and post a summary to Slack #eng — runs in the cloud at 7am
Why it works: A loop you have to start by hand is a manual task with extra steps. A scheduled routine is the difference between "I run it" and "it runs."
3Lessons 6
3.1Create a persistent state file for your agentic loop
A markdown file that lives outside the model context and records what the loop has already done.
You will have a STATE.md file that the loop reads and updates on each iteration.
Open your project folder in a terminal.
Create an empty file named STATE.md.
Add a first line # Loop state to give the file a header.
Edit your outer‑loop script (e.g. the while‑loop from the Ralph technique) to prepend cat STATE.md before invoking the agent so it can observe the current state.
After each agent run, append a line like - iteration $(date +%s) to STATE.md using echo "- iteration $(date +%s)" >> STATE.md.
You'll see STATE.md contains a growing list of timestamps showing each loop pass, and the agent’s prompts include the file contents.
Takeaway External files act as durable memory for long‑running agents, letting you track progress across independent runs.
3.2Add persistent state to a looping agent
Anchor files that store the current specification or results, reloaded by every fresh‑agent iteration.
Modify the forever loop so it reads and writes a state file that accumulates work across iterations
Create a JSON file named state.json containing {}
Open PROMPT.md and prepend Load state from state.json; ; Save updated state back to state.json
Replace the loop command in your script with while :; do cat PROMPT.md | claude-code; done
Run the script for several cycles, then open state.json to confirm it now holds data from previous passes
You'll seestate.json is updated after each iteration, showing cumulative information while the agent itself starts fresh every time
Takeaway External files act as persistent memory for autonomous loops, separating long‑term state from volatile model context
Check How does work survive from one iteration to the next when the agent itself starts fresh every time?
3.3Add a test‑driven stop condition to your loop
A closed loop that runs tests after each edit and stops when they all pass, preventing endless execution.
Extend the loop so it runs a test suite after each iteration and exits automatically when the suite succeeds
Create a shell script run_tests.sh that exits with status 0 if all tests pass and non‑zero otherwise
Write a new file loop.sh containing while :; do cat PROMPT.md | claude-code && ./run_tests.sh || break; done
Make loop.sh executable using chmod +x loop.sh
Run the script with ./loop.sh and observe the loop stop when the test script reports success
You'll see The loop iterates several times then terminates as soon as the test script returns a zero exit status
TakeawayEmbedding verifiable checks (tests) turns an open‑ended loop into a trustworthy closed loop that self‑terminates on success
Check Which exit status from run_tests.sh stops the loop, and where in loop.sh is that decided?
3.4Add a test‑driven stop condition with /goal
/goal is a Claude Code primitive that repeats until a verification model confirms a condition.
Your loop will automatically stop when a specified test suite passes.
Write a simple test file, e.g., test_pass.py containing an assertion that fails initially.
Run the loop using the /goal command: claude -p "..." /goal "python test_pass.py && echo success".
Create a small verification skill (a separate model call) that checks for the word “success” in the agent’s output.
Configure the loop so that after each iteration it runs the test and feeds the result to the verifier.
Observe that the loop exits once the test passes and the verifier returns true.
You'll see The loop terminates automatically after the test file changes to make python test_pass.py succeed, and you see a final log line indicating the goal was reached.
TakeawayEmbedding verifiable checks turns an endless loop into a goal‑oriented process that stops safely.
3.5Wire persistent state into the stop condition
A combined pattern where STATE.md drives both work and the /goal termination logic.
The loop will cease when a specific entry appears in STATE.md, verified by a sub‑agent.
Add to STATE.md a line DONE that you will manually insert later as the stop marker.
Create a verification skill named check-done that reads STATE.md and returns true if it finds the word DONE.
Modify your /goal command to use this skill: /goal "cat STATE.md | grep -q DONE && echo done".
Run the loop; each iteration will read STATE.md, perform its work, then invoke check-done.
Append DONE to STATE.md and watch the loop stop automatically.
You'll see The loop runs several iterations, then halts immediately after the DONE line is added, with a log entry confirming the goal was satisfied.
Takeaway Persisted state can serve as both work context and a contract‑based termination signal for autonomous loops.
3.6Add a safety guardrail to abort on budget overflow
A simple token‑budget check that stops the loop when a predefined limit is exceeded.
Your loop will automatically stop if it consumes more than the allowed token budget.
Create a file BUDGET.md with a line limit: 50000 representing the maximum tokens.
Add a skill track-budget that reads BUDGET.md, adds the token count of each agent call (use claude -p --token-count) to a running total stored in STATE.md, and compares it to the limit.
In your outer loop script, invoke track-budget after each agent run; if it returns false, break the while loop.
Run the loop with a low limit (e.g., 1000) to trigger the guardrail quickly.
Observe that the loop stops once the accumulated token count exceeds the limit.
You'll see The loop terminates with a message like “Budget exceeded” and STATE.md shows the total tokens used.
TakeawayEmbedding resource constraints prevents runaway loops and makes autonomous agents safe for production use.
4FAQ, Tips & How-to 10
one problem, one solution, one action
▸How-toEveryone
Waiting for CI to pass on a PR
`/loop [interval] [prompt]` re-runs a prompt on a schedule; omit the interval and Claude self-paces (1m–1h). Polling by hand wastes your attention and stalls the moment you step away. A `/loop` watches for you and acts each time the state changes.
Claude Code's `/goal` keeps working across turns until a condition holds, re-checked by a fast model each turn. A vague goal never resolves. A concrete, checkable condition gives the loop an exit signal — and `/goal` re-evaluates it after each turn so the agent self-terminates.
An open loop writes until it claims "done"; a closed loop verifies after every change. Only the closed one is safe to leave running. A model asked "are you done?" will say yes. A test suite that has to pass is a signal it cannot talk its way past — that feedback is what makes a loop trustworthy.
`/batch <instruction>` decomposes a big job into 5–30 independent units and runs one background subagent per unit, each in its own git worktree. Independent work shouldn't run serially. `/batch` parallelises it across isolated worktrees so the units can't collide, and each comes back as a testable PR.
Never let the agent that wrote the code be the one that approves it — a separate reviewer (or the tests) is the gate. A maker grading its own work rubber-stamps it. An independent checker is the single biggest guard against a loop confidently shipping broken code.
Having to remember to run issue triage every morning
For recurring work, a cloud routine runs on Anthropic's infrastructure — no open session, no machine left on. A loop you have to start by hand is a manual task with extra steps. A scheduled routine is the difference between "I run it" and "it runs."
Because each pass forgets the last, durable state lives in a fixed set of files the loop reloads every time. External memory survives the context reset. The files are the source of truth across iterations — the same "keep a living spec" move from PRD engineering, now driving an autonomous loop.
An unattended loop needs hard stops: a max-iteration cap, a no-progress detector, and a token/dollar budget. Without a give-up condition a stuck loop burns money forever on the same error. A cap plus a no-progress/BLOCKED exit turns a runaway into a bounded, reviewable attempt.
Print mode (`claude -p`) runs non-interactively in a script. Pre-approve tools so it never blocks on a prompt. There is no `--dangerously-skip-permissions` flag — it just errors. Scope what the loop may do with `--allowedTools` / `--permission-mode` instead: unattended, but not unbounded.
The simplest way to run an agent unattended: a one-line shell loop feeds the same instructions to a brand-new agent over and over, until you stop it. Each pass starts with a clean slate and does ONE small piece of work. ("Ralph loop" is just the nickname for this pattern.) A long conversation rots as the context fills. Resetting every iteration and keeping progress in git (not the chat) lets the loop grind through a backlog overnight without drift.
The fastest credible "build your first autonomous workflow with Claude Code" walkthrough — a concrete first loop.
6FAQ 5
How is a loop different from a cron job?
A cron job runs a fixed script on a schedule — same steps every time. A loop runs an agent that reads the current state and decides what to do next on each pass, so it can self-heal, adapt, and stop when a goal is met. A schedule (like `/loop` or a routine) is just one way to trigger a loop.
An open loop writes until the agent claims it is done — no check. A closed loop runs a real verification (tests, a build, a separate reviewer) after each change and only stops when that passes. Only closed loops are safe to leave running unattended; open loops are demo-only.
How do I stop a loop running away (and burning money)?
Give every loop a hard stop: a maximum iteration count, a no-progress detector (same error or empty diff N times in a row), and a token/dollar budget. With `/goal`, the condition is re-checked each turn so it self-terminates; with a bash loop, cap it with `for i in $(seq 1 10)` and break on a BLOCKED marker.
Is the Ralph loop the same as Claude Code's /loop?
No. The Ralph loop is a plain bash while-loop that pipes a prompt into a fresh agent each pass — you own the loop. `/loop` is Claude Code's built-in command that re-runs a prompt on an interval (or self-paced) inside a session. Same idea — a system that re-prompts the agent — at two levels of abstraction.
Is it safe to run an agent headlessly without permission prompts?
Run `claude -p` with `--allowedTools` and `--permission-mode acceptEdits` so it only does what you scoped — unattended, not unbounded. There is no `--dangerously-skip-permissions` flag (it errors); scoping the tools is the supported way. Pair it with a sandbox (a git worktree per agent) so nothing reaches main until a check approves.
Designing the system that prompts the agent for you, instead of typing each turn yourself.
Closed loop
A loop that verifies after every change (tests, a reviewer) and only stops when the check passes — safe to leave running.
Open loop
A loop that writes until the agent claims "done", with no verification. Demo-only.
Ralph loop
A nickname for the simplest way to run an agent unattended: feed the same prompt to a fresh agent over and over in a one-line shell loop — one small job per pass, progress saved to git. while :; do cat PROMPT.md | claude-code ; done
Anchor files
The fixed files a loop reloads every iteration (PROMPT.md, fix_plan.md, AGENT.md, specs/) — its memory across the context reset.
Maker / checker
Separating the agent that does the work from a different agent (or the tests) that approves it — never let the maker grade itself.
Stop condition
The rule that ends a loop even when it can't succeed: a max-iteration cap, a no-progress detector, or a token/dollar budget.
BLOCKED
A marker the agent writes (e.g. to fix_plan.md) so the loop wrapper can exit when it cannot proceed.
Worktree
An isolated git working copy so several agents can run in parallel without their edits colliding.
Commands
claude -p
Headless / print mode — runs Claude Code non-interactively in a script. Scope it with --allowedTools and --permission-mode; there is no --dangerously-skip-permissions flag.
/loop
Claude Code: re-run a prompt on an interval (e.g. /loop 5m …) or omit the interval to self-pace (1m–1h).
/goal
Claude Code: keep working across turns until a verifiable condition holds, re-checked by a fast model each turn.
/batch
Claude Code: split a big job into 5–30 units and run one background subagent per unit, each in its own worktree.
/schedule
Claude Code: run a routine on a schedule in the cloud — no open session or machine left on.