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 or block (the engine path). escalate is produced when a rule requires human approval. |
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