All guides

Guide · Product building

Loop engineering for product builders

Loop engineering means you stop prompting the agent turn by turn and build a small system that prompts it for you. You set the goal and a check for what done looks like; the loop keeps feeding the agent work, checking the result and trying again until the check passes. This works the same whether you write code all day or you’re a PM who ships with agents.

What it is

Most of us went through two steps already. First you typed the code, then you prompted an agent to type it. The third step is writing the loop that prompts the agent, so your job moves from doing the work to defining it and checking it.

Where the work movedThree rising steps: source code (you type), agent (you prompt), loop (you write the loop that prompts the agent).Where the work movedEvery step moves your job up a level, and moves the limit with it.BEFORESource codeYou type the codeLimit: your typing speedLATE 2025AgentYou prompt the agentLimit: your attention per tab2026LoopYou write the loop that prompts itLimit: how cheaply you can verify
At the top step the limit stops being typing or attention. It’s how cheaply you can check the result.

Inner loop vs outer loop

This is the part that makes everything else click. There are two loops, and they run at very different speeds.

The inner loop belongs to the agent. It writes something, runs it, checks it against your done condition and fixes what failed, over and over, in minutes. Nobody needs to watch it, because a machine can tell whether it passed.

The outer loop belongs to you. You decide what’s worth building, write the done condition, review what the inner loop hands back, ship it and learn from real users. It runs over days or weeks, and a person has to judge every turn of it.

Inner loop vs outer loopAn outer loop run by you (decide, define done, review and ship, learn) wraps an inner loop run by the agent (write, run, check, fix).Inner loop vs outer loopThe agent runs the inner loop in minutes. You run the outer loop over days.DecideWhat's worth buildingDefine doneA check a machine can runReview + shipRead the report, mergeLearnUsage, feedback, signalWriteRunCheckFixOUTER LOOP · YOUdays to weeks · people judgeINNER LOOP · AGENTminutes · machines checkInner loop: write, run, check, fix. Stops on your done condition or the iteration cap.Outer loop: pick the problem, define done, review what came back, learn from real users.
The inner loop is fast because a machine checks it. The outer loop is slow because a person has to.

The usual way to get burned is mixing the two up: trying to automate the outer loop (“build me the right product”), or babysitting the inner loop by hand and approving every edit. Automate the inner loop hard, and keep the outer loop yours.

What’s inside a good inner loop

A trigger starts it, a maker agent does one unit of work, and a separate checker agent proves it’s done. Failures go back to the maker, passes come to you as a short report. Memory lives in files, not in the chat, because the agent forgets between runs and the repo doesn’t.

Anatomy of a loopTrigger starts a maker agent, a separate checker agent verifies, failures loop back to the maker, passes go to you as a short report. Memory lives on disk underneath.Anatomy of a loop worth schedulingAddy Osmani's building blocks, arranged around the part that holds it up: the checker.TRIGGERSchedule or event/loop · routine · cronGitHub event, new ticketMAKER AGENTOne unit of workown worktreeskills + connectorsCHECKER AGENTProves it's doneruns the actual thingnever grades own workTO YOUGlanceable resultpass / fail + evidencereadable on a phonefail → try againMEMORY, OUTSIDE THE CHATCLAUDE.md · skills · progress file · ticket board. The agent forgets between runs; the repo doesn't.Write the stop condition before it runs, cap iterations and tokens, and keep the maker away from the checker.
The checker is what lets you walk away. An agent grading its own work tends to let itself off easy.

The simplest inner loop: Ralph

Geoffrey Huntley’s Ralph Wiggum technique is the easiest way to see this. It’s a bash loop that feeds the same PROMPT.md to a fresh agent every pass. The agent reads the plan from disk, does one task, writes progress back, commits and exits, and the loop starts it again. When it keeps failing the same way, you don’t jump in and drive; you fix the prompt and let it run.

The Ralph loopA bash loop restarts a coding agent with a fresh context each pass: read prompt and plan, pick one task, build and check, write progress to disk and exit.The Ralph loopGeoffrey Huntley, 2025. A dumb loop, a fresh agent every pass, memory on disk.while :; do cat PROMPT.md | claude ; done1Fresh agent startsReads PROMPT.md + plan2Picks one taskMost important open item3Builds + checksRuns tests and the app4Writes back, exitsUpdates plan, commitsON DISKPROMPT.md · plan.mdprogress notes · gitStops when the agent prints the completion promise, or at --max-iterations. Your job: tune PROMPT.md.
One line of shell. The prompt and the files on disk carry everything between passes.

Set up your first loop today

You can have this running in under an hour. Pick something small with an obvious check, like a ticket with clear acceptance criteria or a set of failing tests.

1. Write the plan and the prompt

Create two files in your repo. The plan is the task list the loop works through; the prompt tells every fresh agent how to behave.

