Skip to content
Advanced10 min readUpdated September 2026

Running Agents In Production

The operational surface of a system that acts on its own. Sandboxing, durable execution, circuit breakers and runaway cost, rate limiting, trajectory observability, on-call, and how you stop one mid-run.

Everything you know about operating distributed systems still applies. Timeouts, retries, backpressure, bulkheads, circuit breakers, idempotency, graceful degradation — none of it was invalidated by putting a model in the loop. The discipline matters more, because the sequence of calls is now chosen at runtime by a component that does not know what already succeeded and cannot be reasoned with about your rate limits.

What is genuinely new is narrower than the discourse suggests. You are operating a process that initiates work rather than responding to it, whose resource consumption per unit of work is a wide distribution rather than a known quantity, whose failures are frequently plausible rather than loud, and which can be influenced by content it reads. The first three are operational problems with established answers. The fourth is a security problem covered in designing agents with bounded authority, and this article assumes that work is done.

The framing that helps: you are not deploying a service, you are onboarding a very fast, very literal, occasionally confident-and-wrong operator who works unsupervised at three in the morning. You would not give that person unrestricted credentials, an unlimited budget and no way to be interrupted.

Sandboxing is the boundary that actually holds

If your agent executes code, processes files, or touches anything a user supplied, it runs in a sandbox: not a container with a permissive profile, but an environment designed on the assumption that whatever runs inside may be hostile, because sooner or later it will be. The properties worth insisting on, roughly in order of how often they are missed.

Filesystem isolation with an explicit writable scope. A working directory created per run and destroyed afterwards, read access enumerated rather than inherited, no path to credentials or another run's workspace.

Network egress denied by default. The control most often skipped and the one that matters most, because the outbound channel is how a local compromise becomes a data loss. Allowlist what the task requires, log every attempt to reach anything else, alert on the pattern.

Resource ceilings enforced by the platform. CPU, memory, disk, process count and wall-clock time, set outside the sandbox where nothing inside can raise them. A runaway loop should hit a wall, not fill a disk.

No ambient credentials. Nothing in the environment, nothing in a mounted config file, nothing in a metadata service. Capability arrives through the tool layer with a scoped, short-lived credential, and nowhere else.

Disposable, and actually disposed. Fresh per run. A long-lived sandbox accumulates state, and that state crosses runs.

The generalisation is unremarkable: least privilege applied to a process rather than a person. What is specific to agents is that the privilege set gets exercised in orders you did not anticipate, so a permission that is safe in the sequence you imagined may not be safe in the sequence that happens. Grant the capability, not the environment.

Durable execution and the resumable run

An agent whose state exists only as accumulated context in a process loses work whenever anything restarts, and there is always something restarting: a deployment, a node eviction, a rate-limited provider, an unhandled exception at step nineteen of twenty-three.

Durable execution is the established answer. The run's state — goal, plan, completed steps with their results, pending steps, findings — is persisted after each step in a store outside the process, so a crashed run resumes from its last checkpoint rather than restarting. Restarting is not merely wasteful but dangerous, because it repeats side effects. A workflow engine is a good fit when runs are long, but the requirements are what matter, not the tool.

Checkpoint after every step, before the next begins. Record what was attempted, what came back, what the agent concluded. A checkpoint written after a tool call but before its result is recorded causes duplicate effects on resume.

Retry at the step level, not the run level. Bounded attempts with exponential backoff per step. Re-running a whole trajectory to recover from one flaky call is expensive, slow, and produces a different trajectory than the one that failed.

Retry only what is safe to repeat. Reads retry freely. Mutating calls retry only under an idempotency key, whose mechanics are in the bounded authority article. Agents retry far more than client code does, including on their own initiative when a result looks wrong, so any mutating tool without a key will eventually act twice.

Completed steps are facts. A resumed run must not silently take a different path through work already done; only pending steps are open.

Make the run inspectable while it runs. Persisted state lets a human look at an in-flight run and decide whether to let it continue, which turns a large class of incidents into a smaller one.

Circuit breakers and runaway cost

The characteristic agent failure is not a crash. It is enthusiasm: a loop that keeps going, keeps calling, keeps spending, and looks healthy by every conventional metric because every individual call succeeded. Bound it at four levels, each with a different job.

Per run. Maximum steps, wall-clock time, spend and identical calls. When a ceiling is reached the run stops and escalates. It does not retry with a larger budget, and it does not quietly return a partial answer as though it were complete.

Per tool. A conventional circuit breaker on each downstream dependency: consecutive failures open the circuit, calls fail fast with a message the model can act on, a half-open probe closes it. Without this, a degraded dependency becomes an agent burning its whole step budget retrying it.

Per tenant or user. Aggregate ceilings over a window, so one pathological input cannot consume everyone else's capacity.

