pliuz

Build

Policies

Declarative JSONLogic, evaluated server-side with no LLM. Reviewable in a PR, diffable across environments, queryable by an auditor.

Anatomy

policy JSON
{
  "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:

  1. auto_reject first (reject-wins) → auto-rejected.
  2. auto_approve second → auto-approved (provenance policy).
  3. Otherwise → notify the approver group.
If no policy matches, the request is rejected with 422 (fail-closed). A malformed sub-expression is skipped with a structured log — relative to that rule it is fail-open, so surface eval errors in review.

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.

shadow → 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 }