Skip to content
4/5 - When Done Actually Means Done: Loop Engineering for Long-Running Agents

4/5 - When Done Actually Means Done: Loop Engineering for Long-Running Agents

Most agents are built around a loop. The model receives context, proposes a response or tool call, the runtime executes the tool, the result returns to context, and the model gets another turn. The loop is short. Knowing when to run it, what counts as progress, and when to stop is not.

Loop engineering begins when a human no longer writes every next prompt. A schedule, event, queue, or goal starts the run. The system can execute many turns and perhaps several helpers before a person returns. That is useful, but it changes the core contract. “The model said it was finished” is an observation. It is not proof that the work is finished.

The mental model: a finite control system

A long-running loop needs a goal, a definition of success, an action budget, a progress signal, and a stop policy. It also needs durable state so a restart resumes from a known checkpoint rather than redoing unknown work. This is closer to a workflow controller than to a chat transcript.

Loop engineering state machineA long-running agent moves between accepted, executing, verifying, paused, completed, and failed states.
A long-running agent is a state machine
The loop is safe when every transition has a predicate, a budget, and a durable checkpoint.
Acceptedgoal and deadline bound
Executingone bounded action
Verifyingcheck actual state
Decisionstop, pause, retry, continue
continue only when state changed or a bounded recovery policy applies
Progress?
Pausedneeds authority, input, or budget
Completedgoal predicate passed
Failedcontinuing is unsafe or futile
The model may report completion; the verifier owns the completion predicate.
State machines make success, pause, and failure distinct. That distinction is what lets operators resume work without guessing.
Loop budget ledgerA loop spends turn, time, token, tool, and money budgets while progress must rise.
Every iteration spends a finite budget
A loop controller should show remaining capacity and verified progress on the same dashboard.
Budget ledger
Turns remaining · 12 / 20
Time remaining · 18 min
Tokens remaining · 64k
Side effects · 3 / 5
progress ledger: state hash → action → observation → verifier result
Brake conditionssame state hash twicesame arguments repeatederror class unchangedbudget or deadline exhausted
Activity is not progress. A next turn must be purchased by state change, evidence, or an explicitly bounded recovery attempt.
The budget ledger pairs remaining capacity with progress evidence so a loop cannot hide runaway work behind a growing turn count.
Checkpoint and resume handoffA paused loop saves a structured handoff and resumes only after its state and authority are revalidated.
Pause and resume should be a designed path
A checkpoint is a handoff contract, not a screenshot of the last model response.
1 · Pause trigger
approval requireddeadline neardependency unavailableno progress detectedbudget exhausted
2 · Checkpoint
goal and predicateverified factschanged artifactsopen risksremaining budget
3 · Resume gate
reload and validate staterecheck authorityrefresh evidencechoose a new hypothesiscontinue or fail closed
Never resume by blindly replaying the last turn; resume from durable state and a fresh authority check.
A good checkpoint gives the next worker enough truth to continue and enough uncertainty to avoid replaying an unsafe action.

Description: The return path is deliberately conditional. If a turn produces no state change, repeating it should require a reason and a decreasing budget. Otherwise the loop can pay repeatedly for the same call while reporting activity as progress.

Define completion before autonomy

A goal should be written as a state transition, not a mood. “Improve the service” is not directly verifiable. “The test suite passes, the error budget is unchanged, the deployment has the target digest, and the smoke check returns 200” is much closer. The completion predicate may combine deterministic checks and a human approval. Record the predicate version with the run so a future policy change does not rewrite history.

There are at least three different stops: success, safe pause, and failure. Success means the goal predicate passed. Pause means the system lacks authority, budget, or information and can resume safely. Failure means continuing automatically is unsafe or unlikely to help. A cancelled run should be distinct from both. These states make the operator UI meaningful and prevent a timeout from being reported as a successful completion.

Budgets are control surfaces

Set a maximum number of turns, maximum wall time, maximum input and output tokens, maximum tool calls, maximum spend, and maximum parallel work. Use one overall deadline and pass the remaining time to each child operation. A per-call timeout of five minutes does not make a run safe if the loop can execute one hundred calls.

