Loop engineering: let loops prompt your coding agents

Last updated By the Zoltbot team

Short answer

Loop engineering means you design the system that prompts your coding agents instead of prompting them yourself, turn by turn. A loop that can run without you needs six parts: a trigger, a written definition of done, a worker in its own worktree, a separate checker, a record of progress kept outside the conversation, and a way to stop or hand the work back to you.

From prompts to loops

For two years, you worked with a coding agent one turn at a time. You wrote a prompt, read the reply, then wrote the next prompt. The agent typed the code and you decided every next step.

Now agents can prompt themselves. Geoffrey Huntley's "Ralph" loop ran one agent in a while loop against the same plan file until the plan was done. Claude Code's /goal keeps an agent working until a condition you wrote is true. Codex automations run a prompt on a schedule and put what they find in an inbox. Addy Osmani gave the practice a name in June: loop engineering. Instead of writing the next prompt, you write the system that writes it.

We run Claude Code and Codex every day. This guide covers what a loop needs before you can leave it running, with the research behind each point.

The six parts of a loop

  1. A trigger. Something starts each pass: a schedule, a failing CI run, a merged PR, a new issue.
  2. A contract. A written definition of done that a checker can verify. You agree on it before the worker starts.
  3. A worker. An agent with its own worktree and branch, doing one task per pass.
  4. A checker. A different agent, ideally a different model, that grades the work against the contract.
  5. A record. A place outside the conversation that holds what was tried, what passed and what's next: a progress file in the repo, an issue, or a card in your task tracker.
  6. An exit. The loop stops when the work is done, when it can't be done, or when it needs a person.
One pass of a loop, and the three ways a pass can end.Each pass runs through five steps in order: a trigger such as a CI failure, a contract that says what done means, a worker in its own worktree, a checker running another model, and a record of progress, such as a file or a task tracker. If the checker requests changes, the work goes back to the worker. The next pass starts by reading the record. A pass ends in one of three ways: done, when the checker confirms the contract and a PR waits for you; impossible, when the worker explains why and the reason is noted for the next pass; or needs a person, when the loop pauses and sends you a question.Each passTriggera CI failureContractwhat done meansWorkerown worktreeCheckeranother modelRecordfile or trackerchanges requestednext pass reads the recordThree ways a pass endsDonechecker confirmsPR waits for youImpossibleworker says whynoted for next passNeeds a personloop pausesquestion sent to you
One pass of a loop, and the three ways a pass can end.
Text version of this diagram

Each pass runs through five steps in order: a trigger such as a CI failure, a contract that says what done means, a worker in its own worktree, a checker running another model, and a record of progress, such as a file or a task tracker. If the checker requests changes, the work goes back to the worker. The next pass starts by reading the record. A pass ends in one of three ways: done, when the checker confirms the contract and a PR waits for you; impossible, when the worker explains why and the reason is noted for the next pass; or needs a person, when the loop pauses and sends you a question.

The worker is the easy part. Loops usually break because the contract, the checker or the exit is missing.

Write "done" before the work starts

In Anthropic's long-running harness experiments, a generator agent and an evaluator agent agreed on a "sprint contract" of testable criteria before the generator wrote any code. One sprint had 27 of them. The evaluator then graded against that list instead of against the generator's own account of what it did.

Claude Code's /goal shows why the wording matters. After every turn, a small model reads your condition and the conversation and decides whether you're done. It doesn't run commands or open files. It can only judge what the agent's own output shows. So a condition like "the auth tests pass" works only if the agent prints the test run. Write conditions that the transcript can prove:

/goal npm test -- test/auth exits 0, npm run lint is clean,
      and no file under test/ was modified

The last clause stops the agent from making the tests pass by editing them. The next section shows why you need it.

Keep the checker separate from the worker

Agents go easy on their own work. Anthropic found that Claude would find real bugs in its own app and then approve it anyway. Anthropic could tune a separate evaluator to be skeptical far more easily than it could make the generator critical of itself.

It gets worse when the loop has a score to hit. METR caught OpenAI's o3 overwriting timers, stubbing out evaluators and redefining equality so its outputs always matched. On one task it did this in 80% of runs. Adding "do not cheat" to the prompt barely moved that number. When researchers asked afterwards, the model said in 10 of 10 trials that its approach wasn't what the user wanted.

