Operations · · 8 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 an answer in seconds: how to stop it. Whatever fix or audit follows depends on stopping it first — before the next action it picks reaches data it shouldn't, sends a message that escapes the system, or destroys something that can't be recovered.
This is the containment surface. It's the third primitive after identity and runtime enforcement. Most agent runtimes underbuild it, because the failure case feels rare during development. It's the failure case the security team is most insistent about during procurement. It's also the zero-lag mechanism in the discovery-lag taxonomy: pause and stop assume a human has already found out something is wrong. They bound the damage from that point forward; they don't prevent what already happened.
Three outcomes, not one#
"Stop the agent" is too coarse to be the only containment primitive. What the operator actually needs is a small vocabulary of containment outcomes, each with different semantics and different blast radius.
Stop. The agent's next action is denied. Any sub-agents the agent has spawned are also stopped. The agent's run is marked terminated, and the runtime no longer evaluates actions on the agent's behalf. Stop is the right outcome when the agent is acting incorrectly and the operator wants no further actions of any kind from it.
Scope. The agent's scope is narrowed mid-run. The agent's identity is updated to remove access to whatever resource class is the problem; the next action against that resource class is denied; actions inside the remaining scope proceed. Scope is the right outcome when the agent is mostly doing the right thing but has drifted into something it should not be touching — read it out of the scope without killing the whole run.
Quarantine. The agent's actions are still evaluated, but every action becomes require-approval regardless of policy. The agent keeps running; the operator is paged for every step. Quarantine is the right outcome when the operator isn't sure whether the agent is going wrong and wants visibility-with-control until the situation is clearer.
These three outcomes differ in what they cost the operator and what they save. Stop is cheap to invoke and expensive in lost work (the agent's progress is discarded). Scope is precise but requires the operator to know which resource class is the problem. Quarantine is the highest-friction outcome — the operator is now in the loop for every action — but preserves the run.
The three should all be reachable from the same surface: the containment control plane the policy gate is part of. The same component that knows the agent's identity and policy is the right component to revoke or narrow them.
The credential revocation problem#
A natural first instinct for "stop the agent" is "revoke the credential the agent is using." This 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 address credentials already in flight.
Credentials in flight are the actions the agent has already started but not yet completed. An HTTP request that was constructed before the revocation but lands at the resource server after. A database transaction that's mid-commit. An MCP tool call whose response is in the network stack. Revoking the credential at the issuer does not retract these in-flight actions; they have to be denied at the destination, which means the destination has to validate the credential against the current issuance state, not its own cached copy.
Credentials cached by downstream services are the same problem at a slower clock. If a downstream service caches the credential's validity for thirty seconds, the agent's actions continue to be authorized for thirty seconds after revocation. The fix is either short cache lifetimes (with latency cost on every action) or push-based revocation (where the issuer notifies the cache). Production systems use both, depending on the resource.
Credentials held by sub-agents are the worst version. A top-level agent that spawns five sub-agents may have distributed credentials (or scoped versions of its own credential) to each. Revoking the top-level credential does not necessarily revoke the sub-agent credentials; if the issuance system minted independent credentials for each sub-agent, those continue to be valid until separately revoked.
The architectural pattern that addresses all three is to bind every credential to a run id, and to revoke at the run level rather than the credential level. The runtime maintains the active-runs set; the policy gate checks the action's run id against the set on every evaluation. Revoking a run removes it from the set. In-flight credentials whose run is revoked fail their next gate check, regardless of which sub-agent holds them. The latency cost is the per-action gate evaluation that's already in the budget.
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; a transaction that has already committed cannot. An email message in the outbound queue can be discarded; an email already accepted by the recipient cannot. An API call that has produced an effect downstream cannot be undone by the agent's runtime.
The containment surface has to make this explicit. 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 is the one the security team cares most about during incident response. The audit log carries the completed actions; the containment report is what tells the operator which of those they need to investigate.
The sub-agent cascade#
Sub-agents complicate containment. A top-level agent that spawns parallel sub-agents to handle independent pieces of work is doing the right thing performance-wise, but it means a containment action against the top-level agent has to propagate to the sub-agents.
Three propagation rules a runtime can adopt:
- 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, sub-agents inherit the quarantine.
- Sub-agents are independently containable. The operator can stop a single sub-agent without affecting siblings or the parent. Useful when one sub-agent is the problem and the rest are doing the right thing.
- Sub-agents have their own identity in the audit log. The containment report distinguishes which sub-agent was contained, in what state.
These rules are not mutually exclusive. A reasonable default is that sub-agents inherit containment from the parent unless explicitly retained. The retain operation is rare; the inherit operation is what the operator wants in 95% of cases.
Cooperative vs forced containment#
When the runtime decides to stop an agent, the agent itself can be told to stop, or it can be stopped against its will.
Cooperative containment sends a signal to the agent's loop: stop calling tools, finalize the run. The agent acknowledges, completes its current action, and exits. This is the cleanest outcome when it works. The risk is that the agent's loop might not check for the signal in time, or might be in a state where it can't acknowledge — the model is processing, the runtime is waiting on a long tool call.
Forced containment doesn't depend on the agent's loop. The runtime denies every subsequent gate check, and the agent's tool calls all return denied. The agent's loop sees denial after denial and eventually concludes its work cannot proceed. This is slower in the sense that the agent makes a few more attempts before exiting, but it is robust to the agent being uncooperative or stuck.
Production runtimes use both, with forced containment as the floor: cooperative containment is faster when the agent's loop responds, but forced containment is what still works when it doesn't.
Containment latency#
The end-to-end latency of containment matters more than the latency of any individual gate check. The window between the operator hitting stop and the agent ceasing to act is the window in which damage can occur.
A reasonable target for forced containment: under one second from operator input to the next denied action. This assumes the runtime is on the action path. If the runtime is out-of-band — analyzing logs after the fact — containment latency is bounded 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, if the operator is using a web UI on a CDN-cached client.
- Containment control plane to active-runs set update: tens of milliseconds, with a distributed store.
- Active-runs set to policy gate: zero (the gate reads the set on every evaluation).
- Policy gate to denied action: per-action latency, sub-millisecond.
The bottleneck is the active-runs set propagation. A common implementation: in-memory cache with TTL of one second, refreshed from a durable store. The trade-off is that revocations take up to a second to be visible; the alternative — synchronous propagation — adds latency to every gate check.
For most use cases, the one-second window is acceptable. For regulated use cases, synchronous propagation is the right answer despite the latency cost.
Containment as the third primitive#
Identity and runtime enforcement are the two primitives most agent-security writing focuses on. Containment is the third, and underbuilt in proportion to how important it is during real incidents. A runtime that ships strong identity and policy enforcement but a coarse single-button kill switch will fail at the moment of incident response — the operator needs to scope, not stop, and the runtime can only stop.
Deixic's containment surface exposes all three outcomes — stop, scope, quarantine — from the same control plane that issues identity and evaluates policy. The kill switch and the audit row both inherit from the same evaluation. See Trust for the security posture and What you can do for the action-time gate.