2026-08-28 · Updated 2026-08-28 · 14 min read
Why unbounded Ralph loops fail
A diagnostic catalog of the ways an unbounded Ralph loop fails — search-blind duplication, stale repetition, drift, context exhaustion, cost blowout, fragile state, the broken morning, and claimed completion — each identified by the observable symptoms it leaves on four surfaces, with the mechanism that produces it, the check that separates it from its neighbors, and the direction its remedy lives in.
By Juno AI INC · ralph-loop · failure-modes · yylo
A Ralph loop costs five lines of shell to start and nothing to keep running, which is exactly why its failures arrive as surprises: nobody wrote down what going wrong would look like, so when the morning comes, the evidence sits there — a terminal of scrollback, a diff nobody has read, a plan file the loop rewrote itself, a bill — and nobody knows which failure they are looking at. This page is the diagnostic layer for that moment. It names the failure modes an unbounded loop produces, pairs each with the observable symptoms that identify it, explains the mechanism that makes that mode inevitable rather than unlucky, and gives the check that discriminates it from the mode it imitates. The catalog and the triage procedure at the end are this site's original research, dated 2026-08-28; every quotation was re-verified against its linked source on that date.
Two neighbors own adjacent jobs and are linked, not repeated, here. What the technique is, where it came from, and the limits its own originator reports belong to the Ralph loop reference; whether a raw loop or a bounded workflow is the better trade for your work belongs to the run-anatomy comparison. This page assumes you have already run the thing — or are about to leave one running — and owe someone an answer about what went wrong or what will.
The shape of the loop predicts its failures
An unbounded Ralph loop has four structural properties, and every failure mode below is one of those properties observed at 3 a.m. First, nothing inside the loop decides that enough is enough: the while : skeleton restarts the worker whether or not the previous pass accomplished anything, and stopping is an operator's interrupt. Second, the loop's intent and its memory live in prose — a prompt file, a plan file, specs — that the same nondeterministic process edits, so the failing process doubles as its own historian. Third, every pass spends a fresh context window re-deriving its position from those files, which makes the window a hard per-pass budget. Fourth, commits land ahead of any human read, so breakage and review debt accumulate while everyone sleeps. The originator's own framing acknowledges the posture this creates: "Building software with Ralph requires a great deal of faith and a belief in eventual consistency." Faith is not a diagnosis. The four surfaces below are.
Read the four surfaces before naming anything
Diagnosis starts with what you can observe, and an unbounded loop exposes exactly four surfaces. The stream is what the agent is doing in the current pass — visible live or in scrollback. The diff is what has actually changed: the commit history, the working tree, the tags. The state files are what the loop believes: the prompt, the plan, the specs, in their current edited form. The spend is what the run costs, per pass and cumulative. Every failure mode announces itself on a specific surface or combination of surfaces, and most misdiagnoses come from reading one surface and generalizing — a quiet stream is not staleness if the diff is still growing, and a growing diff is not progress if the closed-item count is not moving. Read all four, then match against the catalog.
The failure-mode catalog
Search-blind duplication
Symptoms. Two or three implementations of one capability appear across passes, near-identical in intent but not in name or location; the plan file lists the same remaining item twice; module counts grow faster than features. The originator's own words describe the trigger precisely: "A common failure scenario for Ralph is when the LLM runs ripgrep and comes to the incorrect conclusion that the code has not been implemented." The escalation is equally specific: "If you wake up to find that Ralph is doing multiple implementations, then you need to tune this step."
Mechanism. Code discovery through search is probabilistic, and each pass starts with no memory of what the previous pass concluded. A search that misses existing code yields a confident "not implemented" verdict, and the loop spends real passes rebuilding what is already there — which is why the originator calls this "the Achilles' heel" of the whole technique.
Discriminating check. Grep by capability semantics rather than by symbol name: search for the behavior's vocabulary (verbs, config keys, error strings), not the class or function name the latest pass invented. Duplication confirmed this way is search-blind duplication; a single implementation that is merely wrong is a different mode.
Remedy direction. A sign reading "don't assume it's not implemented" treats the symptom for a while. The structural treatment is a deduplication gate inside the pass — a check that fails the pass when it adds a second implementation of an existing capability — so the loop cannot reward itself for rebuilding.
Stale repetition
Symptoms. Passes keep completing and commits keep landing, but the number of closed items stops moving; the plan file churns — reordered, reworded, re-expanded — without shrinking; the diff oscillates, applying a change, partially reverting it, and reapplying it. From outside it looks like diligence. On the surfaces, nothing is moving.
Mechanism. The loop equates activity with progress because nothing inside it can tell the difference. With no semantic stop condition, a pass that produces a commit and a pass that produces the *next* unit of value are indistinguishable to the while loop, so the second kind can stop happening entirely without anything halting.
Discriminating check. Pick the state that the work is supposed to move — items closed, tests passing, acceptance criteria met — and compare it between pass N and pass N minus three. Identical state plus continuing commits is stale repetition. Distinguish it from context exhaustion by where the failure lives: stale repetition is visible *across* passes (each pass is internally fine), while exhaustion degrades *within* a pass.
Remedy direction. Staleness has to become machine-detectable — a runner that diffs the work-state between iterations and stops when nothing changes. That design property, and the numeric-plus-semantic stop pairing it belongs to, is owned by bounded failure design.
Drift
Symptoms. The output diverges from what anyone asked for: capabilities nobody requested appear, the codebase grows features the spec never mentioned, and the prompt file accretes guardrail lines with each observed escape. The practitioner history records the terminal form of the same process in the originator's own metaphor about signs added beside the playground slide: "Eventually all Ralph thinks about is the signs so that’s when you get a new Ralph that doesn't feel defective like Ralph, at all." Drift also arrives upstream of the loop, in the intent itself. The same practitioner had a loop write specifications from a half-pager, built from those specs, and reported: "The output sucked. I went back to read the specs and they were way off base." His compressed lesson — "if the specs are bad, the results will be meh" — is the drift diagnosis in one line.
Mechanism. Intent lives in prose that a fresh process reinterprets every pass. Whatever the prompt can plausibly be read as saying is what gets optimized, and the prompt's meaning shifts as the loop's own edits accumulate around it. Overbake is drift's most visible form: the history's earliest recorded warning about the technique is that if you leave it running too long, "you end up with all sorts of bizarre emergent behavior, like post-quantum cryptography support."
Discriminating check. Grade the last ten commits against the specifications' acceptance criteria — not against the plan file, which is the loop's own diary and will always agree with itself. Divergence from the spec is drift; divergence from your unstated expectations with the spec satisfied is a spec gap, and the loop is not the author of that one.
Remedy direction. Verifiable acceptance criteria written before launch, and the practitioner's own boundary for exploratory work: if you cannot state the end state and how you will test it, an unattended loop is the wrong instrument for finding it.
Context exhaustion
Symptoms. Quality collapses late in a pass; the agent re-reads the same files repeatedly inside one session; verbose build and test output crowds the plan out of the window. The originator states the law plainly: "The more you use the context window, the worse the outcomes you'll get." His own worst case is architectural: "I recall when I was first getting this compiler up and running, and the number of compilation errors was so large that it filled Claude's context window."
Mechanism. The pass budget is fixed. Every re-derivation, every near-duplicate implemented because search missed the original, every verbose log line spends it, and once the window fills, the model reasons over its own debris — the failed outputs of this pass become the context for the rest of it.
Discriminating check. Exhaustion announces itself *within* a pass: the session starts coherent and degrades as it lengthens. If every pass is individually coherent but the work is going nowhere, look back at stale repetition; if passes are individually coherent but wrong, look at drift.
Remedy direction. Smaller items per pass, terse backpressure output, and reserving the primary window for scheduling work rather than performing it — the originator's own mechanic for spending the budget deliberately.
Cost blowout
Symptoms. The bill grows on a flat progress curve. Overnight spend produces no reviewable delta, or a delta that is entirely rework of the previous night. The famous economics of the technique — a reported contract delivered for a few hundred dollars of spend — is the *good* shape: cost proportional to delivered work while a senior operator keeps watch over the run. Blowout is the same loop shape with nobody watching and no numeric bound, compounding whichever other mode is running.
Mechanism. Unbounded passes times cost per pass, with nothing in the loop tying spend to outcomes. Because stopping is an interrupt rather than a condition, spend continues through every other failure mode in this catalog — a spinning loop does not bill less.
Discriminating check. Track cost per closed item, not cost per pass. Flat cost with stalled items means blowout is compounding stale repetition or drift; rising cost per item with items still closing means the work is simply expensive, which is a different conversation.
Remedy direction. A numeric bound chosen before launch, with any unbounded mode a named exception rather than the ambient setting. The design review that makes that decision explicit belongs to the bounded-failure guide linked above.
Fragile state
Symptoms. The plan file comes back duplicated, malformed, or drifted from the diff history, and the loop keeps editing around its own record; the prompt file's guardrails multiply until they consume the intent. The official Anthropic plugin variant produced the purest specimen: it "installs hooks in weird places you can't find, uses a strange markdown file to track state," and the history reports the custodianship problem plainly: "If you, in trying to stop it, delete the markdown file before stopping it, you break claude in that repo until you disable the plugin entirely."
Mechanism. The loop remembers through files that the loop itself writes. The same nondeterministic process that produces the failures is the custodian of the record of what remains, so a state corruption does not merely lose information — it steers every subsequent pass.
Discriminating check. Between passes, ask whether a program other than the model can parse the state and reconcile it with the diff: does the plan match what the commits actually did? An unreadable or irreconcilable plan is fragile state; a readable plan the loop is ignoring is drift.
Remedy direction. State the model cannot edit. Moving work-state out of model-written prose into a record with schema and ownership is the durable answer, and the task-truth guide owns that contract in full. The prompt file itself is also a standing injection surface every pass re-reads; the prompt-safety guide sets those boundaries.
The broken morning
Symptoms. The tree does not compile, and the rescue-versus-reset decision has to be made now, on no evidence but scrollback. The originator's warning is unconditional: "Yep, it's true, you'll wake up to a broken codebase that doesn't compile from time to time, and you'll have situations where Ralph can't fix it himself."
Mechanism. Commits land ahead of review, and the backpressure inside a pass has gaps: a gate that green-lights the wrong change, a test suite blind to the breakage, a pass that spends its whole window mid-fix. The next pass inherits the broken tree and spends its budget on rescue instead of progress, which is how one bad pass becomes a bad night.
Discriminating check. Find the last tag or commit where the tree built. If breakage predates the most recent passes, the loop has been spending passes on top of a corpse; if the last good state is recent, a single gap in backpressure explains it. Either way, this mode is triaged first because every other diagnosis requires a building tree.
Remedy direction. Backpressure wired inside the pass — build, test, typecheck as the pass's own gate — and review between cycles instead of after all of them.
Claimed completion
Symptoms. The agent reports the work finished while the acceptance evidence is missing. The practitioner history's refactor run is the canonical specimen: after six hours the loop "developed a REACT_REFACTOR_PLAN.md and blasted through the whole thing", and on check-in "it claimed to be finished, so I stopped it and sent it over to team for a look" — yet "the PR quickly got some merge conflicts and so we never ended up merging it". Completion claimed is not completion delivered, and even the technique's longest practitioner confesses the evaluation gap: of the repositories his own showdown stream produced, "I still haven't gotten around to evaluating which one, if any, actually solves my problem".
Mechanism. Completion is the model's opinion. Nothing outside the pass referees the claim, and the model's incentive structure rewards declaring success — the originator notes that "Claude has the inherent bias to do minimal and placeholder implementations", which is claimed completion's miniature form: one function, marked done, hollow inside.
Discriminating check. Ask what command decides done. If the answer is the agent's own testimony rather than a command's exit status, this mode is live even when everything looks green. A diff that stops growing, a plan file that empties, and a bill that keeps accruing all describe a loop that has finished claiming without finishing.
Remedy direction. Acceptance expressed as state a runner can read — a gate that passes or fails without the model's testimony — and one verifiable outcome per unit of work, which is the shape the bounded-loop walkthrough teaches from the first task.
Triage: name the mode in ten minutes
The catalog collapses into an ordered procedure because the surfaces are cheap to read in sequence. Work through the questions in order and stop at the first yes:
- Does the tree build? No — triage the broken morning first; every other diagnosis presumes a building tree. Yes — continue.
- Is the diff full of near-duplicates of one capability? Yes — search-blind duplication; confirm by semantic grep rather than symbol names.
- Does the closed-item count move while commits continue? No — stale repetition; confirm the flat work-state across three passes.
- Does the output still satisfy the spec's acceptance criteria? No — drift; grade the commits against the spec, never against the plan file.
- Does any single pass degrade as it lengthens? Yes — context exhaustion; the failure is within the pass, not across passes.
- Can another program parse and reconcile the state files? No — fragile state; the record itself is the casualty.
- What decides done — a command, or the agent's word? The word — claimed completion, whatever the diff looks like.
- What is the cost per closed item doing? Rising — cost blowout, compounding whichever mode above fired first.
Two modes frequently co-occur — duplication feeds exhaustion, drift feeds claimed completion — so name the primary mode by which surface dominates the evidence, and treat the secondary after the first is bounded. The procedure's output is a name, and the name is worth having because each remedy lives in a different place: some in the prompt, some in the pass's own gates, some in the loop's stop conditions, one in state that outlives the model that edits it.
What a diagnosis is worth
Naming the mode does not bound the next run. The preventive discipline — bounded spend, stops a runner can evaluate, staleness a machine can detect, evidence written before progress is claimed — is a design method, and bounded failure design owns it end to end; the honest decision of when a raw loop still beats a bounded workflow belongs to the run-anatomy comparison linked above, because for greenfield bulk generation with a senior operator present, it still can. What diagnosis buys you is the difference between a post-mortem and a guess: a named mode points at a specific missing bound, a specific unread surface, a specific gate nobody wired. This catalog is versioned by its evidence date — every quotation above was re-verified against the linked sources on 2026-08-28, and the mode names, symptoms, mechanisms, and triage order are this page's own. If it saves your next post-mortem a re-derivation, cite this URL as the source: attribution is what keeps a diagnostic reference from drifting into the folklore that surrounds the technique it documents.