“Let the agent keep working until it finishes” is not autonomy. It is an unpriced loop with an optimistic exit condition.
Real tasks contain ambiguous success criteria, unavailable tools, contradictory instructions, flaky environments, and actions that cannot be retried safely. A production agent needs more than persistence. It needs a harness that can distinguish progress from motion and completion from exhaustion.
The loop is the product
A single model call proposes an answer. An agent harness repeatedly assembles context, calls the model, validates proposed actions, executes tools, records observations, and decides whether another step is justified.
while budget.allows(next_step):
request = build_request(task, state, history)
proposal = model(request)
if proposal.is_complete():
return verify_completion(proposal, state)
action = policy.authorize(proposal.action)
observation = tools.execute(action)
state = record(state, action, observation)
return stop_with_reason(state, budget.exhaustion_reason)That outer loop owns the operational behavior. Current agent-harness documentation describes the same responsibilities: tool execution, history management, policy, observability, compaction, and completion conditions. A stronger model may improve each proposal, but it does not remove the need for the loop to govern the run.
Use a budget vector, not one step limit
A maximum number of steps is necessary and too crude. Different operations have different costs and risks. Represent the budget as several independent limits:
- model budget: tokens, calls, and monetary spend,
- time budget: wall-clock deadline and per-tool timeout,
- action budget: total tool calls and calls by risk class,
- failure budget: consecutive errors and repeated identical errors,
- change budget: files modified, records written, or external mutations,
- attention budget: approvals or clarifications requested from a human.
Budget checks belong before a step begins. Discovering after an expensive tool call that the run exceeded its limit is accounting, not control.
Define progress in the environment
Agents are excellent at producing plausible activity. Logs grow, plans become more detailed, and the same failed hypothesis returns with different wording. None of those observations proves the task is closer to completion.
Progress should be tied to state that matters:
- a previously failing test now passes,
- the set of unresolved diagnostics shrank,
- a required artifact was created and validated,
- new evidence eliminated at least one hypothesis,
- a human supplied information that unlocks a blocked branch.
Store a compact progress fingerprint after each meaningful step. If the agent repeats the same action against the same state or produces no state change across several attempts, the harness should interrupt the pattern rather than hoping for inspiration.
Make every stop explicit
“Stopped” should never be the only outcome. A useful run ends with a typed reason:
| Stop reason | Meaning | Next action |
|---|---|---|
| completed | Success criteria were verified | Deliver artifacts and evidence |
| blocked | A named dependency is unavailable | Ask for the minimum missing input |
| budget_exhausted | A hard resource limit was reached | Resume with a deliberate new budget |
| policy_denied | The proposed action was not authorized | Choose a safer path or request approval |
| no_progress | The state stopped improving | Change strategy before resuming |
These reasons are product behavior. They determine what the user sees, what automation may retry, and which events deserve an alert.
Design for resume instead of pretending runs never die
Long agent runs will encounter deploys, crashes, expired credentials, and user interruptions. Resumability requires durable facts rather than a giant transcript.
Persist at least:
- the task and acceptance criteria,
- the latest validated environment state,
- completed and pending actions with idempotency keys,
- the active budget and consumption ledger,
- the stop reason and the evidence behind it.
On resume, reload the environment before deciding what to do next. The world may have changed while the agent was asleep. Replaying the last model response without revalidation is how duplicate messages, duplicate pull requests, and duplicate payments happen.
The harness contract
The model proposes. The harness owns time, tools, permissions, state, and termination. Keep those responsibilities outside the prompt so they remain deterministic, inspectable, and enforceable.
A good agent is not the one that runs longest. It is the one that can explain what changed, why the next step is worth its cost, and exactly why the run ended.