Agentic software development is now, quite literally, full of loops: systems that build artifacts on their own, inside ever more sophisticated harnesses. Nearly every methodology I have read draws one. But why a loop? Why not a better prompt, or a better model, or one more human reading the diff? In the pages I have read, that question gets a sentence when it gets anything at all. And the research that does take it seriously argues for a different loop from the one most of us build.1
The first essay argued that writing code became cheap while checking what it means did not. So that is where the work goes now: into checking. Whether you spend that work on prompts, on models, on review, or on a loop is exactly what this question decides, which is why I would rather answer it carefully than by habit.
If the case for loops is settled for you already, skip to the loop I run, which is the concrete one, or to the engineer at its centre, which is the part of it I have not found anywhere else.
What an agent is, in one line
Before fixing anything, I like to write down what we are dealing with. The whole business fits in one line of type:
Agent : Ctx × Env × Goal → Env'
The agent reads three things: a context (instructions, retrieved files, prior turns, tools available), an environment (the codebase, the knowledge base, the running infrastructure), and a goal (what we asked for). It produces one thing: a new environment. And it produces it probabilistically. Run it twice on the same three inputs and you need not get the same answer.2 This is the interface I choose to engineer against, not a claim that nothing else can move a model. Provider-side memory, fine-tuning, tool wiring, the choice of model and its inference settings all change later calls too. The reason to draw the line here is that these three inputs are the ones a team can own: hold, read, version, and hand to the next call on purpose.

Look now at what the line withholds. It carries no memory of its own that you control: the context is assembled for this call and, whatever a provider caches behind the scenes, nothing there is yours to inspect or depend on. What you can depend on reaching the next call is what was written into the environment, the one argument that comes back as the result.
So the correction you made yesterday does not reliably reach today’s call unless you wrote it down, into a file the next call will read. A vendor may remember it for you; you cannot audit that memory, version it, or carry it to another model, so you cannot build on it. That leaves one lever a team can actually depend on, the inputs it hands over, and the useful thing about them is that they are ordinary artifacts: files a team can version, read and improve.
Which puts the whole weight on how good those inputs are. An ambiguity left in them about what you actually want comes back as wrong code that the agent cannot know is wrong. And it will find the ambiguity you did not know you had left, then resolve it in the direction that never crossed your mind, with complete composure.

Why one call is not enough
Suppose you have made those inputs as good as you know how to make them. Is one call enough?
It is not, and the reason is not sloppiness. Nothing in the agent guarantees a correct answer, while on realistic coding tasks the measured error rates are not small. A 2025 USENIX Security study analysed 576,000 generated samples across sixteen models and found packages that do not exist: at least 5% of the packages recommended by commercial models, and 22% of those recommended by open-source ones. Nothing in the output hedges, the code parses, the import statement is perfectly well formed, and… the package has never existed.
One study is one measurement rather than a law, and this one predates agents that resolve packages as they go. What generalises is the shape of the failure. When agents are wrong, they are not noisily wrong. They are confidently wrong, and the output looks the same either way.

That kind of wrongness is funny only once it is harmless. What makes it harmless is a check that catches that particular class of mistake. A package that does not exist is caught by anything that resolves dependencies. An algorithm that looks right and fails on one input in a thousand is caught by nothing you were given for free. Closing that distance is the work this series describes.
Why repeating helps
One call cannot be trusted, and the agent itself cannot be improved. What is left is to call it again.
Suppose one call has probability p of getting it right, and suppose for a moment that the calls are independent. Then k calls give you at least one success with probability 1 − (1 − p)k. Put p = 0.3 and k = 10 into that and you get 97%.
Real calls are not independent, and p has to be non-trivial to begin with. You will never read your own p off a dashboard, but its order of magnitude is usually plain from the task: an endpoint that resembles four existing ones sits high, and a concurrency bug in code the agent has never seen sits near zero. The attempts you need grow like 1/p: at p = 0.3, ten tries get you to 97%; at p = 0.001, about three and a half thousand; at p = 0, no number of tries gets you anywhere.
The measured version is messier. On SWE-bench Lite, the share of problems where at least one sample is correct climbs from 15.9% with one sample to 56% with two hundred and fifty. That share only becomes performance if something can pick the right sample automatically, and an imperfect picker caps the whole thing at a level no amount of extra compute lifts.3
Which is this essay’s argument, arriving from the other direction. Iterating without a reliable check buys you nothing. Repetition raises the probability that a valid candidate exists, and the check decides whether you can recognise it when it appears. Put the two together and you have the smallest thing worth calling a loop: produce a candidate, check it, decide what happens next. The repetition can be parallel, sampling many candidates at once, or sequential, repairing one on feedback, and the sequential version has a name, the Ralph loop, after Geoffrey Huntley’s popularisation. The arithmetic above is not evidence for that version in particular.
Why repeating is not enough either
A loop that produces and checks can still run all night without getting anywhere, because nothing in it says that this cycle left you better off than the last one. What it needs is a measure of progress, and three conditions have to hold before such a measure exists at all.
Progress has to be divisible: the work splits into obligations that can be checked on their own, so that a cycle can accept part of it and send only the rest round again. Progress has to be monotone: an obligation that passed stays passed when its neighbours move, and a repair cannot quietly undo the rest. And the measure has to be trustworthy, which means the checker says which obligation failed rather than that something did. That last one is also the feedback a sequential loop needs in order to aim its next attempt, and it is where sequential repair is measured to fail, rather than on the number of turns.

