opbox

The board.* family (16 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.

Archiveboard.archive

PropertyValue
Capabilityboard.author
Risk classDestructive - autonomy L3
Min. permissionAdmin
AvailabilityOn demand (MCP tier 2)
IdempotentYes
EgressNone - in-box (pure Postgres, no outbound call)

Withdraw a board from NEW instantiation: DRAFT|ACTIVE → ARCHIVED. { id }. An ARCHIVED board can no longer instantiate new matters (matter.create already refuses a non-ACTIVE board); EXISTING matters are unaffected (they pinned instantiatedFromVersion, R11 - the published Version snapshot is immutable, INV-8). History + in-flight instances are retained-not-deleted (INV-8); reversible only via authoring a new version. Mirrors party.archive/ portal.archive/doc.archive (status-not-timestamp, INV-3; never a hard DELETE).

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

Createboard.create

PropertyValue
Capabilityboard.author
Risk classDestructive - autonomy L3
Min. permissionAdmin
AvailabilityCore - always on (MCP tier 1)
IdempotentNo
EgressNone - in-box (pure Postgres, no outbound call)

author a new DRAFT Board/Template. { key, title, description?, phases? }.

Input

FieldTypeRequiredDescription
keystringyes
titlestringyes
phasesobjectyes{version, phases:[{id,name,traversalMode,onComplete,steps:[…]}]}

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

Editboard.edit

PropertyValue
Capabilityboard.author
Risk classDestructive - autonomy L3
Min. permissionAdmin
AvailabilityCore - always on (MCP tier 1)
IdempotentNo
EgressNone - in-box (pure Postgres, no outbound call)

re-draft a DRAFT board’s body. { id, title?, description?, phases? }. Only DRAFT boards are editable (a published version is immutable, R11).

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

Getboard.get

PropertyValue
Capabilityboard.read
Risk classRead - autonomy L0
Min. permissionMember
AvailabilityCore - always on (MCP tier 1)
IdempotentNo
EgressNone - in-box (pure Postgres, no outbound call)
Render schemaYes - drives an inline chat artefact and a GUI panel

one board definition. { id }.

Input

FieldTypeRequiredDescription
idstringyes

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

Listboard.issue.list

PropertyValue
Capabilityboard.issue.read
Risk classRead - autonomy L0
Min. permissionAdmin
AvailabilityAdmin only (CLI/HTTP; never advertised over MCP)
IdempotentNo
EgressNone - in-box (pure Postgres, no outbound call)
Render schemaYes - drives an inline chat artefact and a GUI panel

list projected issues for a matter (or the whole tenant). { matterId? }. READ/L0. The issues are a VIEW of PG MatterStep state; never read as the SoR.

Call POST /v/board.issue.list with a JSON body; returns JSON (or { error, code }). Not advertised over MCP (admin-only); reachable via the CLI and HTTP doors.

Reassignboard.issue.reassign

PropertyValue
Capabilityboard.issue.write
Risk classWrite - autonomy L1
Min. permissionAdmin
AvailabilityAdmin only (CLI/HTTP; never advertised over MCP)
IdempotentNo
EgressNone - in-box (pure Postgres, no outbound call)

reassign a board_issue’s projected ASSIGNEE (ownership-only). WRITE/L1/ADMIN. { issueId, toAssignee }. Mirrors review.reassign: a guarded UPDATE ... WHERE id=$ AND workspace_id=$ move of the projected owner - rows_affected==0 ⇒ the issue does not exist in THIS workspace (fail-closed not-found; the RLS/IDOR fence). Ownership/attribution ONLY: the board is a VIEW (INV-6), so this NEVER writes matter/step state - it moves WHO owns the projected ticket, never the work itself (the work moves only via matter.advance, INV-1). toAssignee is the kernel principal (an org-node/actor id board.principal.resolve maps to an external board user).

Call POST /v/board.issue.reassign with a JSON body; returns JSON (or { error, code }). Not advertised over MCP (admin-only); reachable via the CLI and HTTP doors.

Syncboard.issue.sync

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

project/refresh a matter’s issues from its current MatterStep state. { matterId }. Idempotent: re-syncing upserts the same issue set (INV-2 re-sync safe). PG is the SoR; this is a kernel->board projection (one direction), never a board->matter write (ADR-0002).

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

Handleboard.issue.webhook.handle

PropertyValue
Capabilityboard.issue.write
Risk classWrite - autonomy L1
Min. permissionExternal (portal / signer token)
AvailabilityAdmin only (CLI/HTTP; never advertised over MCP)
IdempotentYes
EgressNone - in-box (pure Postgres, no outbound call)

the ONE idempotent inbound seam (WRITE/L1/EXTERNAL, idempotent). { issueId | externalRef, transition, deliveryKey, signature, note? }.

An HMAC-verified board webhook. A terminal ticket transition (e.g. “done”) routes to matter.advance(matter_id, step_id) - the ONE write path (INV-1). The handler NEVER writes matter/step status directly: it resolves the linkage, then re-enters matter.advance. • HMAC over the raw signed body (NFR-SEC-5); a bad/missing signature is a fail-closed deny. • Idempotent on deliveryKey (TASK-BOARDS-05): a redelivery is a no-op, never a double-advance. • Unknown linkage / unknown transition is rejected/ignored safely (fail-closed).

Call POST /v/board.issue.webhook.handle with a JSON body; returns JSON (or { error, code }). Not advertised over MCP (admin-only); reachable via the CLI and HTTP doors.

Listboard.list

PropertyValue
Capabilityboard.read
Risk classRead - autonomy L0
Min. permissionMember
AvailabilityCore - always on (MCP tier 1)
IdempotentNo
EgressNone - in-box (pure Postgres, no outbound call)
Render schemaYes - drives an inline chat artefact and a GUI panel

list boards in the workspace (optionally filter by status). { status? }.

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

Resolveboard.principal.resolve

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

map a KERNEL principal (org-node/actor) <-> an EXTERNAL board user. WRITE/L1/ADMIN. { principalId, externalUserId, externalSystem? }. ONE idempotent linkage upsert (one row per (workspace, principal, externalSystem)): re-resolving the SAME pair re-points the EXISTING row (a moved external account), never a duplicate. The linkage is the cross-system id map the projection reads to render board_issue.assignee against the external board - it carries ONLY the id pairing, NEVER a copy of the actor’s role/grant (steering #1: the org/actor stays the SoR).

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

Publishboard.publish

PropertyValue
Capabilityboard.author
Risk classDestructive - autonomy L3
Min. permissionAdmin
AvailabilityCore - always on (MCP tier 1)
IdempotentNo
EgressNone - in-box (pure Postgres, no outbound call)

validate the DRAFT body, forward-mint an immutable Version, DRAFT→ACTIVE, point current_version at the minted version. { id, changelog? }. R11: snapshot-not-live.

Input

FieldTypeRequiredDescription
idstringyes
changelogstringno

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

Regenerateboard.regenerate

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

tenant-wide reconcile: re-project EVERY matter’s steps -> board_issue. WRITE/L1/ ADMIN, IDEMPOTENT. The bulk twin of board.issue.sync: it walks every matter in THIS workspace and upserts the same per-step linkage (the issue_sync upsert, applied workspace-wide), so a re-run mints no duplicates (the uq_board_issue_matter_step arbiter + last_projected_version bump). PG is the SoR (ADR-0002): this is a one-direction kernel->board refresh, never a board->matter write. Matters whose board has been HALTED (board.stop-projecting; board.projecting=false) are SKIPPED - no new view rows are minted for a stopped board (existing rows retained, INV-8).

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

Setboard.step.condition.set

PropertyValue
Capabilityboard.author
Risk classDestructive - autonomy L3
Min. permissionAdmin
AvailabilityCore - always on (MCP tier 1)
IdempotentNo
EgressNone - in-box (pure Postgres, no outbound call)

Set step conditional-visibility on a DRAFT board. Rule-builder write path (US-RENDER-28). Accepts TWO exclusive forms:

  1. boolean (M1): {conditionalVisibility:{visible:bool, onFail?:skip|block}}
  2. fact-guard (TASK-MATTER-10): {conditionalVisibility:{requiresFact:{factKey, targetType?, onFail?}}} DRAFT-board-only. Step must exist (BadInput if missing). The whole conditionalVisibility object is stored verbatim (the engine’s visibility() reads it); exactly one form must be present.

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

Stop projectingboard.stop-projecting

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

reversibly HALT a board’s matter->board_issue projection. WRITE/L1/ADMIN. { boardId }. Sets board.projecting=false: while OFF, board.regenerate / board.issue.sync mint NO new view rows for that board’s matters. REVERSIBLE (a resume flips it back to true) and NON-DESTRUCTIVE: existing board_issue rows are RETAINED, never hard-deleted (INV-8: regenerable view). Guarded UPDATE ... WHERE id=$ AND workspace_id=$ (the RLS/IDOR fence); a re-stop of an already-halted board is an idempotent no-op success.

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

Statusboard.sync.status

PropertyValue
Capabilityboard.issue.read
Risk classRead - autonomy L0
Min. permissionAdmin
AvailabilityAdmin only (CLI/HTTP; never advertised over MCP)
IdempotentNo
EgressNone - in-box (pure Postgres, no outbound call)
Render schemaYes - drives an inline chat artefact and a GUI panel

sync-health for a matter/tenant. { matterId? }. READ/L0. Reports last-projected-version + stale/orphan/missing counts (the boards twin of connection.status). • stale = a projected issue whose projected_state != the live PG step status (a refresh is due) • orphan = a projected issue whose linked matter_step no longer exists (PG won; the issue lags) • missing = a live PG step with NO projected issue yet (the projection is behind)

Call POST /v/board.sync.status with a JSON body; returns JSON (or { error, code }). Not advertised over MCP (admin-only); reachable via the CLI and HTTP doors.

Validateboard.validate

PropertyValue
Capabilityboard.read
Risk classRead - autonomy L0
Min. permissionMember
AvailabilityAdmin only (CLI/HTTP; never advertised over MCP)
IdempotentNo
EgressNone - in-box (pure Postgres, no outbound call)
Render schemaYes - drives an inline chat artefact and a GUI panel

save-time validatePhases + step-type-exists + cycle check. { id } or { phases }. Returns { valid, errors[], normalized }. Never mutates (READ).

Call POST /v/board.validate with a JSON body; returns JSON (or { error, code }). Not advertised over MCP (admin-only); reachable via the CLI and HTTP doors.