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.

A hand-drawn diagram read from left to right, inside one dashed boundary labelled AROUND THE AGENT: EVERYTHING YOU CAN ENGINEER. Boxes drawn with a dotted outline are artifacts, each naming itself on its first line: context, holding instructions, files and tools; environment, holding codebase, knowledge base and infrastructure; goal, holding what we asked for; and further right, new environment, holding the same three items primed, and verdict, holding pass slash fail. Boxes drawn with a solid outline are the ones who act: ENGINEER at the left, holding a dotted box named understanding, and DETERMINISTIC CHECKS and AUDITORS, human or AI, at the right. One box has a heavy outline: AGENT, Ctx times Env times Goal to Env prime. Three thin arrows leave the engineer, each carrying a verb: sets to the context, maintains to the environment, writes to the goal. Every other arrow is thick and unlabelled: the three artifacts into the agent, the agent into the new environment, the new environment into the checks and the auditors, and both of those into the verdict. Nothing points back to the left.
The type, drawn. Dotted boxes are artifacts, solid boxes are whoever acts on them, thick arrows carry an artifact and thin ones carry a verb. Nothing points back, so there is no loop here yet; that is the next essay.

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.

A three-panel stick-figure comic. Panel one: the engineer hands the small robot labelled agent a sheet reading make it fast. Panel two: the robot works at a desk, striking every line off a list, a wastebasket full of pages beside it. Panel three: the robot beams, holding up a stopwatch reading 0 ms, while the engineer stands open-mouthed under a question mark.
It did make it fast.

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.

A three-panel stick-figure comic. Panel one: the small robot proudly hands the engineer a page labelled done. Panel two: the engineer asks: does it work? and the robot answers: it looks like it works! Panel three: the page sits in a machine labelled checks showing a large cross; the robot looks sheepish while the engineer points calmly at the machine.
Confidence is not a signal. The checks are.

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.

A three-panel stick-figure comic. Panel one: the small robot labelled agent holds up a sheet with four rows, a, b, c and d; three carry ticks and the fourth a cross, beside a box labelled CHECKS, while the engineer watches. Panel two: the three ticked rows lie in a pile marked kept, the robot works on a single sheet labelled d, and the engineer reads calmly. Panel three: the four rows are back together, all four ticked, handed to the engineer under an arrow labelled ship.
The ratchet, once you have built one: what passes is kept, and only what failed goes round again.

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.

  1. 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. ↩︎

  2. 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. ↩︎

  3. 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. ↩︎