How to Keep an Agent Loop From Running Away
You hand an agent a goal and walk away. That is the entire point — you stop watching. The danger is that the agent doesn't stop either. It chases an unsatisfiable check for six hours, edits the module you didn't mean, or retries the same broken fix until the token bill shows up.
Keeping a loop safe is not a framework or a tool. It is a few specific lines in the prompt that tell the agent when to quit, what to check, and what to leave alone. Most loops skip them. We check every loop in this directory for those lines, so we can put a number on it: only 1 in 5 states when to stop. Here is what to write, starting with the line that matters most.
Start here: the two lines that bound the loop
Take an ordinary goal loop:
Fix the failing tests.
There is no stopping point, so the agent keeps going as long as anything is red — including when a test is broken in a way it cannot fix. Add two sentences:
Fix the failing tests until npm test exits 0. Stop after 10 attempts and report what is still red. Only touch application code — never edit the tests to make them pass.Now it has an exit condition (npm test exits 0), an iteration budget (10 attempts), and a scope limit (leave the tests alone). That one edit is the difference between a loop that stops on its own and one that runs until you notice. Everything below is a variation on it.
The lines that bound a loop
Six things make a prompt safe to run unattended. Put the ones that apply into yours:
| Put this in the prompt | Example | Why |
|---|---|---|
| An exit condition | "until the audit is clean", "until pytest passes" | Without a finish line, the loop never stops on its own |
| An iteration budget | "stop after 10 turns" | The backstop for when the exit condition turns out to be unreachable |
| A check to run each pass | tests, lint, build, a script | Self-reported "done" is not done — make it prove it |
| A scope limit | "never touch the tests", "minimal diffs", "report-only" | Stops the agent reward-hacking the check or wandering off-task |
| A human gate | "open a PR, never auto-merge" | Keeps a person on anything that actually ships |
| No dangerous commands | (see the last section) | The one line that is not a judgment call |
The first two do most of the work, and they are the two people leave out most.
Why the exit condition and the budget matter most
Across the vetted loops in this directory, a stated exit condition and an iteration cap are consistently the two rarest lines. They are also the two that most directly stop a runaway.
They are also what separates a loop that runs cleanly unattended from one that doesn't. The loops here that get it right are worth copying: Ship a PR until green bounds itself on CI status, and Make tests pass, gate frozen adds a scope limit so the agent can't cheat the check by rewriting it. If you add only two lines to your prompt, add these.
Picking `/goal` over Ralph will not save you
It is tempting to think one loop command is safer than another. It is not. Average safety barely moves by type — /goal, /loop, /schedule, and the fire-and-forget Ralph pattern all land in the same middle band. A /goal loop with no exit condition is more dangerous than a Ralph loop that has one. The bound lives in the prompt, not in which command you typed.
The line that is never optional
Everything above is a judgment call about how tightly to bound the loop. One thing is not: no unattended loop should carry a destructive command. No rm -rf, no git push --force, no curl | sh. No loop published here contains one — not because every author was careful, but because the directory rejects them on sight. Give your own loop the same floor. A loop that can force-push can undo a safeguard faster than you can read the log.
Check your own loop
Paste your prompt into the grader and it tells you which of these lines you are missing — the same check every loop here runs through. For the harness-level version — hooks that veto bad commands before they run, hard budgets, evaluators that reject bad output — see Agent Loop Safety. Or start from a loop that is already bounded: the Builder generates a harness with the exit condition, budget, and evaluator already wired in.
Most loops that run away were not reckless. Their authors just forgot to write down when to stop. Write it down, and you have done the single most important thing.