opbox

The watch.* family (3 verbs). Every verb enters through the one front door: it is capability-checked, permission-checked, scope-checked and audited before it runs (see Security & permissions). Each entry below lists its capability, risk class (which fixes the minimum autonomy level), the minimum caller permission, its availability tier, whether it is idempotent, and any outbound egress.

Addwatch.add

PropertyValue
Capabilitywatch.write
Risk classWrite - autonomy L1
Min. permissionMember
AvailabilityOn demand (MCP tier 2)
IdempotentYes
EgressNone - in-box (pure Postgres, no outbound call)

Subscribes the CALLER to the object’s change signals. Watching grants ZERO access (the read is still gated by acl/visibility - ADR-0042 decision 6). The object need only exist in the workspace (a watcher may follow a workspace-visible object they can already see; a restricted object they cannot see is simply never fanned to them in practice, and the watch row alone never opens it). Upserts (re-watching is idempotent; auto may flip false→true).

Input { objectType, objectId, auto? } (fields ending in ? are optional)

Call POST /v/watch.add with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool watch.add.

Listwatch.list

PropertyValue
Capabilitywatch.read
Risk classRead - autonomy L0
Min. permissionMember
AvailabilityOn demand (MCP tier 2)
IdempotentNo
EgressNone - in-box (pure Postgres, no outbound call)
Render schemaYes - drives an inline chat artefact and a GUI panel

The caller’s own watches (optionally filtered by object_type). An actor sees ONLY its own watch list (the recipient-scoping IDOR fence - actor_id = ctx.actor.id, the same posture as inbox.list).

Input { objectType? } (fields ending in ? are optional)

Call POST /v/watch.list with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool watch.list.

Removewatch.remove

PropertyValue
Capabilitywatch.write
Risk classWrite - autonomy L1
Min. permissionMember
AvailabilityOn demand (MCP tier 2)
IdempotentYes
EgressNone - in-box (pure Postgres, no outbound call)

Unsubscribes the CALLER. Idempotent: removing a non-watch is a no-op success. Recipient-scoped: a caller can only remove its OWN watch (the WHERE keys actor_id).

Input { objectType, objectId } (fields ending in ? are optional)

Call POST /v/watch.remove with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool watch.remove.