PromptABCD
FeaturesLearnGuideBlogContext Blocks
Sign inGet started free
Sign inSign up
PromptABCD

A calm home for your best AI prompts. Save them once, find them in seconds, reuse them forever.

Product

  • Features
  • Chrome Extension
  • Free Courses
  • How it works
  • Use cases
  • Blog
  • Context Blocks
  • Export Anywhere
  • FAQ

Resources

  • User guide
  • Learn prompting
  • Sign in
  • Get started free

© 2026 PromptABCD. All rights reserved.

AboutPrivacy PolicyTerms and Conditions
Home/Blog/Autonomous AI Agents/Stopping Conditions for Autonomous Agents
Autonomous AI Agents

Stopping Conditions for Autonomous Agents

One agent looped 400 times refining a report nobody would read, then billed for it. A weak autonomous agent stopping condition is how that happens - here's the teardown and the fix.

October 6, 2026·8 min read
ShareShare
⚡Featured Prompt— copy and use right now
while True:
    result = agent.step(goal)
    if agent.believes_goal_met(result):   # the ONLY exit
        break

An agent was asked to polish a quarterly report. It polished. Then it polished the polish. Four hundred iterations later it was still making microscopic wording changes to a document that had been good enough at iteration 12 - and it had quietly run up a bill doing it. Nobody told it to stop, because its only stopping condition was "stop when the report is done," and to the agent, a report can always be a little more done.

An autonomous agent stopping condition is the rule that decides when the loop ends. It's the most under-designed part of most agents and the one most responsible for runaway cost and wasted work. "Stop when the goal is met" feels sufficient and almost never is, because goals like "polish," "improve," or "research" have no natural completion point. This teardown pulls apart a weak stopping condition and rebuilds it into something that actually terminates.

Before: the weak stopping condition

Here's the stop logic that let the report agent run 400 times:

python
[object Object], ,[object Object],:
    result = agent.step(goal)
    ,[object Object], agent.believes_goal_met(result):   ,[object Object],
        ,[object Object],

What this does: it loops indefinitely and exits only when the agent itself judges the goal complete - so if the agent never decides it's finished, the loop never ends.

The single exit is the problem. It puts the entire termination decision in the hands of the same model that's incentivized to keep improving, and it offers no other way out. For a goal with a fuzzy finish line, "the agent decides it's done" is a stopping condition that may simply never fire.

Why it fails

It fails for three separate reasons, and a real stopping condition has to cover all three because they're independent.

First, the goal may have no natural end. "Polish the report" is unbounded - there's always another tweak. The agent isn't malfunctioning; it's correctly observing that the report could be marginally better, forever. A single goal-met check can't terminate an open-ended goal because open-ended goals are never met.

Second, the agent's self-assessment can be wrong in both directions. It might declare a goal met that isn't (stopping too early) or never declare a goal met that is (running forever). Relying solely on the agent's judgment inherits the agent's judgment errors, with no backstop.

Third, there's no cost awareness. The loop has no concept that iteration 400 costs the same as iteration 4 but delivers nothing. A stopping condition blind to cost will happily spend a fortune achieving nothing, because spending isn't part of its exit logic at all.

⚠️ Common mistake: Using goal-completion as your only stopping condition. It's necessary but nowhere near sufficient - it fails silently on exactly the open-ended tasks where runaway loops are most expensive.

After: the improved stopping condition

Here's the rebuild - four orthogonal stop signals, any one of which ends the loop:

python
[object Object], ,[object Object],(,[object Object],):
    prev_states = []
    ,[object Object], step ,[object Object], ,[object Object],(max_steps):                     ,[object Object],
        result = agent.step(goal)
        ,[object Object], agent.believes_goal_met(result):           ,[object Object],
            ,[object Object], result, ,[object Object],
        ,[object Object], spend() >= max_spend:                       ,[object Object],
            ,[object Object], result, ,[object Object],
        h = state_hash(result)
        ,[object Object], h ,[object Object], prev_states:                           ,[object Object],
            ,[object Object], result, ,[object Object],
        prev_states.append(h)
    ,[object Object], result, ,[object Object],

What this does: it ends the loop on whichever fires first - a hard step ceiling, the agent judging the goal met, a spend limit, or a detector that spots the agent revisiting a state it's already been in - so no single failure mode can run the loop forever.

Each signal covers a gap the others don't. The report agent would have stopped at the budget cap or the step cap long before iteration 400, even though its own goal-met check never fired.

Breaking down each element

The hard step cap is the crude backstop that makes the loop finite no matter what. It's not elegant, but it's the one guarantee that the loop cannot run forever. Set it generously enough not to cut off real work, tight enough to bound the worst case.

The goal-met check stays - it's how the agent exits cleanly on a good run, and it should be the most common exit. The rebuild doesn't remove it; it stops relying on it as the only exit.

The budget cap ties termination to cost, which is what you actually care about protecting. On a task where each step is expensive, budget can bind before step count - which is why you want both. A slow, pricey step can blow the budget well inside the step limit.

The no-progress detector is the subtle one and the biggest information-gain here. By hashing the agent's state each step and checking for repeats, it catches the loop where the agent oscillates - polishes a sentence, un-polishes it, polishes it again - or revisits an identical state. Pure oscillation is invisible to step and budget caps until they're hit, but the no-progress detector catches it the moment the agent circles back, ending the loop early and cheaply.

