Verdicts, obligations & mandates
govern() returns a Decision, a frozen, auditable record of what the policy concluded and what must happen next.
Decision fields
Section titled “Decision fields”| Field | Meaning |
|---|---|
outcome |
allow, block, or needs_approval (when a rule requires human approval). (escalate, modify, and dispatch_to_sandbox are reserved internal names the pipeline does not emit yet.) |
reason |
Machine-readable cause, e.g. pii_in_input, no_policy_compiled. |
behavior_id, pipeline_id |
Correlation IDs echoed back; the audit trail is queryable by both. |
decided_at |
UTC timestamp of the verdict. |
details |
evidence, rule_id, rule_kind, category, which rule decided, and everything it saw. |
obligations |
Effects the caller must apply (see below). |
mandate |
short-lived signed token minted on allow (see below). |
approval |
Approval evidence when the call resumes a granted approval. |
A blocked call carries the full evidence of why, the same evidence written to the audit trail. There is no difference between what the caller sees and what an auditor sees.
Obligations: effects, not just verdicts
Section titled “Obligations: effects, not just verdicts”A verdict can carry obligations, typed instructions the runtime applies around the decision:
| Obligation | Timing | Effect |
|---|---|---|
redact |
pre / post | Mask detected spans (PII, secrets) in the prompt, messages, tool args, or response, the call continues with clean content |
redact_tool_arg |
pre | Regex-replace a pattern in a named tool argument |
route_to_model |
pre | Rewrite the target model (e.g. force a tier: frontier → local) |
require_approval |
pre | Suspend the call and open a human-approval request |
rewrite_response |
post | LLM auto-correct the response against a criterion (fail-open) |
filter_tools |
pre | Restrict the visible tool list (MCP tool visibility) |
requires_audit_signing |
, | Mark the record for the signing layer |
Obligations are discharged by registered handlers, and a failing handler fails closed, if redaction can’t be applied, the call doesn’t go through. The one deliberate exception is rewrite_response, which is fail-open by design.
Redaction is the important mental shift: policy isn’t only yes/no. “Strip the SSN and let the call through” is a first-class outcome, expressed as allow + a redact obligation.
Approvals
Section titled “Approvals”A rule of kind RequireApproval turns the verdict into an approval request instead of a block. The caller gets a request_id and a fingerprint; a human decides in the dashboard, the CLI, or via WebAuthn-signed approval. When the call is resubmitted, the granted approval appears in subject.approval and the rule passes. One approval authorizes exactly the fingerprinted action, not the agent’s next fifty actions.
Mandates
Section titled “Mandates”On allow, the kernel mints a mandate: a compact, short-lived signed mandate naming the authorized capabilities:
llm:call:gpt-4o tool:call:send_email sor:write:customer.emailExecutors verify mandates offline against the JWKS published at /.well-known/jwks.json (or via POST /v1/tokens/verify). The mandate is how a decision made at the gateway stays meaningful at the point of execution: a tool server can prove this exact call was authorized, moments ago, by policy it never had to load.
There is no revocation list, the TTL is the revocation window.
Determinism
Section titled “Determinism”Verdicts are deterministic: the same policy and input always produce the same verdict, which is what makes replay provable. This is what makes the audit trail more than a log: you can replay any historical decision against a different policy version and get a provable what-if answer.
Next steps
Section titled “Next steps”- Policies, rules & bundles, where verdicts come from
- Rule reference, the rules that produce these outcomes and obligations