Skip to main content
Policies are functions. They take a PolicyContext and return a Decision.

Policy Function Shape

Every policy is a plain Python function:
No inheritance, no framework, no configuration file. Just a function that receives context and returns a decision.

Registering Policies

Use @runtime.before_capability or @runtime.after_capability to register:
The decorator registers the function as a Policy targeting "execute_sql" at the before_capability stage. The original function is returned unchanged, so you can call it directly in tests.

Policy Targets

Exact match:
Wildcard:
Wildcard policies run alongside exact-match policies. Both are evaluated; deny wins.

Policy Metadata

Provide a name and version to make decisions traceable:
The name and version are annotated onto the Decision and appear in CapabilityDeniedError.policy_name.

Policy Metadata Fields

  • name: human-readable identifier. Defaults to the function name.
  • version: policy version string.
  • description: what this policy enforces.
  • priority: higher priority runs first. Default is 0.
  • enabled: set False to disable without removing. Default is True.
  • source: where this policy came from.

Multiple Policies On The Same Capability

Multiple policies can target the same capability. They all run. Deny wins: if any policy returns deny, the action is denied regardless of other policies returning allow.

Testing Policies

Because policies are plain functions, you can test them by constructing a PolicyContext directly:

Where Policy Lives

Policy should be a separate control layer: not scattered across tool implementations, not hidden in prompts, not inside ad hoc if-statements in the agent logic. Start with a single policy file per agent. Once policies are explicit, they can be tested, audited, reused, and eventually moved to a central policy system or cloud bundle.
Write explicit deny rules for high-risk capabilities rather than relying on allow-by-default.