Your Agent Needs a Supervisor, Not a Retry Loop
Your agent died at step seven of a twelve-step task. The framework caught the exception, waited with exponential backoff, and retried. It retried the step — with the same context window that had accumulated three failed tool calls, a half-parsed error message, and a plan the model had already abandoned. The retry failed too, of course, because a retry is a bet that the world changed, and nothing about that agent's world had changed. What needed to change was the agent's state — and no retry policy in any agent framework makes that decision.
Erlang's OTP libraries codified this exact decision thirty years ago, for telephone switches that had to run for decades. The insight behind supervisor trees was never "restart things when they crash." It was that how to recover is a separate concern from doing the work, owned by a separate process, arranged in a hierarchy where each level knows a little more about what recovery means. Most agent frameworks today bolt retries onto individual calls, which is like putting a try/catch around every line of a telephone switch. What they need is the hierarchy.
Retries Are a Policy for Calls. Supervision Is a Policy for Processes
The retry logic shipping in most agent stacks today answers one question: should this API call run again? That question has a good answer — retry 429s and 503s with backoff, fail fast on auth errors, cap the budget. Gateways and client libraries handle it well, and it belongs exactly where it lives: at the call site.
But an agent loop is not a call. It is a long-running process with accumulated state: a context window, a scratchpad, tool results, partially committed side effects. When the loop itself breaks — the model paints itself into a corner, a tool returns something that poisons the context, the process OOMs at step seven — retrying the call is answering the wrong question. The right question is the one OTP asked: this process has failed; what do we do with its state?
There's a mechanism worth stealing here, and recent research backs up why. When an agent fails and retries in place, the failure stays in its history — early wrong attempts contaminate everything the model produces afterward. Practitioners see this constantly: an agent that has argued itself into a bad plan does not recover by being told to try again. It recovers by being restarted with a cleaner view of the world. That is a supervision decision, not a retry decision, because the component that failed cannot be the component that decides how to recover from its own failure.
The Three Decisions OTP Codified
Strip away the Erlang-specific machinery and a supervisor makes exactly three choices for each failed child, and every one of them maps directly onto agents:
- Restart with clean state. The OTP default. The process comes back at its initial state, on the theory that most failures are transient and state corruption is the disease, not the symptom. For agents: rerun the step with a fresh context — the original task, the durable facts, none of the failure debris. This is the "let it crash" philosophy, and it works precisely because the restart is clean.
- Restart with saved state. The process resumes from a checkpoint that was written before things went wrong. For agents, this is what the durable-execution wave — Temporal, Inngest, DBOS, Restate, LangGraph's checkpointers — provides: journal each completed step, and on recovery replay from the log instead of repeating work. Completed tool calls return cached results; the crashed step runs anew.
- Escalate. The supervisor itself gives up and fails upward, to a parent supervisor with broader authority — or, at the root of an agent system, to a human. OTP made this quantitative with restart intensity: more than
max_restartsfailures withinmax_seconds, and the supervisor stops restarting and dies, propagating the failure up the tree.
That third one is the piece agent frameworks are most conspicuously missing. Retry policies have a max-attempts number, but when it's exhausted the task just... fails. An exhausted retry budget carries no information about what kind of intervention comes next.
In a supervision tree, exhaustion is itself a signal that travels somewhere: to a coarser recovery strategy, a different model, a different decomposition of the task, or a person. Restart intensity is your human-escalation budget, stated as configuration instead of vibes.
OTP even distinguishes which exits deserve restarts: permanent children always restart, temporary children never do, transient children restart only on abnormal exit. Agents need the same taxonomy. A monitoring agent that watches a queue is permanent. A fire-and-forget summarization is temporary — if it dies, drop it. A code-migration step is transient: restart it if it crashed, but not if it exited cleanly after deciding the file needed no changes. Frameworks that treat every failure identically will restart things that should stay dead and abandon things that should come back.
One-for-One, Rest-for-One: Restart Topology for Pipelines
OTP's second contribution is that the restart decision depends not just on the failed process but on its relationships. A supervisor declares a strategy for the whole group:
- One-for-one: a child crashes, only that child restarts. Correct when children are independent.
- One-for-all: any child crashes, every child restarts. Correct when children share state that a failure may have corrupted.
- Rest-for-one: a child crashes, and that child plus every child started after it restarts. Correct when later children depend on earlier ones.
- https://www.erlang.org/doc/system/sup_princ.html
- https://www.inngest.com/blog/durable-execution-key-to-harnessing-ai-agents
- https://www.dbos.dev/blog/durable-execution-crashproof-ai-agents
- https://mastra.ai/blog/what-are-durable-ai-agents
- https://docs.langchain.com/oss/python/langgraph/persistence
- https://portkey.ai/blog/retries-fallbacks-and-circuit-breakers-in-llm-apps/
