After this article: you should be able to tell the story of one run, explain why every observation must change the next decision, and design clear state, exit, budget, and retry rules.

Evidence boundary: the mechanisms come from OpenAI’s official Codex Agent Loop walk-through and practical agent guide, plus Anthropic’s Building effective agents. SDK events and API fields vary; the state names here are vendor-neutral abstractions.

1. Understand the loop through one task

1.1 Watch one task advance through four rounds

An Agent receives “fix the failing payment test.” It cannot responsibly edit the first plausible line and stop. A useful run might unfold like this:

  1. Round 1: read the failure and relevant code. The new observation is that an expired-order guard is missing.
  2. Round 2: make the smallest code change. The new observation is the exact diff.
  3. Round 3: run the payment tests. The new observation is another failure in a related case.
  4. Round 4: adjust the change and run the tests again. The new observation is a passing result.

Each round uses what the previous round discovered. If the Agent keeps issuing the same command after the same error, it is not progressing; it is only repeating.

1.2 Give this repeated process a name

An Agent Loop is the repeated process inside one run: prepare the current information, ask the model for the next step, execute an allowed action through the harness, observe the result, and decide whether to continue or stop.

Three roles are enough to understand the basic loop. The model proposes the next step. The harness turns an allowed proposal into a real action and observation. The loop controller carries state forward and decides whether another round is needed.

For a beginner, the loop first needs only three broad states: running, waiting, and stopped. Later we will split them into completed, blocked, failed, cancelled, and other precise states.

2. Make one run converge through evidence

2.1 Every round must change the next decision

In plain language, each round must bring back a change for the next one: reading a file produces a new fact, running a test produces a new error, and editing code produces a new diff. The outer program organizes that result, updates progress, and prepares the next packet of material. Continuing is useful only when evidence, plan, risk, or the done judgment has changed.

The table below only gives engineering names to the actions you already saw. Preparing material is Assemble, model judgment is Infer, action is Execute, organizing the result is Observe, and choosing whether to continue is Decide. It is not a second process.

Agent loop state diagram with five stations and continue and final exits
An observation need not change the outside world, but it must change evidence, plan, risk, or done judgment. Otherwise the next iteration is probably expensive repetition.
StateInputNew fact it must produce
AssembleGoal, control state, recent observationNext model view and budgets
InferModel viewGoverned proposal or final candidate
ExecuteAuthorized tool callTyped result, artifact, environment delta
ObserveResult and world deltaSuccess, failure, or unknown with provenance
DecideDone criteria, risk, budgetsContinue or an explicit exit reason

2.2 Stopping has more than two meanings

“The model returned final” is a signal, not a termination protocol. The runtime should map it to verified completion, waiting for user input, blocked by authority, retryable failure, terminal failure, exhausted budget, or cancellation. Each exit needs different evidence and a different next owner.

Agent loop exit gates for complete, wait, blocked, budget, failure, and cancellation
Exit reason is an input to the outer loop and shared truth for UI, audit, and recovery.
ExitMinimum evidenceNext owner
CompletedDone check passed plus artifact or diffEvaluator or delivery flow
Waiting userMissing decision, options, default impactUser
BlockedRequired capability or permission and current scopeHarness owner or approver
Retryable failureError class, attempt, backoff conditionCurrent loop or outer loop
Terminal failureUnrecoverable reason, reconciled in-flight effects, failure artifactOuter loop, evaluator, or person
Budget exhaustedCompleted, remaining, checkpointOuter loop or person
CancelledCancel source, in-flight action, cleanupHarness cleanup

2.3 Define “done” before the first action

Without a done contract, an agent substitutes fluent prose for completion. A bug fix may require the target test, relevant regressions, a scoped diff, and no unexplained effects. Research may require source coverage, citations for every conclusion, and marked conflicts. Done enters state before the loop starts and is reevaluated after every observation.

The model may propose “I believe this is done.” Deterministic checks should run in the harness; subjective quality can go to an independent grader or person. Reflection helps, but one component should not be contestant and sole judge.

Put the three checks on different time scales and the boundary is clearer. After this test passes, the Agent Loop asks, “may this run exit?” The Outer Loop reads test, CI, or review evidence and asks, “may this long-lived work item end?” Evals repeat many tasks and ask, “did this system version become reliably better?” They check one run, one work item, and one system version respectively.

