THINK IN LOOPS
2-3 iterations. Stop. Review. Update context. Repeat.
The Workflow
Problem: A long agent run can compound a wrong assumption before the operator sees the code. The final diff shows the damage but not the iteration where the run drifted.
Solution: Slow mode. 2-3 iterations, then stop. Review the code. Update context. Repeat. The human is the checkpoint in the loop.
Ralph runs (2-3x) → Stop
↓
Review code
↓
Update context
↓
RepeatWhat's a Ralph?
Named after Geoffrey Huntley's concept: AI models are like Ralph Wiggum from The Simpsons. No memory. No plan. No continuity. Every moment is complete and isolated.
Every message is a fresh instance that only knows what you show it right now. That makes the supplied context one of the operator's direct control surfaces.
Every message is a new Ralph.
Why Slow Mode Works
When you let Ralph run unsupervised for 50 iterations, you're hoping. Wishing. You come back to either a miracle or a mess.
When you stop every 2-3 iterations:
- You see where Ralph is heading
- You correct course before it compounds
- You update the context with what you learned
- The next iterations are better informed
Time isn't saved. Time is spent differently. Instead of typing implementation, you're writing tests. Instead of debugging your code, you're examining what Ralph could see.
The Memento Problem
There's a movie called Memento about a man who can't form new memories. Every few minutes, he forgets everything. So he tattoos the important things on his body—the facts that must persist.
Your AI is this man. The context window is his mind. Everything you don't tattoo (include explicitly) doesn't exist.
The inversion: you are not the one without memory. The AI is. You're the handler. You're the one who writes the tattoos.
In slow mode, the "code review" step is where you write new tattoos. You see what Ralph did, you update AGENTS.md or your task list, you give the next Ralph better context than the last one had.
The Context I Can Change
The context window is the part of the run I can inspect and rewrite between iterations.
The model and tooling still matter, but neither can recover a constraint that never entered the context or disappeared during compaction.
Slow mode turns review into context maintenance: inspect the diff, record the missing constraint, and start the next run with a better board.
THE SIMPLEST IMPLEMENTATION
A GitHub Action that loops:
name: ralph
on:
push:
branches: [main]
workflow_dispatch:
jobs:
run:
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- name: Run Ralph
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
npm install -g @anthropic-ai/claude-code
# The context: everything Ralph can see
claude --dangerously-skip-permissions \
--print \
"$(cat AGENTS.md)"
- name: Guardrail - Something Must Change
run: |
if git diff --quiet; then
echo "Nothing changed. Loop failed."
exit 1
fi
- name: Continue Loop
run: |
git config user.name "ralph-bot"
git config user.email "ralph-bot@users.noreply.github.com"
git add -A
git commit -m "ralph: iteration"
git push # triggers next loopFresh context (checkout) → Ralph reads AGENTS.md → Ralph works → Guardrail checks for changes → Commit and push → Push triggers next iteration
The Guardrail
git diff --quiet
Did something change? Yes → continue. No → fail.
The loop enforces itself. You can't wish for a different outcome with the same inputs. If Ralph did nothing, that's not feedback—that's a broken loop.
Adding Backpressure
Tests are backpressure:
- name: Run Tests
run: npm test
- name: Guardrail
run: |
if git diff --quiet; then
echo "Nothing changed."
exit 1
fiNow Ralph must change things in a way that passes tests. The tests define the shape. Ralph fills it.
Adding a Kill Switch
- name: Check Kill Switch
run: |
if [ -f .ralph/PAUSED ]; then
echo "Ralph is paused."
exit 0
fiStop Ralph: touch .ralph/PAUSED && git push
Restart: rm .ralph/PAUSED && git push
Adding Failure Memory
Ralphs forget. The filesystem remembers:
- name: Record Outcome
if: always()
run: |
mkdir -p .ralph
if [ "${{ job.status }}" = "success" ]; then
echo "0" > .ralph/failures
else
FAILURES=$(cat .ralph/failures 2>/dev/null || echo "0")
echo "$((FAILURES + 1))" > .ralph/failures
if [ $FAILURES -ge 5 ]; then
touch .ralph/PAUSED
echo "Too many failures. Pausing."
fi
fi
git add .ralph/
git commit -m "ralph: record state" || true
git push || trueFive failures in a row? Ralph pauses itself.
The Core Loop
The loops in these examples share four parts:
- 1. Fresh context every cycle — Ralph is born again each time
- 2. Clear instructions — what should Ralph try to do?
- 3. The ability to act — Ralph must be able to change something
- 4. Observation — did it work?
- 5. A guardrail — something MUST change, or the loop failed
That last one is key: the loop must eat its own tail.
If Ralph runs and nothing changes, that's not neutral. That's failure. You can't observe without influencing. The concept validates itself.
Slow Mode vs Full Auto
Full auto:
ralph runs → ralph runs → ralph runs → ... → you check → ???
Slow mode:
ralph runs (2-3x) → you review → update context → ralph runs (2-3x) →
you review → ...
Full auto is gambling. Slow mode is steering.
The right tools for proper code review don't fully exist yet. So we slow down. We stay in the loop. We use our eyes as the checkpoint until better tooling catches up.
The Inversion
Old: I write code, tests validate it.
New: I write tests, Ralph fills in the code.
Old: I am the harness.
New: Tests are the harness. I observe.
Old: Debugging means tracing my code.
New: Debugging means examining what Ralph could see.
Same features. Built backwards.
The Existing Harness
"I could just write the code."
Sure. Then write the tests to make sure it's not broken. Then the guardrails in staging. Then the cascade of other tests as you add more features. Then production monitoring. Then alerts. Then rollback procedures.
A normal delivery process already contains parts of a harness.
CI/CD is a loop. Testing is a guardrail. Code review is a checkpoint. Deployment is a gate. Monitoring is observation.
The Ralph loop makes those checkpoints explicit and gives each new run the same route through them.
What I Want to Test Next
I want to see how much of the workflow can live in the repository: scoped tasks, checks, progress, and stop conditions.
Different coding agents can modify the same repo, but model behavior and tool support still change the result. The shared part is the artifact and the checks around it.
I spend more time on checks than I used to.
The harder part is writing tests that actually specify what you want. That's not trivial. But when you can define "done" clearly enough that a test can verify it, Ralph has a shot. When Ralph fails, you learn what was missing from the context or what the test didn't cover.
Patience
The loop also changes the pacing. I have to wait for a run, inspect what happened, and decide whether the next iteration has enough information.
That resembles ordinary debugging, but the actor performing the next change is different. The review step is where I recover context and update the constraints.
I am still learning how long to let a run continue and when another iteration only repeats the same mistake.
The Wall You'll Hit
Once you start doing this, another problem appears:
Observation.
You need to see what changed, why it changed, what failed, and what reality says. Without observation, loops turn into superstition.
I'm using gateproof.dev in my projects. It's just a collection of ideas for doing this end-to-end—observing what changed and validating against constraints. Not expecting many people to use it, but it works for me.
Automation without checkpoints is just a fast way to be wrong.
Slower loops. More deliberate steering. Code review as backpressure.
That's the workflow.