Nothing gives you those for free. A test suite passing on one version says nothing about the next. A repair can break what worked an hour ago. Changing a definition can invalidate every proof that rested on it. Modular proof developments are the one place I know where the three hold by construction, because compositionality is the whole design: an obligation is a statement carrying its own proof, its validity depends on nothing but the statements it invokes, and a verdict on it is exact.
One more rule belongs here, and it is not a condition on the measure but on what you do when the measure stops moving: the loop has to be able to conclude that this direction is wrong. After a few cycles that move nothing, the answer is not another cycle. It is to leave the inner loop, go back to the specification, and change the strategy, which is a decision no amount of sampling will make for you.
All of which puts the weight on the check, whose quality is the ceiling on everything above it. For critical cores, this series argues for proof checking. You state the proposition. The agent proposes a program and a proof of that proposition, since a proof of anything else is a proof of something you did not ask about. Proof obligations split into lemmas, so progress is divisible; against fixed definitions, a checked lemma remains available to later proofs, so it is monotone; and the kernel identifies the obligation it cannot verify, so the verdict is trustworthy enough to aim the next attempt. A small kernel makes those decisions independently of whichever model wrote the program or proof. The verdict is categorical for the proposition you stated, and only for that, which is why stating it is the part nobody can hand over. In Rocq, rocqeteer is what I am building it with. What the proposition leaves out, together with everything sitting outside the proof, is the trusted boundary, and drawing it is the job of Harness engineering (a forthcoming essay).
Why the loop outlives the model
You might still ask why to build any of this, when the next release could make it unnecessary. Because no model is permanent, and neither is the work you do to please one. Some of what you tune to a particular agent’s quirks, usually under the name of prompt engineering, does transfer. Much of it is renegotiated with the next release of the agent, which is another way of saying that none of it is yours to keep. What you build around the agent is yours.
I also want my loop to benefit from a new generation the day it ships. Two habits follow. Keep the coupling to any one model accidental rather than structural. And keep the authority over what counts as correct outside the generator.
Fix the loop, not the output
So when the agent produces wrong code, do not stop at patching that code. Patch whatever let it recur, or let it through: the structure of the codebase it read, the specification it was given, the checks that failed to catch it, or the drifting understanding of the human who approved it. The loop will produce code again, on a different problem, tomorrow. Hence the slogan I use with my team: fix the loop, not the output.
Those four layers are four disciplines. The next essay is the loop that arranges them.
Appendix
Sources, with what each one is good for.
- We Have a Package for You! (USENIX Security 2025), package hallucinations measured across 576,000 generated samples and sixteen models: at least 5% of the packages recommended by commercial models do not exist, and 22% of those recommended by open-source ones. The structural reason the checks exist.
- Ralph loop (Geoffrey Huntley), the sequential instance of generate-check-decide, and the name most people use for it.
- AlphaCode (Science, 2022), sampling at scale then filtering on program behaviour, named as one of three critical components and ablated; an explicit argument for iterating rather than for a better model.
- Large Language Monkeys (2024), coverage against sample count, the cost table where cheap samples beat one expensive call, and the precondition: it pays where answers can be verified automatically.
- Inference Scaling fLaws: The Limits of LLM Resampling with Imperfect Verifiers (Stroebl, Kapoor, Narayanan, 2024), the ceiling an imperfect verifier imposes on any amount of resampling; the strongest objection to the loop, and an argument for spending on the checks.
- Is self-repair a silver bullet? (Olausson et al., 2023), sequential repair measured against equal-budget resampling, with the bottleneck located in the quality of the feedback rather than in the number of turns.
- Building agents with the Claude Agent SDK (Anthropic), the gather-act-verify-repeat loop as a vendor presents it, and the one sentence of justification that comes with it.
- SWE-agent (NeurIPS 2024), agent-computer interface design moves solve rates with the model held fixed; the evidence that the system around the agent is a lever, collected in full by Harness engineering (a forthcoming essay).
- rocqeteer, a toolchain for building certified, efficient programs with Rocq and OCaml; where the categorical check named above is being built, and the reason I can promise one.
The case for iterating is made explicitly in the literature, and with numbers, but for a particular loop: sample many candidates, then let a verifier pick. AlphaCode names large-scale sampling followed by filtering as one of three components critical to its result, and ablates it. Large Language Monkeys puts the contrast in a table: five samples from a cheap model beat one call to an expensive one, at a fifth of the price. SWE-agent holds the model fixed on purpose, to show that the interface around it is the lever, and moves the same model from 1.31% to 12.47% on SWE-bench. The sequential edit-run-observe loop that the harness discourse actually means is a different animal, inherited from ReAct by citation rather than defended, and where it has been measured against equal-budget resampling it does not reliably win (Olausson et al.). On the vendor side the reason is one asserted sentence: agents that check their own output “catch mistakes before they compound” (Anthropic), with no benchmark and no comparison against the alternatives. So what follows is my argument, not a summary of a consensus. ↩︎
Functional programmers will have recognised the shape. With the context and the goal fixed, Env → Env’ is a state transformer, and a run of the loop is a sequence of those composed. What the analogy makes visible is exactly the subject of this essay: composing them is the loop’s job, and nothing in the type does it for you. ↩︎
Large Language Monkeys (2024) calls that share coverage: pass@k, with an oracle picking among the samples, which is why it is not a solve rate. The paper states the precondition plainly, that repeated sampling turns into performance in domains where answers can be verified automatically, and its authors later cautioned that coverage does not hand you a recipe for converting it. The ceiling is Stroebl, Kapoor and Narayanan (2024): with an imperfect verifier, a weaker model resampled cannot match a stronger model’s single shot, whatever the compute budget. ↩︎