2.4 Why an Agent cannot run forever

A loop manages time, model calls, tool calls, tokens, external APIs, concurrency, and risk. A maximum iteration count treats a cheap read and an expensive deployment equally. Better controllers estimate value and cost before each action and reserve capacity for validation.

  • Near a limit, narrow search, reduce parallelism, or request a choice instead of stopping abruptly.
  • Reserve an independent verification budget so editing cannot consume the ability to test.
  • Risky writes pass through an independent authority gate; more tokens cannot compensate for missing authority.
  • Budget exhaustion produces a checkpoint and exit reason, never a disguised completion.

2.5 A retry must introduce a change

Retry is meaningful only if input, environment, strategy, or time changes. Repeating the same arguments, error, and context is a loop defect. Classify transient, invalid input, permission, not found, conflict, invariant violation, and unknown errors to choose recovery.

Agent loop recovery routes for transient, invalid input, permission, conflict, invariant, and unknown errors
Recovery strategy belongs to an error class, not to one undifferentiated “failure” bucket.
Error classUseful changeDo not
TransientBackoff, jitter, bounded retryReplay at full speed
Invalid inputRead schema and repair argumentsRetry identical arguments
PermissionRequest explicit authority or use a read-only pathBypass the gate
Conflict / staleRefresh state and replanOverwrite new truth
Invariant failureRollback, shrink the change, escalateStack more changes
UnknownSave artifacts, stop, or probe in isolationExplain forever

3. Advanced: expand three broad states into a recoverable state machine

By this point, a beginner can review one run through evidence changes, done criteria, exit reasons, budgets, and meaningful retries. Only when implementing the controller do those judgments need to become durable state.

while (toolCalls.length) expresses a syntax condition, not an engineering state. At minimum distinguish running, waiting approval, waiting user, blocked, completed, failed, cancelled, and budget exhausted. State determines who may wake the run, which resources remain valid, and whether an outer loop can retry safely.

Before naming fields, follow one payment-task round as state changes:

  1. The runtime begins by reading the goal, the previous test failure, and remaining budgets.
  2. The assembler turns those facts into the current model view, and the model proposes one next action with a call id.
  3. The harness validates and executes the tool, producing a new observation; the proposal itself does not directly change run state.
  4. The controller writes the observation into state and updates progress, budgets, repeated-failure counts, and any candidate exit reason.
  5. Only after checkpointing does it start another round. A passed done check, required approval, or lack of meaningful change selects a different exit instead.
{
  "run_id": "run_18",
  "state": "running",
  "iteration": 7,
  "goal": { "id": "fix-payment-test", "done_check": "test://payment" },
  "last_observation": { "kind": "test_failure", "ref": "log://9f2" },
  "budgets": { "tool_calls_left": 12, "time_s_left": 480 },
  "progress": { "changed_files": 2, "same_failure_count": 1 }
}
Shape-level example: loop state is not the message array. It is deterministic control state that the runtime can inspect and recover.
while run.state == "running":
    view = assemble_context(run)
    proposal = model.infer(view)
    observation = harness.dispatch(proposal, run)
    run = transition(run, observation)

    if done_check(run):
        run.state = "completed"
    elif repeated_without_change(run):
        run.state = "blocked"
    checkpoint(run)
Minimal controller: policy.ask moves running to waiting_approval; approval_granted wakes it back to running; only a test observation that satisfies the done check enters completed. Model final text alone cannot complete the run.

4. Review the health of one run

Review pointHealthy signalDanger signal
ProgressNew evidence or state delta every iterationSame calls and errors repeat
DoneDefined before, verified afterFinal-answer tone
ExitMachine-readable reason and checkpointSuccess/failure boolean only
BudgetMultiple budgets, dynamic, verification reservedOnly max iterations
RecoveryStrategy changes by error classRetry every error
HumanIntervenes at judgment and authority boundariesApproves everything or never appears

The agent loop makes one run converge with evidence. Next we lengthen the horizon: when work requires triggers, queues, checkpoints, and handoffs across runs, design the outer loop.

Official sources