Skip to content

Verdicts, obligations & mandates

govern() returns a Decision — a frozen, auditable record of what the policy concluded and what must happen next.

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.

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.

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.

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.email

Executors 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.

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.