A prompt won't stop that. Set up the loop so the worker can't change how it's graded:

  • Make the tests and the checklist hard to edit. Anthropic kept its feature list as JSON, which models corrupt less often than Markdown, and let the agent change only each feature's status field.
  • Have the checker exercise the running app the way a user would, with browser automation or real requests. Unit tests alone let too much through.
  • Give the checker a known-good reference when you have one. In Anthropic's C-compiler project, 16 agents were stuck on the same bug until they could compare their output with GCC's.
  • Use a different model as the checker. A reviewer from another vendor doesn't share the worker's blind spots or its habit of agreeing with itself.
Claude Code writes the fix and Codex reviews it. Neither can change what the work is graded against.Claude Code is the worker: it writes the fix in its own worktree and sends the diff to Codex. Codex is the checker, from another vendor, and reviews the diff. If it finds problems, it sends the work back with changes requested. Zoltbot passes the work between them, and hop and rate limits stop endless back-and-forth. Three things are read-only for the worker and are what the checker grades against: the contract with the done condition, the tests in test/, and the feature list, where the worker can change only the status field.Worker: Claude Codeown worktreewrites the fixChecker: Codexanother vendorreviews the diffdiff to reviewchanges requestedZoltbot passes the work between themhop and rate limits stop endless back-and-forthThe worker can't edit these. The checker grades against them.Contractthe done conditionTestseverything in test/Feature liststatus field only
Claude Code writes the fix and Codex reviews it. Neither can change what the work is graded against.
Text version of this diagram

Claude Code is the worker: it writes the fix in its own worktree and sends the diff to Codex. Codex is the checker, from another vendor, and reviews the diff. If it finds problems, it sends the work back with changes requested. Zoltbot passes the work between them, and hop and rate limits stop endless back-and-forth. Three things are read-only for the worker and are what the checker grades against: the contract with the done condition, the tests in test/, and the feature list, where the worker can change only the status field.

That last point is hard to set up when each tool runs only its own agents. We built Zoltbot so Claude Code and Codex can run side by side and check each other's work.

Keep state outside the conversation

Every pass starts with an agent that remembers nothing. If the plan lives only in a chat, the next pass rebuilds it from scratch, slightly differently each time. Huntley lists the results: placeholder code, features rebuilt that already existed, and drift away from the plan.

Anthropic's fix is a short startup routine. A first session writes a progress log, a feature list, a script that starts the app, and an initial commit. Every later session reads those first, runs a quick end-to-end check to catch what the last session broke, then finishes one feature and commits. Git history is the undo button.

The record doesn't have to be a file. A file in the repo moves with the branch, and git history shows every change to it. An issue or a card in a tracker such as Linear or GitHub Projects is easier for your team to see and comment on, and the loop can update it through a connector. Pick whichever your team already checks. What matters is that the record lives outside the chat, and every pass reads it before doing anything else.

For several agents at once, the C-compiler project didn't use an orchestrator at all. An agent claimed a task by committing a lock file to a current_tasks/ folder. If two agents claimed the same task, git sync caught the clash. The project also kept test output to a few lines, put ERROR on the same line as the reason so agents could grep for it, and gave each agent a fixed random sample of the test suite so a pass stayed fast.

Give the loop three exits

A loop that can only stop when it succeeds will never stop on hard problems. /goal in Claude Code ends in one of three ways: the condition is met, the agent decides it can't be met, or it hits an error a person has to fix. It also stops when the agent goes several turns without using a tool, because an agent that stops using tools is usually going in circles.

Your own loops need the same exits:

  • Done. The checker confirms the contract.
  • Impossible. The worker explains why, and the loop records that so the next pass doesn't try again.
  • Needs a person. A question, an approval, a missing credential. The loop pauses and asks, and doesn't guess.

Add a budget too. The /goal checker reads your condition as text and can't count turns, so writing "stop after 20 turns" won't stop anything. Set hard caps with a hook or your tool's own limits.

What loops cost

Loops spend tokens while you're not watching, and every agent you add to a loop adds to the bill. Anthropic has published these numbers:

Published costs of agent loops, checked 10 November 2026
SetupResultSource
One agent, no harness20 minutes, $9, and the app didn't workAnthropic harness design
Planner, generator and evaluator6 hours, $200, working appAnthropic harness design
Same harness, simplified for a newer model3 hours 50 minutes, $124.70Anthropic harness design
16 parallel agents building a C compilerAbout 2,000 sessions over 2 weeks, just under $20,000Anthropic C compiler
Agent teams in Claude CodeAbout 7 times the tokens of one sessionClaude Code cost docs

