Policy rule syntax
OnePolicyRule row expresses one governance intent for one subject. Rules are
managed under /v1/policies; see the generated API reference for request and
response shapes.
Synopsis
PolicyDocument. The layers resolve in
the order workspace → agent → user → task into one immutable EffectivePolicy
carrying source_policy_ids and resolver_version (policy-resolver-v1).
Fields
PATCH replaces params wholesale rather than merging keys.
Values
Subject types
The task layer is not a rule. It is supplied as a
PolicyDocument in
task_policy at task creation.
Effects
Target selectors
target parses as kind or kind:value. * parses as kind all with no
value. A selector naming an unknown kind, or with an empty component, is rejected
at parse time.
Tool names are matched with
fnmatch glob semantics against the LLM-facing tool
name.
Params by effect
Approver references are
user:<id>, group:<id>, or a userset
<type>:<id>#<relation>. A bare id is rejected at write time. Only user:<id>
grants approval at resolution.
Merge and validation rules
Applied per layer in order. A lower layer may only tighten.
A rejected chain raises a validation error, surfaced as HTTP 422.
Enforcement
A rule that parses is not necessarily a rule that acts. The compiler skips unrecognised effect and target combinations at debug log level, so the row exists and the API returns it while the runtime never sees it.
Two further enforcement boundaries:
Defaults and overrides
New workspaces are seeded fromconfig/default_policies.yaml. Seeding is
idempotent per (target, effect, period) dimension: a dimension the workspace
already has is left untouched.
No approval rule is seeded.
Example
Deny one tool for one agent, and require approval on another with a named approver:See also
- Authorization model — the separate resource authorization surface.
- Limits — the numeric ceilings and their code defaults.
- Errors — the validation and permission responses these rules produce.
- The policy engine — how the layers merge.