Operations · · 7 min read
Stopping a running agent
Three containment outcomes (stop, scope, quarantine), the credentials-in-flight problem, the sub-agent cascade, and what a kill switch actually means at runtime.
When an agent goes wrong in production, the platform team needs to stop it in seconds. Any fix or audit depends on that, because the agent's next action can reach data it shouldn't, send a message that escapes the system, or destroy something that can't be recovered.
This is the containment surface, the third primitive after identity and runtime enforcement. Most agent runtimes underbuild it because the failure case feels rare during development, and it is the case the security team presses hardest on during procurement. It is also the zero-lag mechanism in the discovery-lag taxonomy: pause and stop assume a human has already found out something is wrong. They limit the damage from that point forward and do nothing about what already happened.
Three outcomes#
"Stop the agent" is too coarse to be the only containment primitive. The operator needs three outcomes with different blast radius.
Stop. The agent's next action is denied, and any sub-agents it spawned are stopped too. The run is marked terminated, and the runtime no longer evaluates actions on the agent's behalf. Use stop when the agent is acting incorrectly and the operator wants no further actions of any kind.
Scope. The agent's scope is narrowed mid-run. Its identity loses access to the resource class that is the problem, the next action against that class is denied, and actions inside the remaining scope proceed. Use scope when the agent is mostly doing the right thing but has drifted into something it should not touch.
Quarantine. The agent's actions are still evaluated, but every action becomes require-approval regardless of policy. The agent keeps running and the operator is paged for every step. Use quarantine when the operator is unsure whether the agent is going wrong and wants visibility with control until the situation is clearer.
The costs differ:
| Outcome | Cost to invoke | What it loses or requires |
|---|---|---|
| Stop | Cheap | The agent's progress is discarded |
| Scope | Precise | The operator must know which resource class is the problem |
| Quarantine | Highest friction | The operator is in the loop for every action, but the run survives |
All three should be reachable from the same surface: the containment control plane the policy gate is part of. The component that knows the agent's identity and policy should revoke or narrow them.
The credential revocation problem#
The first instinct for "stop the agent" is to revoke the credential the agent is using. That works for service-account architectures where the credential is the gating mechanism. For ephemeral-identity architectures it works at the issuance layer but does not reach credentials already in flight.
Three forms of the problem:
- Actions already started. An HTTP request constructed before revocation lands at the resource server after it. A database transaction is mid-commit. An MCP tool call has its response in the network stack. Revoking at the issuer does not retract these, so the destination has to validate the credential against current issuance state instead of its own cached copy.
- Downstream caches. If a downstream service caches a credential's validity for thirty seconds, the agent stays authorized for thirty seconds after revocation. The fix is short cache lifetimes (with a latency cost on every action) or push-based revocation, where the issuer notifies the cache. Production systems use both, depending on the resource.
- Sub-agent credentials. A top-level agent that spawns five sub-agents often gives each a credential or a scoped version of its own. Revoking the top-level credential does not revoke independently minted sub-agent credentials until they are revoked separately.
One pattern addresses all three: bind every credential to a run id and revoke at the run level. The runtime maintains the active-runs set, and the policy gate checks the action's run id against it on every evaluation. Revoking a run removes it from the set, and in-flight credentials for that run fail their next gate check whichever sub-agent holds them.
In-flight actions#
Even with run-level revocation, some actions cannot be retracted once started. A database transaction in pending state can be rolled back and a committed one cannot. An email in the outbound queue can be discarded and one the recipient's server has accepted cannot. An API call that has produced a downstream effect cannot be undone by the agent's runtime.
Stop revokes the run's authority and reports the work that had already committed.
When the operator hits stop, the runtime should report:
- Actions denied (the next action and any queued actions)
- Actions in flight, with status (some recoverable, some not)
- Actions completed during the window before the stop took effect
The third category matters most during incident response. The audit log carries the completed actions, and the containment report tells the operator which of them to investigate.
The sub-agent cascade#
A top-level agent that spawns parallel sub-agents is doing the right thing for performance, but a containment action against it has to propagate to them. Three propagation rules:
- Sub-agents inherit containment. When the parent is stopped, sub-agents are stopped. When the parent is scoped, sub-agents inherit the narrowed scope on their next action. When the parent is quarantined, they inherit the quarantine.
- Sub-agents are independently containable. The operator can stop one sub-agent without affecting siblings or the parent, which helps when one sub-agent is the problem.
- Sub-agents have their own identity in the audit log. The containment report shows which sub-agent was contained and in what state.
A reasonable default is that sub-agents inherit containment from the parent unless the operator explicitly retains them. Retaining is rare, and inheriting is what the operator wants in about 95% of cases.
Cooperative and forced containment#
The runtime can tell the agent to stop, or stop it regardless of what the agent does.
Cooperative containment sends a stop request to the agent's loop: stop calling tools and finalize the run. The agent acknowledges, completes its current action, and exits. This is the cleanest outcome when it works. It fails when the loop does not check for the request in time or cannot acknowledge, for example while the model is processing or the runtime is waiting on a long tool call.
Forced containment does not depend on the loop. The runtime denies every subsequent gate check, so every tool call returns denied. The agent makes a few more attempts before concluding its work cannot proceed, which is slower, but it works when the agent is uncooperative or stuck.
Production runtimes use both, with forced containment as the floor.
Containment latency#
The end-to-end latency of containment matters more than the latency of any single gate check. The window between the operator hitting stop and the agent ceasing to act is the window in which damage occurs.
A reasonable target for forced containment is under one second from operator input to the next denied action. That assumes the runtime is on the action path. A runtime that analyzes logs after the fact has containment latency set by the slowest cache TTL in the credential path, which can be much longer.
Where the second goes:
- Operator input to the containment control plane: tens of milliseconds, using a web UI on a CDN-cached client.
- Control plane to active-runs set update: tens of milliseconds, with a distributed store.
- Active-runs set to policy gate: zero, because the gate reads the set on every evaluation.
- Policy gate to denied action: sub-millisecond per action.
The bottleneck is active-runs set propagation. A common implementation is an in-memory cache with a one-second TTL, refreshed from a durable store, so revocations take up to a second to become visible. Synchronous propagation removes that window and adds latency to every gate check. One second is acceptable for most use cases. Regulated use cases should pay for synchronous propagation.
Containment as the third primitive#
Containment is underbuilt in proportion to how much it matters during real incidents. A runtime with strong identity and policy enforcement but a single coarse kill switch fails at the moment of incident response: the operator needs to scope the agent, and the runtime can only stop it.
Deixic checks policy on routed tool calls and retains approval and execution history. The pause guide covers the app's pause control, which changes agent status and does not cancel an in-progress tool call. Stop, scope, and quarantine are the containment requirements to evaluate in your own runtime; the pause control does not provide them. Keep tested containment procedures with the company's skills and checks.