Use a progress ledger. Each iteration should record the state hash, planned action, observed effect, verifier result, and cost. A no-progress detector can flag repeated state hashes, identical tool arguments, alternating states, or an error class that never changes. A detector is not a substitute for verification, but it is a valuable brake against a doom loop.

Context rot and the doom loop

Long runs accumulate their own history. Earlier plans become stale, tool output crowds out the goal, and the model starts optimizing for the most recent text rather than the actual state. This is context rot. A doom loop is the operational form: the agent repeatedly calls the same tool, applies and reverts the same change, or keeps asking for information that cannot exist.

The remedy is not always another prompt. Compact state at checkpoints, keep durable artifacts outside the context window, re-read authoritative sources, and make the verifier’s result prominent. Use a fresh context when the working set is no longer legible, but preserve a structured handoff: goal, facts, decisions, open risks, changed artifacts, and last verification.

Failure modes and brakes

The tempting design is to add a larger turn cap whenever the agent fails to finish. That increases cost while hiding the actual defect. A better design has separate brakes for repeated calls, repeated state, rising failure rate, tool latency, budget exhaustion, and missing authority. Each brake should say whether to retry, pause for a person, switch to a fallback, or terminate.

Parallelism is not free

Parallel sub-agents can reduce elapsed time when work is independent, but they increase coordination, context assembly, cost, and failure surface. Give each child a scoped goal and output contract. The parent must reconcile outputs, detect contradictory evidence, and remain responsible for completion. “Five agents finished” is not the same as “the task passed.”

Use a work queue when the number of tasks is dynamic. Make leases, retries, cancellation, and ownership explicit. A worker that is alive but has lost its lease should not continue mutating shared state. A parent that has timed out should cancel or quarantine its children rather than leaving orphan work behind.

A production recipe

Start with a single loop and a deterministic completion check. Add pause and resume before adding more turns. Then test timeout after a side effect, worker restart between action and receipt, stale context, repeated tool errors, a verifier outage, and a goal that is impossible under the available tools. Observe queue age, turn count, cost, state changes, verifier outcomes, and stop reason. Make stop reason a first-class field in the run record.

For a code change, the run might stop when tests pass, the diff is clean, and a reviewer approves. For a data pipeline, it might stop when the expected partition exists, row counts match, and a quality check passes. For a research task, completion may require a human because “good enough” is a judgment. The engineering is to make that judgment explicit instead of hoping the model guesses it.

Verification patterns that scale

The verifier should inspect state, not merely restate the model response. For a code task, run the relevant tests and inspect the diff. For a data task, check schema, counts, constraints, and freshness. For an infrastructure task, query the actual deployment and health state. A model-generated checklist can be useful as a hint, but the hard completion predicate should be backed by a deterministic check or an explicitly assigned human decision.

Control parallel work with leases

Parallel agents are useful when tasks are independent, but a parent loop must own reconciliation. Give each child a scoped task, lease, deadline, and output contract. The lease prevents a disconnected worker from mutating state forever. The parent should reject duplicate or contradictory results and should cancel child work when the goal is complete or the run is paused. Otherwise “parallelism” becomes orphaned cost and an uncontrolled side-effect surface.

Use hysteresis, not nervous automation

A controller that reacts to one slow tool result can oscillate between strategies. Require a signal to persist for a small window, use cooldowns between expensive changes, and keep a cap on concurrent recovery attempts. This is the same reason production autoscalers use stabilization windows. The loop should be responsive enough to recover, but slow enough to distinguish noise from a state change.

Design cancellation as a real transition

Cancellation should stop new work, signal running children, preserve the last checkpoint, and record which effects completed. It should not simply drop the process and mark the run cancelled. A user who resumes later needs to know whether the previous tool call was never dispatched, is still running, or finished without a receipt. Cancellation is part of the run contract, not an exceptional afterthought.

Primary references

The takeaway

Loop engineering is the discipline of making repeated work finite and accountable. Define success before the run, preserve state, spend a bounded budget, detect no progress, and verify completion independently. Autonomy is not measured by how long an agent keeps working. It is measured by how reliably the system reaches a true, observable state and stops there.