policy.updated
The autonomy level or the rules changed. Takes effect on the next action, not retroactively.
Direction: Chips → Harness
Sent by: a person
Requires a run: no
Schema: policy.updated.json
Fields
Section titled “Fields”Every event also carries the envelope.
| Field | Required | Type | Description |
|---|---|---|---|
v |
yes | 1 |
Protocol major version. |
type |
yes | "policy.updated" |
|
id |
yes | string |
The event’s own id. Stable across a retry of the same event. |
ts |
yes | string |
When it happened, by Chips’ clock. Stamped on the way in; a value the sender writes is replaced. |
workspace_id |
yes | string |
A workspace identifier: ws_ followed by a ULID. |
space_id |
no | string |
The space, when the event belongs to one. |
run_id |
no | string |
The run, when the event belongs to one. |
seq |
no | number |
Assigned by the server on append, monotonic per workspace. Absent on the way in. |
idempotency_key |
no | string |
Required on every client-originated write. Sending the same key twice is a no-op. |
actor |
yes | object | The participant an event is attributed to. |
actor.kind |
yes | "person" | "harness" | "agent" | "system" |
Whether a person, a harness, one of a harness’s agents or Chips itself acted. |
actor.id |
yes | string |
The participant id, or system for Chips. |
actor.harness_id |
no | string |
For an agent: the harness it speaks through, whose budget and runs are the agent’s (ADR 0087). Filled in by Chips. |
harness_id |
yes | string |
A harness identifier: hrn_ followed by a ULID. |
policy |
yes | object | A harness’s autonomy level and the rules that fill in the details. |
policy.autonomy |
yes | 0 | 1 | 2 | 3 |
0 observe, 1 ask first, 2 ask when it matters, 3 autonomous and report back. Presets that expand to rules. |
policy.rules |
yes | object[] | Evaluated in order; the workspace cap always wins. |
policy.rules[].match |
yes | string |
A glob over action kinds, for example payment.*. |
policy.rules[].when |
no | object | Extra conditions on the action’s flags, and for a command, how its parts start. |
policy.rules[].when.external |
no | boolean |
|
policy.rules[].when.irreversible |
no | boolean |
|
policy.rules[].when.money_usd_over |
no | number |
|
policy.rules[].when.risk |
no | enum[] | One of external, external_communication, irreversible, destructive, financial, credential, privacy, legal. |
policy.rules[].when.starts_with |
no | string[] |
For an action that carries a command (ADR 0239): the words a part of it starts with. A command goes ahead on such rules only when every part starts with one that allows it. |
policy.rules[].decision |
yes | "allow" | "ask" | "deny" |
What to do when the rule matches. |
policy.rules[].approvers |
no | string[] |
Who may answer, when the decision is ask. |
policy.rules[].reason |
no | string |
Shown to the harness, and recorded in the audit log. |
policy.rules[].off |
no | boolean |
Turned off by a person (ADR 0195): kept in the list to turn back on, and skipped by the policy engine until then. |
policy.rules[].made_by |
no | string |
Who made it by answering an ask with Always (ADR 0195). Filled in by Chips. |
policy.rules[].made_at |
no | string |
When a person’s answer made it (ADR 0195): Always, or This session. Filled in by Chips. A rule a person’s answer made never allows an action that matters. |
workspace_max_autonomy |
yes | 0 | 1 | 2 | 3 |
The workspace cap. It always wins. |
budget_usd |
no | number |
The harness’s spending ceiling, in US dollars. Absent leaves it as it was; the harness’s spend is what usage has added up. |
changed_by |
yes | string |
Who changed it, or system for an earned promotion. Filled in by Chips from the credential that sent it. |
reason |
no | string |
Why it changed. |
Example
Section titled “Example”{ "v": 1, "type": "policy.updated", "id": "evt_01K4ZQPX00000000000000007C", "ts": "2026-09-02T14:22:24.004Z", "workspace_id": "ws_01K4ZQPX000000000000000001", "space_id": "spc_01K4ZQPX000000000000000002", "actor": { "kind": "system", "id": "system" }, "harness_id": "hrn_01K4ZQPX000000000000000004", "policy": { "autonomy": 2, "rules": [ { "match": "email.send", "when": { "external": true }, "decision": "ask", "approvers": ["owner"] } ] }, "workspace_max_autonomy": 2, "budget_usd": 25, "changed_by": "system", "reason": "Six approvals in a row with no edits."}