Browse documentation

How do I write a policy?

A policy is an ordered list of rules. The first rule that matches a call decides it; if none match, the policy's default decision applies — and if that's unset, the engine denies.

The shape of a rule

Each rule matches a tool and yields a decision:

a single rule
{
  "tool": "send_*",
  "decision": "require_approval",
  "where": [
    { "path": "to", "matches": "@example\\.com$" }
  ]
}
  • tool — a glob over the tool name. * matches any run of characters, ? a single character. send_* matches send_email, * matches everything.
  • decisionallow, deny, or require_approval.
  • where — optional argument conditions, AND-ed together. A rule only matches if its tool glob and every condition match.

Argument conditions

Conditions test the call's arguments by a dot-path. Use matches / notMatches for regular expressions (with an optional flags), or equals for a deep equality check:

conditions
"where": [
  { "path": "amount",     "matches": "^[0-9]{4,}$" },
  { "path": "user.role",  "equals": "admin" },
  { "path": "to",         "notMatches": "@trusted\\.com$", "flags": "i" }
]
An invalid regex never matches — combined with default-deny, a malformed rule fails safe rather than letting calls through.

Order and priority

Within a policy, rules are evaluated top to bottom and the first match wins — put your most specific rules first. When a key has its policy evaluated, enabled policies are sorted by priority (highest first), then rules within them.

The default decision

If no rule matches, the policy's defaultDecision applies. Leave it unset to fall through to the engine default, which is deny. A common pattern is an allowlist policy that ends in an explicit deny catch-all:

allowlist policy
[
  { "tool": "read_*",   "decision": "allow" },
  { "tool": "list_*",   "decision": "allow" },
  { "tool": "send_*",   "decision": "require_approval" },
  { "tool": "*",        "decision": "deny" }
]

Arguments are never stored

Conditions run against the arguments in memory only. The audit log stores a sha256 hash of the canonicalized arguments, never the values themselves. See security & data handling.

Test any rule set against sample calls in the dashboard Playground before you attach the policy to a live key.