# plan.md
## Goal
Users can reset their password from the login screen.

## Done when
- [ ] npm test passes
- [ ] "Forgot password" link visible on /login
- [ ] Reset email sends in the local dev mailer

## Tasks
- [ ] Add reset token table + migration
- [ ] POST /auth/reset-request endpoint
- [ ] Reset form UI
- [ ] Tests for expired and reused tokens

## Notes from previous passes
# PROMPT.md
Read plan.md. Pick the single most important unchecked task.
Do only that task. Then run npm test and npm run lint and fix
anything they catch. Check off the task, add one line under
"Notes from previous passes" about what you learned, and commit.
If every box under "Done when" is checked, write STATUS: DONE
at the top of plan.md. Do not start a second task.

Not everything has a test suite. If your loop writes posts, reports or specs, “Done when” still needs checks a machine can run:

CheckExample
Count or limitUnder 200 words, five bullets max
ContainsMentions the price and links the source
FormatValid JSON, matches the template’s headings
RubricA separate reviewer scores it 1–5 against your criteria
YouThe fallback for taste and judgment, so keep these few

2. Run it with a cap

Run it on a branch so a bad pass is easy to throw away. Every pass is a fresh claude -p call, so the agent starts clean and only knows what’s in the files. The caps matter: 20 passes, 40 turns and $3 per pass, because a loop with no ceiling is a token bill with no ceiling.

# ralph.sh  (run on a branch)
for i in $(seq 1 20); do
  claude -p "$(cat PROMPT.md)" \
    --allowedTools "Read" "Edit" "Write" "Bash(npm test *)" "Bash(npm run lint *)" "Bash(git *)" \
    --max-turns 40 --max-budget-usd 3
  grep -q "STATUS: DONE" plan.md && echo "Done after $i passes" && break
done

Inside Claude Code you can skip the script, with one difference: these run inside a single session, so context builds up instead of resetting each pass. The Ralph plugin uses a stop hook to feed the same prompt back until the agent outputs your completion phrase. /goal keeps going until a condition is true; a separate small model judges it after each turn, but only from what shows up in the conversation, so write the condition as something Claude can prove by running a command. Use auto mode if you want either one to run without stopping for approvals.

/ralph-loop "Follow PROMPT.md. When plan.md says STATUS: DONE, output <promise>DONE</promise>" --max-iterations 20 --completion-promise "DONE"

/goal npm test exits 0 and npm run lint is clean, or stop after 20 turns

3. Add a checker

Once the basic loop works, split the grading out. Right now the same agent writes the code and checks its own boxes, which is fine for a first run but not for anything you’ll walk away from. Make a second agent whose only job is to verify against “Done when.” In Claude Code that’s a subagent file with no edit tools.

# .claude/agents/checker.md
---
name: checker
description: Verifies finished work against "Done when" in plan.md. Use before marking anything done.
tools: Read, Grep, Glob, Bash
---
You verify, you never fix. Read "Done when" in plan.md, run the
checks it names, and report PASS or FAIL per item with the evidence.
Do not edit, create or delete files.

It has Bash so it can run tests, which means “never fix” is an instruction, not a hard lock. If you want it truly read-only, drop Bash and have it read the test output the maker saved.

4. Put it on a schedule

For recurring work, /loop reruns a prompt on an interval while your session stays open (recurring loops expire after seven days). For anything that should survive a closed laptop, use a routine, which runs in the cloud on a schedule of an hour or longer. Good first schedules are boring ones: a morning digest, a PR babysitter, a nightly test fixer. Not in a terminal? Scheduled tasks in the Claude app give you the same idea without any code.

/loop 30m check open PRs, rebase any that are behind main, fix failing CI, report what changed

5. Run the outer loop

Read the report, not the diff stream. When the loop fails the same way twice, don’t fix it in chat; add a line to PROMPT.md, CLAUDE.md or a skill so every future pass knows. That habit is how the loop gets better every week instead of making the same mistake forever.

What to put in a loop

Before anything gets a schedule, ask one question: who verifies the result, and what does that check cost? Hard work with a cheap check goes in the loop first. Easy work with an expensive check stays a draft that you decide on.

What to put in a loopA table of work sorted by verification cost: digests and ticket hygiene run unattended, spec breakdown and builds run with a checker, PRDs are draft-only, strategy never.What to put in a loopSort the work by who verifies the result and what that check costs.WORKWHO VERIFIESCHECK COSTVERDICTMonitoring + digestsErrors, competitors, user feedbackNobody. It informs, never actsfreeLoop it tonightFix failing tests or CILint, types, flaky testsThe test suite itselffreeLoop it tonightBuild a ticket with clear ACOne task per passTests + agent runs the appcheapLoop + checkerSpec → ticketsBreak an approved spec downChecker maps each AC to a testcheapLoop + checkerFeature with fuzzy scopeNo clear definition of doneYou, reading the diffexpensiveDraft onlyStrategy + architectureWhat to build, how it fitsHumans, over monthsprohibitiveNeverA hard task with a cheap check gets automated before an easy task with an expensive one. Difficulty isn't the deciding column.

