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.
Provide a name and version to make decisions traceable:
The name and version are annotated onto the Decision and appear in CapabilityDeniedError.policy_name.
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.