Developer documentation

Policies

Last reviewed 31 August 2026

QuickstartCLI referencePython SDKTypeScript SDKMCPIntegrationsPoliciesActionProofEvidenceCAIN TraceConformanceTroubleshootingDeveloper portalMarketplaceFree tierBenchmarksArchitectureCAIN IdentityCAIN ControlCAIN BudgetCAIN GovernanceCAIN MemorySelf-Hosted MCPGateCAIN PrivateCAIN TrajectoryCAIN Agent SecurityCAIN Drift7-Moat ArchitectureChangelog

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.