How I run mine

My loop stackAn outer loop run by me contains a signal loop, a human decision gate, a spec loop and a build loop, with shipped work feeding new signal. A mistake loop underneath turns repeat failures into skills.My loop stackInner loops run on their own. The outer loop is mine.OUTER LOOP · MESIGNAL LOOPScrape + digestCompetitor posts andfeedback, every morningread-only, nothing to breakMEDecide the betRead the digest,choose one problemhuman gateSPEC LOOPIdea → PRD → spec→ tickets, one skillper stepI approve PRD + specBUILD LOOPRalph on ticketsOne ticket per pass,checker runs the appI merge the PRship → new signalWhere I stay in the loop. Everything else runs without me.MISTAKE LOOP, UNDER ALL OF ITWhen any loop fails the same way twice, the fix goes into a skill or CLAUDE.md, not into the chat.
Inner loops run on their own. The blue dots are the only places I’m required.
  • Signal loop. A content-intelligence pipeline scrapes competitor posts and an LLM step writes a digest. It’s read-only, so the worst case is a stale summary.
  • Spec loop. A pack of product skills takes an idea through PRD, spec and tickets, one skill per step. The skills draft and push back; I approve the PRD and the spec.
  • Build loop. Approved tickets go to my agent software factory, one ticket per pass with a checker that runs the app. I merge the PR, and I’m wiring an orchestrator on a home machine so I can kick these off from my phone.
  • Mistake loop. Repeat failures become skill edits. My last skill audit fixed five skills, mostly YAML errors, script bugs and skills contradicting each other.

What I’d recommend

  • Start with one inner loop this week. A ticket with clear acceptance criteria and a test suite is the perfect first target.
  • Write “Done when” before you write the prompt. If you can’t say how a machine would check it, it isn’t ready for a loop. PMs already have this muscle from writing acceptance criteria.
  • Run it by hand for a week before you schedule it. You’ll find the checks you forgot while you’re still watching.
  • Make your first scheduled loop read-only. Digests and monitors can’t break anything, and they teach you what good loop output looks like.
  • Keep the maker and the checker apart. Different instructions, read-only tools for the checker, and a stronger model where it’s worth paying for.
  • Anything irreversible needs your yes. Sending, posting, paying, deleting or contacting someone always stops for approval, no matter how good the loop gets.
  • Cap every loop. Iterations, a dollar budget (--max-budget-usd in headless runs) and a branch or worktree you can delete.
  • Protect the outer loop. Read what shipped, talk to users and decide what’s next yourself. The faster the inner loop runs, the more that judgment is the whole job.

Try it yourself tonight

Paste this into Claude Code, or into the Claude app if you don’t write code. It interviews you, turns your idea of “done” into real checks, writes the loop files and runs one pass while you watch. After that first run, you’re the outer loop: read the report, fix whatever it got wrong in the prompt and run it again.

Loop starter prompt
I want to set up my first agent loop. Act as my loop engineer and walk me through it.

STEP 1 — Ask me these one at a time. Wait for each answer.
1. What task do I want done, either until it's finished or on a repeat?
2. Is it code (a repo with tests) or non-code (writing, research, reports)?
3. What does "done" look like? Push back until it's something a machine could check.
4. What must never happen without my approval? (sending, posting, paying, deleting, contacting anyone)

STEP 2 — Turn "done" into 3 to 6 checks.
- Code: real commands, like "npm test exits 0".
- Non-code: checks like a word limit, must contain X, matches a format, or scores 4+ out of 5 on a rubric graded by a separate reviewer.
- Mark any check only I can judge.
Show me the checks and wait for my OK before moving on.

STEP 3 — Create three files:
- plan.md: Goal, Done when (the checks), Tasks (small enough for one per pass), Notes from previous passes.
- PROMPT.md: read plan.md, do only the most important unchecked task, run the checks, add one line of what you learned, then stop. Never take an action on my approval list.
- checker.md: instructions for a separate reviewer that only verifies "Done when", reports PASS or FAIL per check with evidence, and never edits anything.

STEP 4 — Run one pass yourself while I watch. Then run the checker and show me its report.

STEP 5 — Give me the exact way to run it without me:
- Code: a capped loop for Claude Code (max 10 passes, a budget cap, on a new branch).
- Non-code: how to put it on a schedule.
Then tell me the one thing I should look at after the first unattended run.

Keep every step short and plain.

Start with something small and safe, like a daily digest or one ticket with tests. If the first run goes sideways, that’s the loop doing its job: it shows you which check you forgot.

Practical AI for founders & builders.

Get the next guide when it ships, plus the systems and skills behind it.