Build
Policies
Declarative JSONLogic, evaluated server-side with no LLM. Reviewable in a PR, diffable across environments, queryable by an auditor.
Anatomy
{
"name": "finance-large-transfers",
"priority": 10,
"conditions": { "==": [{ "var": "tool" }, "transfer_funds"] },
"auto_reject": { ">": [{ "var": "args.amount" }, 100000] },
"auto_approve": { "<": [{ "var": "args.amount" }, 100] },
"approver_group": "finance",
"sla_seconds": 300
}Available variables: tool, args.*, agent_id, originator, session_id. Operators are a ~12-op whitelist (no eval, no exec).
Precedence (reject-wins)
Policies evaluate in priority ascending. For a matched policy:
- auto_reject first (reject-wins) → auto-rejected.
- auto_approve second → auto-approved (provenance
policy). - Otherwise → notify the approver group.
Versioning
Every change to a policy's decision logic bumps an immutable version and snapshots the full definition to policy_versions. That answers "which exact rule decided this?" — toggling shadow mode is operational and does not bump the version.
Shadow mode
A feature flag for safety: test a new (or edited) policy against live traffic without it deciding anything. The evaluator records what each shadow policy would have done to policy_shadow_evaluations. Compare, then promote.
# Create a policy in shadow mode: it's evaluated and logged,
# but never affects the real decision. Compare, then promote.
POST /api/v1/policies { ..., "shadow": true }
# Promote (start deciding):
PATCH /api/v1/policies/:id { "shadow": false }