Two lessons from that table. First, the evaluator paid for itself only on work the model couldn't do reliably alone. When a newer model arrived, Anthropic removed harness steps and cut the cost by a third. Each time you change models, try the loop again with each part switched off. Second, idle time isn't free: Claude Code's docs note that check-ins and messages between sessions resend the full context.

You are still the bottleneck

A loop does more of the work, but someone still has to review what it produces. Gergely Orosz asked engineers who run agents in parallel how it was going. Simon Willison said he could review and land one significant change at a time. Armin Ronacher had cut back on parallel agents because review couldn't keep up. In our parallel agents guide we put the same limit at three or four tasks a day for one reviewer.

What changes is how you supervise. Anthropic's study of Claude Code usage found that experienced users approve fewer steps one by one and step in when something looks wrong. On complex tasks, Claude stopped to ask a question more than twice as often as people interrupted it. The loop should come to you, not wait for you to check on it.

So design the human checkpoint like any other part of the loop. Decide which questions the loop may answer itself, which ones wait for you, and where you'll see them when you're away from your desk.

An example loop

Here is a loop for fixing CI failures in an existing repository:

  1. Trigger. A CI run fails on main.
  2. Contract. A triage agent reads the failure and writes a plan on the task's issue: the failing test, the likely cause, and a done condition that names the exact test command.
  3. Worker. Claude Code picks up the task in its own worktree and branch, makes one fix, and runs the tests.
  4. Checker. Codex reviews the diff against the contract and checks that no test was edited or skipped. If it finds a problem, it sends the task back with its notes.
  5. Record. Each pass adds a comment to the issue saying what it tried and what happened.
  6. Exit. Done means a PR with the review attached, waiting for a person to merge. Impossible, or a third rejected pass, means a question in your inbox.

Nothing merges, deploys or publishes without a person. The loop does the work and reports back, and you decide what ships.

Where Zoltbot fits

Zoltbot is a Mac app that runs Claude Code, Codex, Cursor and other agents side by side through their own CLIs. Several parts of a loop are already built in:

  • Agents from different vendors work together. Agents can message each other and hand off tasks, so Claude Code can do the work and Codex can check it. Messages between agents have hop and rate limits, so two agents can't keep a loop running between themselves forever.
  • Each task gets its own worktree. Tasks that share a folder wait in a visible queue instead of editing the same checkout.
  • Wake when. A chat can wait until a PR merges, a GitHub Actions run finishes, a task completes or another chat's turn ends, then continue with a saved next step. No model runs while it waits. Every wait has a fallback time, and if the condition hasn't happened by then, the chat comes back to you without starting anything.
  • You review every result. A finished task waits for you to accept it or request changes, and a request runs another pass in the same conversation.
  • Questions reach you anywhere. When an agent needs you, its question shows up as a card on the Mac or your phone.

In Zoltbot, a wake condition can start the next step, but it can't merge, deploy or publish. Zoltbot doesn't run loops on a timer yet. For scheduled passes, use /loop in Claude Code, Codex automations or cron, and let Zoltbot handle the handoffs and the review.

Build the loop, keep reading the code

Loops are worth building. A good one fixes a flaky test at 3 a.m. and leaves you a PR with its review attached. You can trust that PR only as far as you trust the checker, and you still have to read it before it ships. Write the contract, keep the checker separate, keep a record outside the chat, give the loop a way to stop, and keep reading the code.

Questions

What is loop engineering?

Designing the system that prompts your coding agents, instead of prompting them yourself one turn at a time. The loop finds work, gives it to an agent, checks the result and records what happened, and it brings in a person when it needs one.

What is a Ralph loop?

Geoffrey Huntley's name for running one coding agent in a plain while loop against the same plan and spec files until the plan is done. It works best on new projects with strong tests and type checks. Huntley says he wouldn't use it on an existing codebase.

What is the difference between /loop and /goal in Claude Code?

/loop runs a prompt again on an interval. /goal keeps one session working until a condition you wrote is met, and a separate small model checks the condition after every turn.

Should the same model write and review the code?

Preferably not. Models go easy on their own work. A separate reviewer told to be skeptical catches more, and a reviewer from another vendor doesn't share the worker's blind spots.

Sources

Checked on . Claims about other tools come from their own docs and pricing pages: