Ralph, an autonomous agent loop for coding
Ralph is the name of a technique that reduces to one idea: run an agent with the same instruction over and over until the task is finished. Progress accumulates in files and repository history rather than in conversation memory, which lets an agent work for longer than a context window allows.
Where it came from and what hides behind the name
I will start with two corrections, because an earlier version of this text stated things that are untrue, and those claims circulate beyond it too.
First, the name has nothing to do with relaxing while the agent works. It comes from Ralph Wiggum of The Simpsons and refers to persistence paired with an absence of discouragement: doing the same thing over and over until it works. Geoffrey Huntley described the technique, and his term is the one the industry adopted.
Second, the project bearing this name does not belong to Anthropic. The address under the anthropics organisation returns an error, despite appearing in material about this tool. The repository in question is frankbria/ralph-claude-code, written in shell, MIT licensed, with over nine thousand stars. Anthropic did release its own plugin implementing the same idea, available in the Claude Code repository, and the tool itself gained commands doing the same thing in a supported way.
That distinction is worth knowing, because it determines what you install. The technique is public and can be implemented in a dozen or so lines of script. Several independent projects do the same thing with different additions, and for some time a vendor supported version has existed too.
A practical order of preference follows. Start with the version built into the tool, since it is maintained alongside it and requires installing nothing. If it proves too inflexible, write your own loop, because it genuinely is a dozen or so lines and gives full control over the exit condition. Reach for a community project when you need specific additions you would rather not write yourself, elaborate exit detection or notifications for instance.
Where the attention came from
The context in which this technique became popular is worth understanding, because it shapes what you can reasonably expect from it.
The attention arrived through demonstrations where an agent running overnight reproduced the functionality of existing products or generated several repositories at once for a few hundred dollars. Such demonstrations illustrate scale well and usefulness poorly, because reproducing something that already exists and has documented behaviour is far easier than building something new against underspecified requirements.
The real value lies elsewhere and is less spectacular, much as with other agent tools such as goose. It is tedious, repetitive, verifiable work: migrating syntax across hundreds of files, filling in missing types, adding tests to existing code, standardising conventions. Work nobody wants to do by hand and where a human makes more mistakes than a machine, because boredom sets in.
It is also worth noting the idea itself is nothing new outside the agent context. Running a process in a loop until a target state is reached is a pattern familiar from systems that converge configuration toward a declared shape. What is new is that a language model occupies the executor role, and that the target state is sometimes something no declarative description can capture.
How it works in practice
The simplest form of this technique is a shell loop feeding the agent the same instruction file on every turn. The agent reads the project state, performs the next step, saves changes, and exits. The loop starts it again, and it reads the state once more, this time already changed by itself.
The key observation is why that works at all. The agent does not remember the previous turn, and it does not need to, because the entire state sits in the repository: code, tests, notes, a list of things to do. Memory moves from conversation context into the file system, and that is a resource which does not run out.
Newer implementations work differently and more cleverly. Instead of restarting the process, they intercept the moment the agent tries to finish, block that exit, and hand the instruction back. The loop then happens inside a single session, saving the time spent reloading project context.
The exit condition is the hardest part here, and it is what separates implementations. A naive loop spins forever, so you need a way to recognise the task is done: passing tests, an empty task list, an explicit declaration from the agent. The project in question advertises exactly that exit detection, and it is its main value over a loop you write yourself.
What you actually run
The first misunderstanding concerns how the instruction is given. Ralph does not take the task text as a call argument. It reads it from .ralph/PROMPT.md in the project directory, and the list of things to do from .ralph/fix_plan.md, so the invocation itself looks bare and is meant to.
cd my-project
ralph-enable # wizard detects the project type and creates Ralph files
ralph --monitor # the loop together with a tmux dashboardA turn of the loop has five steps: read the instruction from PROMPT.md, run Claude Code with the current context, record progress in the task list and logs, check the exit condition, and return to the start.
The exit condition is a dual one, and that is the core of this project. Finishing needs two things at once: at least two completion signals recognised in the response text, plus an explicit EXIT_SIGNAL: true in the status block the agent prints. Enthusiasm alone, along the lines of "phase complete, moving on", will not stop the loop.
The remaining exits are every item in fix_plan.md ticked off, too many turns spent solely on tests, and hitting Claude's five hour usage limit. Items placed under an Optional, Future, or Nice to Have heading do not block completion, which resolves the deadlock where the agent treats something as skippable while the loop waits for a tick.
Installation
The requirements are Unix ones, since this is a set of shell scripts: Bash 4.0 or newer, Claude Code installed, jq for reading status, git, tmux for the dashboard, and the timeout command from GNU coreutils, which on macOS has to be installed separately.
git clone https://github.com/frankbria/ralph-claude-code.git
cd ralph-claude-code
./install.shInstallation adds the ralph, ralph-monitor, ralph-setup, ralph-import, ralph-queue, ralph-migrate, ralph-enable, and ralph-enable-ci commands to your path. You do this once per machine, the cloned directory can then be deleted, and uninstall.sh removes everything.
One route does not exist here: no package under this name sits in the npm registry, so npm install -g will not work, and neither will pulling this project into your own code as a dependency. The version at the time of writing is 0.11.5, still ahead of a first stable release.
Configuration and limits
Project settings live in .ralphrc, which is a set of shell variables rather than a JSON document.
PROJECT_NAME="my-project"
CLAUDE_CODE_CMD="claude"
MAX_CALLS_PER_HOUR=100
MAX_TOKENS_PER_HOUR=0
CLAUDE_TIMEOUT_MINUTES=15
ALLOWED_TOOLS="Write,Read,Edit,Bash(git *),Bash(npm *),Bash(pytest)"
SESSION_CONTINUITY=true
SESSION_EXPIRY_HOURS=24
CB_NO_PROGRESS_THRESHOLD=3
CB_SAME_ERROR_THRESHOLD=5There are two limits and they act independently, both resetting hourly. The first counts calls and sits at a hundred by default. The second counts tokens and is off by default, since zero means no limit. That second one guards the bill, because a single call can burn more than a hundred thousand tokens, so a limit counted in calls says little about cost.
The permission boundary is set by ALLOWED_TOOLS, the tool list handed to Claude Code. There are no separate allowed and forbidden path lists here, so scope narrows through that list and through which directory the loop starts in.
Brakes
The circuit breaker cuts the loop after three turns without progress or five with the same error. It then sits open, tries to recover through an intermediate state after thirty minutes, and --circuit-status and --reset-circuit let you look inside and force the return by hand.
Claude's five hour usage limit is handled separately. On detecting it the loop asks whether to wait an hour with a countdown or to exit, and with nobody at the keyboard it picks waiting after thirty seconds.
A safety copy is not the default, and it is the setting to turn on immediately. The --backup flag creates a backup branch before every turn, and --rollback restores the state from it. Without that flag nothing reverts on its own, failing tests included.
ralph --calls 50 --timeout 30 --backup --notify
ralph --dry-run
ralph --statusWhere the tasks come from
The ralph-import command turns an existing requirements document into Ralph's structure, accepting markdown, plain text, JSON, Word documents, and PDFs. The same command pulls an issue from GitHub through --github-issue, and with filters by label, title, or assignee the --select flag decides which of the matches to take.
For larger volumes there is a queue. ralph-queue builds a persistent work list stored in .ralph/queue.json, and ralph --process-queue works through it in order and survives a restart. The loop can also close the circuit on the GitHub side: comment on progress every few turns, open a pull request, close the issue, and file a separate one for TODO markers left in the code.
Isolated execution exists too, useful with broad permissions. The --sandbox docker flag confines the loop to a container with resource limits and a network policy, while --sandbox e2b moves it to a cloud sandbox with its own cost cap.
Watching and measuring
A live view comes from ralph --monitor, which sets up a tmux session itself, or from ralph-monitor in a second terminal alongside a separately launched loop. Machine readable state sits in .ralph/status.json and logs in .ralph/logs/, where the main file rotates at ten megabytes and keeps four archives.
The --live flag prints the agent's output as it happens and mirrors it into .ralph/live.log, which is the simplest way to tell whether the loop is working or circling in place. A summary after the fact comes from ralph-stats, reading the metrics record in .ralph/logs/metrics.jsonl.
Ralph against the alternatives
| Trait | Ralph | Claude Code | Devin | GitHub Copilot |
|---|---|---|---|---|
| Mode of work | unsupervised loop on your machine | session driven by a human | agent in the vendor's cloud | suggestions and an agent in the editor |
| Exit condition | dual: signals plus EXIT_SIGNAL | end of the response | end of the task | none, continuous work |
| Reverting changes | backup branch once --backup is on | by hand in git | by hand in git | by hand in git |
| Usage brake | 100 calls per hour, optional token limit | subscription limits | plan allowance | plan credits |
| Licence | MIT | proprietary | proprietary | proprietary |
| Cost | zero, you pay for Claude Code | Claude subscription or API billing | 0, 20, and 200 USD a month, team 80 USD plus 40 USD per seat | 0, 10, 39, and 100 USD a month, 19 and 39 USD per user for organisations |
Troubleshooting
A loop that will not finish is nearly always waiting on one of two things: an unticked item in fix_plan.md or the absence of an explicit exit signal from the agent. The first is fixed by moving the item under an optional heading, the second by stating in the prompt exactly when that signal should be given.
A loop that finishes too early has usually run into an open circuit breaker. --circuit-status shows the state and the reason, --reset-circuit restores work, and --auto-reset-circuit does that on every start, which makes sense only for unsupervised runs.
The rest is tuning: --calls when hitting the hourly limit, --timeout for tasks longer than the default fifteen minutes, --verbose and --live when the run is opaque, --dry-run for a turn without paid calls.
FAQ
Can I leave Ralph unsupervised?
Yes, once four things are set: a token limit per hour rather than a call limit alone, an ALLOWED_TOOLS list narrowed to what the task genuinely needs, the --backup flag, and a separate branch. Notifications from --notify add a signal when the loop asks a question.
What does a run cost?
The project itself is free; you pay for Claude Code's work. The bill depends on the number of turns and the size of the context sent in each, and since one call can burn more than a hundred thousand tokens, the only credible forecast is measuring your own task across a few turns.
Is it safe on production code?
With care. A separate branch, a review before merging, and a narrow tool list are the minimum, and with broad permissions it is worth running the loop in a container through --sandbox docker so commands cannot reach past the project.
How does it handle large projects?
It takes context from files rather than from conversation memory, so repository size constrains it less than the length of a single step does. Session continuity is on by default and expires after a day, while --no-continue starts each turn from scratch, which suits tasks independent of one another.
Is there a vendor supported version?
Yes. The Claude Code repository holds the ralph-wiggum plugin, which implements the same idea through a stop hook: it blocks the session from exiting and hands the same prompt back. You start it with /ralph-loop, passing an iteration cap and a completion phrase, and cancel it with /cancel-ralph.
When the loop works and when it burns money
This is the most important section here, because the difference between the two outcomes follows from a few conditions you can check in advance.
The loop works when an automatic way of telling success from failure exists. A test suite, a compiler, a type checker, a validator. The agent can then check its own work and correct itself without a human, and every turn moves closer to the goal. The classic case is a migration touching hundreds of files: the rule is unambiguous, the result verifiable, and the tedium such that nobody wants to do it by hand.
The loop burns money when no such check exists. A task like "improve how the page looks" has no exit condition, so the agent will circle, making changes, reverting them, and making them again. Cost rises linearly with time; progress does not.
The second condition is step size. A task has to decompose into pieces each finishable in one turn. If a single step does not fit in context, the agent will never finish it, only restart it each time and abandon it halfway.
The third is state recorded outside the conversation, ideally in a format the agent recognises, such as a skill following the Agent Skills standard. A task list in a file, notes on what has been checked, entries in repository history. Without that, the next turn repeats the previous one's work, because the agent has no way of knowing something is already done.
Practical advice before running anything overnight: run the loop for five turns and read what came out. If five turns show progress in one direction, raise the limit. If they show circling around the same spot, no number of turns will fix that.
Costs and safeguards
The bill for this technique grows differently from what intuition suggests, so the mechanism is worth understanding.
Every turn sends the model a growing context: project state, file contents, command output. At twenty turns the cost is not twenty times the first, it rises faster, because more is sent each time. A task costing tens of cents in a conversation can cost tens of dollars in a loop.
A hard turn limit is therefore a necessary safeguard rather than an optional one. It is also worth setting a time limit and checking consumption on the provider's side during the run rather than after it.
The second safeguard concerns change scope. An agent working unsupervised on the main branch is a bad idea regardless of how good its decisions are. A separate branch, a review before merging, and a prohibition on touching deployment configuration are the minimum that lets you sleep.
The third is the boundary of what the agent may run. A loop executing commands without limits can delete a directory, push changes, or call an external service. Narrow permissions to what the task genuinely needs, and treat this exactly as you treat permissions in Claude Code during ordinary work.
The fourth, most often skipped, is output quality. Code written in an unsupervised loop tends to be formally correct and structurally poor: duplicated functions, workarounds instead of fixes, tests fitted to the implementation rather than to requirements. A review afterwards is mandatory here and usually takes longer than somebody running a loop for the first time expects.
The original technique is described in Geoffrey Huntley's article, and this implementation's code sits in the project repository.