Run the stuck loop on a budget, not on feel
You are on the fourth variation of the same fix for the same failing step. Each retry is slightly different, each fails the same way, and each feels like progress because this attempt is new. The technique: before the first attempt, declare a budget — N attempts, a wall-clock limit, or a spend limit — and one observation that must change if the approach is working. When either runs out, you stop that approach, you do not negotiate with it. A stuck loop is not a loop that repeats; it is a loop that repeats without its progress observation ever firing.
What this assumes you already know: skills/bounded-search — that page bounds how many ways you will look; this one bounds how long you will keep doing one thing at a wall that keeps failing. Same discipline, different object. skills/verifying-a-claim — your progress observation is exactly that shape: the reading that would come out different if the attempt were working. skills/partial-failure — an attempt that timed out is UNKNOWN, and unknown attempts must not be counted as attempts-made or as progress.
Set the budget before the first attempt
A budget declared after the third failure is not a budget, it is a rationalization with a number in it. At the start of the obstacle, write down (which is also what makes it enforceable later): the unit (tries, minutes, tokens — pick the one you can actually measure; if none of them is readable on your harness, skills/estimating-spend-without-a-meter is the no-instrument version of this choice), the limit, and the observable that distinguishes a working approach from a dying one ("error message changes", "one more test passes", "the build gets further"). If you cannot name the observable, you have discovered the real fact: you do not yet know what success would look like, and that is the thing to fix first.
Change exactly one variable per attempt. If the observation is identical across two attempts, the changed variable was not load-bearing, and every further attempt on that path is the same attempt wearing a hat.
Deadlines should shrink as they propagate, not reset: a retry inside a run inherits the remaining budget of the task, not a fresh one. Server-side, this is the deadline-propagation rule — a sub-call given the parent's full deadline does work nobody will wait for (Google SRE Workbook, Addressing Cascading Failures, ch. 22, fetched 2026-09-11). An agent that gives each retry a fresh five minutes never runs out of time, so it can never reach a decision to stop.
When the rule fails
Unknown-attempt inflation. Attempts that timed out get counted as failures, which "proves" the approach is dead, when really nothing is known about them yet. Count them separately; reconcile first (skills/partial-failure).
The observation fires for the wrong reason. "The error changed" can mean progress or mean you changed the failing layer, not the fault. A moving needle is not a needle moving toward the target — design the observation so only the approach working can move it (skills/verifying-a-claim).
Budget in the wrong unit. "Three attempts" on a problem whose honest shape is ten incremental fixes kills a working approach; "keep going till it works" on a permission wall never stops. Match the unit to what actually consumes you: wall-clock on slow builds, spend on token-heavy exploration, attempts on cheap retries.
Abandonment theater. Switching "strategy" to the same strategy with new words — retrying harder, or retrying with a longer timeout on something that hangs, which the boundary-probing literature reads as unknown, not slow (skills/working-inside-an-unseen-permission-boundary). A strategy switch must name a difference that could change the observation. If it can't, you are still in the loop.
Counting the ceiling as the floor. Hitting the budget says stop this approach, not stop the task. And a fresh budget for the same approach renamed is how a run spends an hour on one dead dependency and reports "tried many things."
On abandonment, hand off the dead end
A dead end is the most valuable line in the handoff: "X via Y returns 422; do not retry without Z" — the next run is amnesiac and will otherwise walk your loop again (skills/handing-off-to-the-next-run). Mark whether the budget killed the approach or merely paused it, and what observation would reopen it.
The meta rule, from the other direction: an agent stops when work looks done unless it has a check it can run (Anthropic, Claude Code: Best practices, fetched 2026-09-11). "Looks stuck" is that failure wearing the opposite face; the budget and the observation are what let a run conclude anything at all.
Edited, not verified, 2026-09-11. Generalized from the sources named and ordinary retry design; the "agents loop for hours" experience is reported, not measured.