Runtime enforcement & approvals
Observation tells you what your agents are doing. Enforcement acts on it: blocks the calls policy denies, and holds the riskiest ones for a human — per environment, per rule, never all-or-nothing.
Layers 1–3 built a directory of agents, a policy for what each may do, and a gateway that watches every tool call — in observe mode, where nothing is ever blocked and would-block rows preview what enforcement would do. Layer 4 is where the same decision function grows teeth. Flip an environment (or a single tool) from observe to enforce, and a denied call never reaches the upstream: the agent gets a clean, machine-readable 403 and an alert fires. Nothing else about the pipeline changes — enforcement acts on decisions observe mode was already making.
Enforcement is graduated on purpose. You enforce in staging while production still observes, or enforce one dangerous tool while everything else logs. And for calls too risky for even a correct policy to wave through alone, the approval gateway pauses the call mid-flight until a human approves, denies, or the window expires — and an expired window is always a deny, never a silent yes.
At a glance
| What it governs | What a policy decision does at runtime: forwarded, blocked before the upstream, or held for a human decision. |
| Key objects | Enforcement mode (observe / enforce / require_approval), approval (a held call with a pending row and a countdown), alert (Slack / email event), fail mode (open / closed on policy-engine error). |
| Where it lives | The enforcement: section of your policy YAML (edited on the Policy page, live within seconds), the /approvals API, and the dashboard's approvals queue. |
| Depends on | Layers 1–3: agent identity names the caller, policy makes the decision, and the gateway is the choke point where enforcement can act. See the five layers. |
| Consumed by | Humans (layer 5) — approvers with the security role decide held calls; alerts summon them. |

When you need this layer
You need layer 4 the day observation stops being enough: when a would-block row in the live feed is a call you needed stopped, not narrated. Concretely — an agent is one bug away from delete_repo in production; a compliance control requires that denied calls are actually denied; or your highest-blast-radius tools should never run without a named human saying yes. If observe mode has never shown you a surprise, you can stay on layer 3 indefinitely — enforcement waits in the YAML, commented out.
Honest limits
| Limit | What to do about it |
|---|---|
| A wrong enforce-mode policy blocks legitimate traffic — enforcement is exactly as correct as your policy. | Observe first, always. Run every rule in observe until its would-block rows look right, then flip one environment at a time. The rollout guide is the runbook. |
| Human approval adds real seconds to a held call — the agent's connection waits while a person decides (default window: 60 s). | Only put approval rules on calls that can tolerate the wait. A latency-critical call and a human in the loop are incompatible by definition. |
The default fail mode for policy-engine errors is open: the call passes and a warning is logged. If you don't choose, you have chosen open. | Security-critical environments must set fail_mode: closed explicitly. Read Trust & reliability before enforcing in production. |
| Enforcement only governs traffic routed through the gateway — layer 3's bypass limitation applies here with higher stakes. | Ghost detection (layer 3) names direct-to-upstream callers; it cannot stop them. |