An agent session looks like one stream of activity — until you slice it into three loops and the symptom in the trace tells you which one to fix.
Why this, for you: "It looks stuck" is too vague to act on, so you reach for the nearest
intervention and hope. Naming which loop stalled narrows a dozen candidate fixes down to two or three —
before you've burned another twenty minutes guessing.
The three loops are a diagnostic mental model, not a new architecture. They don't
change how agents are built — only how you read a trace. Each loop has a different boundary, a different stopping
condition, and a different way of failing. So the signal you observe routes straight to the matching intervention.
1 Slice the session into three loops
One user-facing session is actually three nested loops running at once. From the inside out:
Tool loop (inside one turn) — the model emits a response, the harness runs any tool call, the result is appended to the prompt, the model is queried again. It stops at "no pending tool calls."
Verification loop (across turns, tests as boundary) — run the code, observe a failure, pass the error back, fix, re-run. The boundary is binary and machine-checkable: a test or build goes green.
Convergence loop (across turns, stable state as boundary) — plan → act → verify, repeated until the work converges. For prose, specs, and partly-specified code there's no machine gate, so it stops on convergence signals: change velocity, output size, similarity.
Each loop produces a distinct observable signal: a spinning tool loop shows up as
repeated tool calls inside one turn; a failing verification loop as tests that stay red across turns; a non-converging
outer loop as a series of substantially different diffs, none reaching a stable state.
2 Read the symptom, route to the fix
The payoff is a lookup table. Match what you see in the trace to the loop that's failing, and the intervention
follows:
Symptom you see
Failing loop
Intervention
Same tool call repeating, no progress between turns
Tool loop
Inspect tool defs & permissions; clip the iteration cap
Tests keep failing; fixes cycle through the same edits
Verification loop
Sharpen the error signal: full stack trace, narrower test, shorter cycle
Diff oscillates, scope drifts, nothing gets closer to done
Convergence loop
Stop iterating the artefact; revisit the plan or scope
Many tool calls but tests are green and the diff stabilises
Healthy — converging
None — let it finish
The verification loop stops only when the tool says PASS. "The agent thinks it's
done" does not count — RefineBench found self-refinement without an external check gains only +1.8 points
over five iterations on frontier models, and that models routinely halt early under overconfidence.
A symptom at one layer can mask a failure at another
The agent looks stuck mid-tool-loop, but the real problem is an ambiguous spec (outer loop). Tests stay red, but
the test encodes a flawed assumption (the verification boundary itself is wrong). Naming the loops separately
is what makes "where is the failure" answerable instead of "the agent is being weird."
3 Know when the frame backfires
The model costs you three loops to remember — worth paying only when diagnosis is genuinely hard. Skip it when:
Single-shot tasks — a typo fix or version bump runs entirely inside one tool loop; there's no verification or convergence loop to diagnose.
A sharp test gate exists — when pytest -x is the whole stopping criterion, the convergence loop collapses into the verification loop and two loops suffice.
Pure exploration or debugging — when the goal is to find out what's wrong, "which loop am I in" is the wrong question. The move is to read more, then hypothesise.
The litmus test: if you can name the failing loop in under five seconds, the frame
is doing its job. If you're debating which loop a symptom belongs to, the real issue is elsewhere (spec ambiguity,
missing context) and the label is a distraction.
One trace can show all three at once. A 40-minute refactor: a turn spins re-Reading the same file
with slight path variations (tool loop — lift the cap, paste the right path); then pytest stays red for
three turns on a generic AssertionError (verification loop — rerun with --tb=long, paste the
full trace); then tests pass but the next diff refactors a correct function and the turn after reverts it (convergence
loop — the task converged two turns ago; end the session). Three failures, three loops, three distinct fixes.
↪ Your win: name the loop before you debug it
Three nested loops — tool (inside a turn), verification (tests as boundary), convergence (stable state as boundary).
Symptom routes to fix — iteration cap, sharper error signal, or revisit-the-plan, respectively.
PASS, not vibes — the verification loop stops on a green tool, never on the agent's own confidence.
Skip the frame for single-shot tasks, sharp test gates, and pure exploration.
Retrieval practice — recall, don't peek
Question 1The tool loop lives entirely inside one turn and stops when…
Question 2Persistent red tests across turns point at the…
Question 3A diff that oscillates while scope drifts and nothing gets closer to done is the signature of the…
Question 4You should skip the three-loop frame when…
Question 5The three loops are best described as…
Ask me anything. Want help mapping a real stuck trace of yours onto a loop, or deciding whether
your task even needs the frame? Next in Part 2: Loop Strategy & Autonomy — how much context each
iteration should carry, and where Ralph's brute-force extreme fits.