Policy reference (vocabulary v1)
Every field a Scopebond policy can use, for writing or reviewing a policy for a gateway, MCP proxy, framework plugin or GitHub check. Coding-agent hook users change limits with commands instead (Write a policy).
The JSON Schema ships in @scopebond/policy-schema. validatePolicy in @scopebond/verify runs the same check every gateway uses.
Document
| Field | Required | Meaning |
|---|---|---|
vocabulary_version | yes | "1.0" |
policy_id | yes | Stable name |
version | yes | Positive integer, raised on every change |
clauses | yes | At least one clause |
assets | with money clauses | { "<ASSET>": { "decimals": n } }; amounts are whole numbers |
agent_id | no | The agent it is written for |
Unknown fields make a policy invalid, and an invalid replacement never takes effect.
Modes
| Mode | What happens |
|---|---|
enforce (default when a clause names no mode) | Blocks the action if the check fails |
require_approval | Holds it for a single-use approval of this exact action, or denies it at the timeout |
monitor | Lets it run and flags it. In a gateway policy, use it only for limits that cannot be checked in real time. The coding-agent hook writes every rule in this mode until you turn the rule on; its protection of Scopebond itself is always enforce |
Clause types
Every clause has id, type, mode and description. Durations use ISO-8601 (P1D, PT4H). Times are UTC.
| Type | Fields | Use it to |
|---|---|---|
action_allowlist | action_types[], optional param_bounds (enum, min, max, pattern; arrays { items, match: "all" | "any" }) | Allow named actions within bounds. The usual clause |
spend_limit | asset, max_per_action, max_per_window, window, scope (principal | global) | Cap amounts |
rate_limit | action_types[], max_count, window, scope | Cap frequency |
endpoint_allowlist / endpoint_denylist | hosts[], paths[] (glob), methods[] | Limit HTTP calls |
time_window | days[], start, end, timezone (UTC) | Limit when actions run |
require_approval | action_types[], approvers[] (key ids), min_approvals, timeout | Require sign-off |
sequence | first_action_types[], then_action_types[], min_gap or forbidden_within | Order pairs of actions |
address_allowlist / address_denylist, contract_allowlist | addresses[] / contracts[] (+ selectors[]), chain_ids[] | Limit on-chain destinations |
oracle_condition | oracle_id, predicate, best_effort: true | Depend on outside data |
key_policy | active_keys[], rotation_delay, max_key_age | Govern signing keys |
How rules are applied
- Anything outside every clause is denied. So is a value of the wrong type.
- A value exactly at a limit is allowed.
- A blocking result wins over approval and monitor results, whatever the clause order.
- Only actions that ran can break a policy.
- A
globallimit that cannot see every gateway's records is treated as deny.
Action types
| Action type | What it is | Produced by |
|---|---|---|
shell.exec | Each program in a command line (program) | Hook |
git.push | A push, per destination branch | Hook |
file.read, file.write | Reading or writing a file | Hook |
mcp.tool.call | An MCP tool call (server, tool) | Hook, MCP proxy |
net.fetch | A web fetch | Hook |
pr.merge | Merging a pull request (paths[]) | GitHub check |
payout.create | A payment (asset, amount) | Gateway, SDK, framework plugin |
The hook records a tool it does not recognize as not evaluated, never as allowed. With a gateway or framework plugin, you name the action type for each tool.