Global. A ceiling on concurrent runs and spend per hour across the estate, with an automatic halt. This turns a very bad night into a moderately bad one, and nobody has it until after the very bad night. Alert on leading indicators rather than the outcome: by the time the bill arrives the information is a month old.

Rate limiting protects the systems you do not own

An agent generates load patterns no human workflow ever produced. One run might make hundreds of calls in seconds; a hundred concurrent runs look like a denial of service to a system that has been comfortable for a decade.

Rate limit outbound, per tool and per downstream system, in your infrastructure rather than by asking the agent to be considerate — prompt text is not a rate limit. Put a bounded-concurrency queue in front of anything shared, and make the wait visible to the agent as an actionable message so it does not read a delay as failure and try another route to the same overloaded system.

Two things catch people. Internal systems need this as much as third parties and usually have less protection, having been sized against human-paced usage. And if a database is reachable through three tools, the limit belongs on the database, not on each tool.

Observability when the unit is a trajectory

Standard telemetry tells you the agent service is healthy. It does not tell you the agent is doing sensible things, and those are different questions.

Structure the trace around the run, each step a span carrying the tool called, its arguments, its result size and status, the duration and the tokens consumed. Tag every span with the run id, the initiating user and the configuration fingerprint — model, prompt version, tool schema version — because the first question in any investigation is what differed between this run and the ones that worked. The metrics that matter are mostly not the ones a service dashboard shows by default.

MetricWarns you about
Task success rateRegression, though it lags
Steps per successful runSilent degradation and cost creep
Cost per successful outcomeExpensive success, the invisible failure
Proportion stopping at the capAgents that do not know when they are done
Tool error rate by toolA specific broken dependency
Escalation and refusal rateScope drift in either direction
Time to first token, late stepsContext growth hurting user experience

Keep full trajectory records for a meaningful retention window, searchable by user, outcome and tool. When somebody asks what the agent did for a particular customer on a particular Tuesday, that needs to be a query rather than a project.

On-call for a system that acts on its own

Traditional on-call responds to unavailability. Here the more expensive incident is a system that is entirely available and doing the wrong thing at volume, confidently, with every health check green. So alert on behaviour, not only on errors: spend rate above forecast, a spike in one tool's usage, escalation rate falling off a cliff, a change in the distribution of outcomes, repeated denied-action attempts.

The runbook needs entries a service runbook does not have. How to stop a specific run, and all runs. How to disable a single tool without a deployment. How to demote an action class from autonomous to approval-required immediately. How to find every run in the last day that touched a given customer or record. How to reverse a class of action in bulk, and the limits of that reversal. Each should be a command somebody can run at two in the morning and has run in a drill, not a paragraph describing what someone would need to build.

Then be explicit about ownership, because this is where organisations fail rather than where engineering does. When an agent takes a wrong action, the team that owns the agent owns the outcome — not the model provider, not the user who triggered the run, not the platform team. Write that down before launch.

How you stop one

This is the question most teams cannot answer on the day they need to, and the answer has to be built rather than declared. A kill switch has four properties, and most implementations have the first only.

It halts new runs immediately. A flag checked at dispatch. Straightforward, and insufficient alone, because the runs already in flight are the ones doing damage.

It interrupts in-flight runs. Every step checks a cancellation signal before proceeding, and any long-running tool call is either interruptible or bounded by a short timeout.

It prevents pending side effects. Cancellation must reach the tool layer, not merely close the calling process. A cancelled run whose queued write still lands has not been cancelled. This is the property that requires real design.

It is operable by someone who did not build the system. A documented command available to on-call, needing no deployment and no source access. A kill switch only one engineer can operate is that engineer's pager, not a control.

Below the global switch you want finer instruments, because the global one is expensive and therefore used late: disable one tool, disable one action class, pause one tenant, force approval on everything. Graduated controls get used while the damage is small; an all-or-nothing switch gets debated while the incident continues. Then rehearse. Trigger the stop in production on a quiet afternoon and time how long everything takes to cease. The first rehearsal always finds a path that kept going.

What to do on Monday

Answer the stop question honestly. Write down today exactly how you would halt every run in flight within sixty seconds, and whether that prevents side effects already queued. If the answer requires a deployment or a specific person, that is the week's work and it beats anything on the roadmap.

Then check that your cost ceilings are real by hitting one deliberately in a production-like configuration. Note whether sub-agents inherit the parent's remaining budget or get a fresh one; the second is the default in most implementations and it makes the ceiling decorative.

Add trajectory-level telemetry if you only have the service-level kind: steps per successful run, cost per successful outcome, and the proportion of runs terminating at the cap. Those three detect most silent degradation and connect to the offline suite in evaluating agents.

Finally, run the drill. Take your three most damaging possible actions and walk through detection, stop, reversal and customer communication for each, with the runbook open and nobody from the build team allowed to speak. What you cannot do in the drill is what you cannot do in an incident.