How do you stop an agent that never decides it is finished?
A bounded agent loop runs under an explicit step budget and token ceiling. A wall-clock limit also applies. A termination contract forces every run to end in a small set of named states, such as success or escalation. When the budget runs out first, the harness ends the run itself.
Also known as step-budget loop, agent circuit breaker, termination contract
What problem does this solve?#
Without an external budget, nothing stops an agent loop that keeps calling tools and re-reading the results. The model has no reliable internal sense of when to stop after six failed tries. A failed tool call sits in context and looks like fresh information. The model then reasons forward from it as if a new attempt might succeed. The loop ends only when something outside the model intervenes, such as a platform timeout or a human who watches the trace.
The cost compounds. Each failed attempt adds more context for the model to re-read, and the constraint that caused the failure stays the same. A harness that cannot tell "making progress" from "looping" treats both the same. An unbounded loop and a long task look alike, until one of them burns ten times the expected cost.
How does it work?#
The harness enforces a hard ceiling on steps and tokens per run, plus a wall-clock limit. The team sets each ceiling in advance, based on the expected complexity of the task. When any ceiling is hit, the harness force-terminates the run into one of a fixed set of terminal states. A circuit breaker trips the same way, before the fuse melts on its own schedule.
A termination contract defines what the terminal states mean: succeeded, failed-with-reason, budget-exceeded, or escalated-to-human. Every run logs exactly one state, so a dashboard answers "how did this run end" without a transcript read. Progress detection asks whether the agent retrieved new information or changed state. A run that only repeats a prior call has made no progress. This lets the harness end a stuck run well before the hard ceiling. The harness need not wait out the full budget on a run that will never resolve.
An escalation path matters as much as the ceiling. A run that hits its budget without success hands off to a human with the transcript and the reason.
What are the moving parts?#
- Set per-run ceilings before launch
Size the step and token ceilings to the expected complexity of the task. Set the wall-clock limit the same way. Do this before the first production run.
- Detect no-progress steps
Track whether the agent retrieved new information or used a new tool. A state change also counts as progress. Repeated calls with none of these count as no progress.
- Force a terminal state on ceiling or no-progress
The harness ends the run itself once a ceiling is hit or a no-progress threshold is crossed. It does not wait for the model to decide to stop.
- Define the fixed terminal states up front
Succeeded, failed-with-reason, budget-exceeded, escalated: every run ends as exactly one of these. The team decides the states before any run happens.
- Escalate to a human on non-success
A run that hits its budget without success hands off to a human with the transcript and the reason.
- Log the terminal reason on every run
Every run writes its terminal state as structured data, successes included. The distribution is then queryable.
When does it fit, and when doesn't it?#
Use it when
- Agent runs vary widely in step count for the same task type, and the tail is expensive.
- Tool calls can fail in ways that look like fresh information to the model, such as a rate limit or a transient error.
- You need a hard, auditable answer to 'how much can one run cost' before you ship to production.
- Several engineers or teams build agents on the same harness and should share one termination logic.
Don't use it when
- The task is a single bounded tool call with no loop. No runaway condition exists to bound.
- The task's own structure already bounds step counts tightly, such as a fixed 3-step pipeline.
- You cannot yet define 'progress' for the task. A budget without a progress signal only makes failures happen at a fixed cost.
What does it cost?#
A hard ceiling on the worst-case cost and duration of any single run.
A long, complex task can be cut off before it would have succeeded. The team must size the ceiling generously to avoid false terminations.
Every run ends in one of a small set of named states. These states become queryable data.
A real progress-detection check takes work to build and maintain. A naive check, such as step count alone, misses loops that vary arguments slightly each time.
Stuck runs end long before the outer ceiling, which saves spend.
Tuning the no-progress threshold takes iteration. A threshold that is too aggressive kills runs that were about to succeed.
A defined escalation path turns budget exhaustion into a handled case.
Escalation needs a real destination, such as a human queue or an alert, and someone must staff it. Otherwise the escalated state becomes another kind of dropped task.
How do you know it's working?#
- Steps per run and token spend per run as distributions (p50 and p99)
- Share of runs ending in each terminal state (succeeded, failed, budget-exceeded, or escalated)
- Rate of near-identical repeated tool calls per run
- Cost per completed task compared with cost per attempted task
What failure modes does this prevent?#
Sources
- Google - Implementing SLOs
The method for setting a service-level objective our release scoreboard follows. Retrieved 2026-08-24.
- Google - Error Budget Policy
The error-budget policy pattern our release gate borrows. Retrieved 2026-08-24.
A Ship Audit checks which of these patterns your system needs. It ranks them by what is most likely to break first.