Back to blog
ralph for idiots: the only explanation you need

ralph for idiots: the only explanation you need

a no-mysticism guide to the ralph technique - why ai agents forget on purpose, and how to make that work for you.

·7 min read

everyone on my timeline is "ralph-pilled" right now.

but if you've ever let an ai coding session run for 40–60 minutes, you've felt this:

it starts repeating itself, undoing its own fixes, and confidently going in circles.

most explanations of ralph are either:

  • terminal priestcraft, or
  • "it's just a loop lol" (true, but missing the point)

geoffrey huntley coined and popularized the technique and wrote the canonical post. start there if you want the origin story and the philosophical framing.

this is the 5-minute, copy-paste, no-mysticism version.


ralph is not "an agent that remembers forever"#

ralph is the opposite: it's an agent that forgets on purpose.

in geoff's purest description, ralph is literally a bash loop that keeps starting over with fresh context:

while :; do cat prompt.md | agent ; done

same task. new brain each iteration.

the "memory" is not the chat. it's the filesystem + git.

if it's not written to a file, it doesn't exist.


the only insight that matters: context pollution#

every ai coding session has a context window (working memory). stuff goes in:

  • files it read
  • commands it ran
  • outputs it produced
  • wrong turns it took
  • half-baked plans it hallucinated at 2:13am

here's the cursed part: you can keep adding, but you can't delete.

failures accumulate like plaque. eventually you hit the familiar symptom cluster:

  • repeating itself
  • "fixing" the same bug in slightly different ways
  • confidently undoing its own previous fix
  • circular reasoning, but with commit rights

that's context pollution. once you're there, "try harder" doesn't work.

adding more instructions doesn't help. more tokens don't help. more patience doesn't help.

ralph doesn't try to clean the memory. it throws it away and starts fresh.


if you rotate constantly, how do you make progress?#

you externalize state.

the trick is simple:

progress persists. failures don't.

aspectcontext (bad for state)files + git (good for state)
lifespandies with the convoonly what you choose to write
persistencepersists forevercan't be edited
pollutionpolluted by dead endscan be patched / rolled back
reliability"memory" can driftgit doesn't hallucinate

each fresh agent starts clean, then reconstructs reality from files.


the anchor file (source of truth)#

every ralph setup needs a single source-of-truth file that survives rotations and tells a brand-new agent what reality currently looks like.

in my cursor implementation, that file is ralph_task.md:

---
task: build a rest api
test_command: "npm test"
---
 
# task: rest api
 
## success criteria
1. [ ] get /health returns 200
2. [ ] post /users creates a user
3. [ ] all tests pass

state lives in .ralph/:

  • guardrails.md: learned constraints ("signs")
  • progress.md: what's done / what's next
  • errors.log: what blew up
  • activity.log: tool usage + token tracking

the loop reads these every iteration.

fresh context. persistent state.

format doesn't matter. invariants do.


why the claude code plugin approach is accidentally anti-ralph#

let me be explicit: the claude code plugin approach is accidentally anti-ralph.

it keeps pounding the model in a single session until context rots. the session grows until it falls apart. no visibility into context health. no deliberate rotation.

claude code treats context rot as an accident. ralph treats it as a certainty.

ralph solves this by starting fresh sessions before pollution builds up. deliberate rotation, not accidental compaction.

the claude code plugin lets a single session grow until it inevitably rots, with no real visibility into when context has gone bad. ralph assumes pollution is coming and rotates deliberately before it happens.

instead of repeating the same mistakes over and over, ralph records failures as guardrails so they don't recur.

and while claude code locks you into a single model, ralph-technique should be flexible enough for you to use the right model for the job as conditions change.


why i built a cursor port (model selection matters)#

i built this because cursor lets you extend the agent loop like a real system (scripts, parsers, signals), and because model choice matters in practice.

different models fail in different ways. ralph lets you exploit that instead of being stuck with one failure mode.

cursor makes it trivial to swap models per iteration. different brains for different failure modes. this is deeply under-discussed compared to "one agent to rule them all."

practical guidance:

  • starting a new project → opus (architecture matters)
  • stuck on something weird → codex

i'm getting better results on some workloads with gpt-codex models than opus 4.5. vibes? tokenization? inductive bias? the gods? idk. but it's repeatable.

and yes, i've used this to port very large repos (tens of thousands of loc) to typescript without it faceplanting every 10 minutes. that's the whole point: long-running implementation work where humans become the bottleneck.


the architecture (cursor version)#

if you don't care about plumbing, you can skip this section. the only point is that vibes get turned into signals.

ralph-setup.sh (interactive ui, model picker)


cursor-agent --output-format stream-json


stream-parser.sh (parses output, tracks usage, detects patterns)

 ├── writes to .ralph/activity.log
 ├── writes to .ralph/errors.log

 └── emits signals:
     ├── warn (near context limits)
     ├── rotate (hard rotate now)
     ├── gutter (same failure repeatedly)
     └── complete (all checkboxes done)

key features:

  • accurate, practical token tracking (a proxy, not tokenizer theology)
  • gutter detection (same command fails repeatedly, file thrashing)
  • real-time monitoring via logs
  • interactive model selection

none of this is magic. it's just turning "it's losing it" into mechanics.


quick start (3 commands, no incense)#

repo: ralph-wiggum-cursor

1) install#

curl -fsSL https://raw.githubusercontent.com/agrimsingh/ralph-wiggum-cursor/main/install.sh | bash

this creates .cursor/ralph-scripts/ and initializes .ralph/.

2) write the anchor file#

cat > ralph_task.md << 'EOF'
# task: build my thing
 
## success criteria
1. [ ] first thing
2. [ ] second thing
EOF

3) run ralph#

./.cursor/ralph-scripts/ralph-setup.sh

optional: watch it like it's a fish tank.

tail -f .ralph/activity.log

guardrails: how ralph stops repeating the same dumb mistake#

ralph will do something stupid. the win condition is not "no mistakes."

the win condition is the same mistake never happens twice.

when something breaks, the agent adds a sign to .ralph/guardrails.md:

### sign: check imports before adding
- trigger: adding a new import statement
- instruction: check if import already exists
- added after: iteration 3 (duplicate import broke build)

guardrails are append-only. mistakes evaporate. lessons accumulate.

next iteration reads guardrails first. cheap. brutal. effective.


"isn't this just slop?"#

fair concern.

there are two modes of development:

  1. exploration — figuring out what to build, experimenting, making architectural decisions
  2. implementation — building the thing you've already designed

ralph is for #2.

if you're exploring, use interactive mode. be deeply involved. make creative decisions.

but once you know what you're building - a rest api with these endpoints, a cli with these commands, tests for these functions - that's implementation work.

that's where ralph shines. long-running implementation work where humans become the bottleneck.


the technique is simple. the insight is simpler: context pollutes, so rotate deliberately. everything else is plumbing.