Developer documentation
Policies
Last reviewed 31 August 2026
Policies
Default deny
cain init writes policy.default: deny. Anything without an explicit rule is
refused. This is the point of the platform; change it deliberately, and `cain
doctor will warn you for as long as it is allow.
policy: default: deny
Where policy is evaluated
Policy is evaluated server-side, by the fabric, from the tenant resolved from
your credential. It is not evaluated in the SDK and cannot be influenced by
anything the caller sends -- an agent cannot raise its own ceiling.
Inspecting and testing
cain policy show
cain policy test --action /refund --resource billing
cain policy test --action /refund --resource billing --payload '{"amount":100000}'
policy test is a dry run: it evaluates and reports, with no enforcement and no
side effects. Use it to answer "would this be allowed?" before shipping a change.
Policy versions
Every decision records the policy version that produced it, captured at decision
time rather than looked up later. That is what keeps an old decision explainable
after the policy changes -- resolving the version at explain-time would describe
today's policy while claiming to explain last month's decision.
cain explain <decision-id> # shows the policy version column
Tool restrictions
tools: allow: [send_email, read_crm] deny: [delete_customer]
An empty allow list means "no tool-level restriction *here*" -- server-side
policy still applies. It does not mean everything is denied. cain doctor
warns when both lists are empty, because "no restriction configured" is easy to
mistake for "restricted".
Requiring a human
policy: require_approval_above_risk: high
Produces the REQUIRE_APPROVAL verdict rather than ALLOW or DENY. Note that
decision.allowed is false for REQUIRE_APPROVAL -- the action must not
proceed while approval is outstanding.