The inbox.* 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.
Getinbox.get
| Property | Value |
|---|---|
| Capability | inbox.read |
| Risk class | Read - autonomy L0 |
| Min. permission | Member |
| Availability | Core - always on (MCP tier 1) |
| Idempotent | No |
| Egress | None - in-box (pure Postgres, no outbound call) |
| Render schema | Yes - drives an inline chat artefact and a GUI panel |
Returns ONE notification - but ONLY if it belongs to the caller (recipient_id = ctx.actor.id): another actor’s notification reads back as “not found” (the IDOR fence returns the same not-found verdict as a truly-missing id, never leaking existence).
Input { notificationId } (fields ending in ? are optional)
Call POST /v/inbox.get with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool inbox.get.
Listinbox.list
| Property | Value |
|---|---|
| Capability | inbox.read |
| Risk class | Read - autonomy L0 |
| Min. permission | Member |
| Availability | Core - always on (MCP tier 1) |
| Idempotent | No |
| Egress | None - in-box (pure Postgres, no outbound call) |
| Render schema | Yes - drives an inline chat artefact and a GUI panel |
Returns ONLY the caller’s own notifications (recipient_id =
ctx.actor.id - the IDOR fence): an actor NEVER sees another actor’s inbox. Optional status/kind
filters. Ordered newest-first; the per-section unread-dot is a thin COUNT over this same store.
Input { status?, kind? } (fields ending in ? are optional)
Call POST /v/inbox.list with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool inbox.list.
Markinbox.mark
| Property | Value |
|---|---|
| Capability | inbox.write |
| Risk class | Write - autonomy L1 |
| Min. permission | Member |
| Availability | Core - always on (MCP tier 1) |
| Idempotent | Yes |
| Egress | None - in-box (pure Postgres, no outbound call) |
where status ∈ {READ, ARCHIVED}. WRITE/L1/MEMBER. Flips the caller’s own notification UNREAD → READ (sets read_at, ck_notification_read_iff_read holds) | ARCHIVED (clears read_at - a dismissed signal is not “read”). Recipient-scoped: a mark on ANOTHER actor’s notification matches 0 rows and reads back as not-found (the IDOR fence - you cannot mark what is not yours). Idempotent: re-marking to the same terminal status is a no-op success.
Input { notificationId, status } (fields ending in ? are optional)
Call POST /v/inbox.mark with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool inbox.mark.