⚡ Pro tip: Add a no-progress detector, not just a step cap. Comparing state hashes across steps catches oscillation and stuck loops far earlier than a step limit does - it stops the agent the moment it starts repeating itself, instead of after 25 wasted rounds.

Worth stressing: these four signals are meant to coexist, not compete. A common error is picking the "best" one and relying on it alone - but each covers a blind spot of the others. The step cap can't see cost; the budget cap can't see oscillation; the no-progress detector can't bound a run that makes tiny genuine progress forever; the goal-met check can't fire on an open-ended goal. Only together do they cover the full space of ways a loop fails to end. Dropping any one reopens exactly the gap it was there to close.

⚡ Pro tip: Always return why the loop stopped. "goal_met" versus "budget_reached" versus "no_progress_detected" tells you whether the run succeeded or was cut off - and which stop signal is firing most often tells you which one needs tuning.

How do you tune stop signals without cutting off real work?

Four stop signals raise an obvious worry: set them too tight and you kill runs that were about to succeed; too loose and you're back to the 400-iteration bill. Tuning the autonomous agent stopping condition is about finding, per signal, the setting that bounds the worst case without amputating good runs - and telemetry makes that a measurement instead of a guess.

The lever is the stop-reason your loop already returns. Run the agent across a realistic sample and tally which signal fired. If most successful runs exit via "goal_met" well under the step cap, your caps are safely loose. If a chunk of runs hit "step_cap_reached" and would have succeeded with a few more steps, your cap is too tight - raise it. The distribution of stop reasons tells you exactly which signal to adjust.

⚡ Pro tip: Watch the ratio of clean "goal_met" exits to forced exits (budget, step, no-progress). A healthy agent exits mostly clean. If forced exits dominate, your agent isn't finishing tasks - and no amount of cap-tuning fixes that; the goal or the plan is the problem.

Be most careful with the step cap, because it's the crudest signal and the most likely to cut off legitimate work. The better a task's other stop signals, the higher you can safely set the step cap - it's a backstop, not a primary control. Tasks with a reliable goal-met check and a good no-progress detector rarely reach the step cap at all, so setting it generously costs nothing while protecting against genuine runaways. The budget cap deserves the opposite treatment: set it to a number that would genuinely hurt to spend, and treat hitting it as an incident to investigate, not a routine exit.

⚡ Pro tip: Re-check your stop-reason telemetry after any significant change - a new model, a different task mix, a reworked prompt. A cap that was safe last month can quietly start cutting off good runs when costs or behavior shift underneath it.

Variations for different contexts

A content team running a drafting agent sets a low iteration cap deliberately - two or three passes - because they know diminishing returns hit fast on prose, and the goal-met check is unreliable for "good writing." The step cap is the real stop here.

A quant researcher running a data-analysis agent leans on the budget cap, because individual steps vary wildly in cost and a single expensive query can dominate spend. For them, dollars are the meaningful limit, not steps.

A support automation lead running a triage agent leans on the no-progress detector, because their failure mode is an agent that bounces a ticket between two categories indefinitely. Oscillation detection is what catches that, and neither cap would catch it as early - the ticket could bounce for dozens of cheap steps before a step or budget cap ever noticed.

Same four signals, different one doing the heavy lifting. A good autonomous agent stopping condition includes all four and tunes which dominates to the task's real failure mode.

Save and reuse this

The four-signal stop logic is exactly the kind of pattern worth standardizing - it's small, it's the same shape across almost every agent, and forgetting any one signal is how a runaway loop slips through. Keeping your stopping-condition patterns in PromptABCD means every agent you build ships with all four exits from the start, instead of you discovering the missing one at iteration 400 with a bill to match. Define the stop once; reuse the guarantee everywhere.

autonomous agent stopping conditionautonomous ai agentai agentsagent loopscost controlagent design

Continue Reading

Managing the Prompts Behind Autonomous Agents
Autonomous AI Agents

Managing the Prompts Behind Autonomous Agents

An agent broke in production after a deploy that 'changed no code.' The culprit was an untracked prompt edit. That's why autonomous agent prompt management is the discipline nobody budgets for until it bites.

October 7, 2026·8 min read
Budget Caps for Autonomous Agents
Autonomous AI Agents

Budget Caps for Autonomous Agents

Most advice on the autonomous agent budget cap stops at 'set a dollar limit.' That's the one that fails first. This case study shows the multi-layered caps that actually held.

October 7, 2026·8 min read
Cost Runaway: The Autonomous Agent's Biggest Risk
Autonomous AI Agents

Cost Runaway: The Autonomous Agent's Biggest Risk

Ever gotten a bill for an agent that ran overnight and did nothing useful? Autonomous agent cost runaway is the most common expensive surprise in agent work. Here's how it happens and how to stop it.

October 7, 2026·8 min read

Save the prompts from this post

PromptABCD is a free prompt manager. Paste, organize, and reuse your best AI prompts — no more hunting through chat history.

Start free →
← PreviousGiving an Autonomous Agent Tools SafelyNext →How to Keep an Autonomous Agent on Task
Share this post:
ShareShare