opbox

The knowledge.* family (8 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.

Distilknowledge.distil

PropertyValue
Capabilityknowledge.write
Risk classWrite - autonomy L1
Min. permissionMember
AvailabilityAdmin only (CLI/HTTP; never advertised over MCP)
IdempotentNo
EgressNone - in-box (pure Postgres, no outbound call)
Budget-gatedRefused when the workspace AI budget is exceeded (Owner break-glass audited)

INV-EPI (the heart): the assertion is born DISTILLED ⇒ the evidenceQuote MUST be an EXACT SUBSTRING of the referenced capture’s body. This verb LOADS the capture and checks body.contains(quote) - the cross-row predicate ck_knowledge_evidence (the column floor) CANNOT express. A quote that is not a real substring is HARD-REJECTED (BadInput), never written. (A specialist who wants a working note without evidence uses a different surface - a DRAFT - not this verb; knowledge.distil is the evidence gate by definition.)

Input { subject, assertion, captureId, evidenceQuote, confidence?, jurisdiction? } (fields ending in ? are optional)

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

Getknowledge.get

PropertyValue
Capabilityknowledge.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

Returns the assertion, its evidence quote, the source capture id + body, and the supersession pointer. Workspace-scoped (a cross-ws assertion is unreachable, RLS).

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

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

Listknowledge.list

PropertyValue
Capabilityknowledge.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

The curation inventory. Lexical FIND-by-text is search.query{scope:knowledge} (the FTS view); this is the typed-filter list.

Input { status?, jurisdiction?, limit?, offset? } (fields ending in ? are optional)

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

Proposeknowledge.propose

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

Creates a DISTILLED knowledge row (same shape as distil) but marks it as proposed for review. The review itself goes through the existing review.* primitives.

Input { captureId, subject, assertion, evidenceQuote, jurisdiction?, confidence? } (fields ending in ? are optional)

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

Publishknowledge.publish

PropertyValue
Capabilityknowledge.write
Risk classSensitive - autonomy L2
Min. permissionAdmin
AvailabilityOn demand (MCP tier 2)
IdempotentYes
EgressNone - in-box (pure Postgres, no outbound call)

Promotes a DISTILLED assertion to PUBLISHED. The transition is guarded WHERE status='DISTILLED' (atomic, idempotent-safe - a re-publish of an already-PUBLISHED row is reported, never a silent re-write; a DRAFT/SUPERSEDED row is a Conflict). Evidence stays required: the ck_knowledge_evidence column floor holds across the transition (PUBLISHED is an evidence-gated status), so a row could only reach here WITH a quote+capture - INV-EPI is preserved by construction.

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

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

Retireknowledge.retire

PropertyValue
Capabilityknowledge.admin
Risk classSensitive - autonomy L2
Min. permissionAdmin
AvailabilityAdmin only (CLI/HTTP; never advertised over MCP)
IdempotentNo
EgressNone - in-box (pure Postgres, no outbound call)

Sets status to RETIRED. Unlike SUPERSEDED, retirement is terminal and does not point to a successor. Only PUBLISHED assertions can be retired.

Input { knowledgeId, reason? } (fields ending in ? are optional)

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

Reviewknowledge.review

PropertyValue
Capabilityknowledge.admin
Risk classSensitive - autonomy L2
Min. permissionAdmin
AvailabilityAdmin only (CLI/HTTP; never advertised over MCP)
IdempotentNo
EgressNone - in-box (pure Postgres, no outbound call)

APPROVE promotes DISTILLED -> PUBLISHED. REJECT leaves it as DISTILLED (no state change, just the audit trail of the rejection). The review decision is recorded as an audit event.

Input { knowledgeId, decision: "APPROVE"|"REJECT", reason? } (fields ending in ? are optional)

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

Supersedeknowledge.supersede

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

Marks knowledgeId SUPERSEDED and points it at supersededById (the newer assertion). FORWARD-ONLY (INV-EPI / INV-8 supersede-not-delete): • the successor must EXIST (same workspace), and differ from the target (the no-self-supersede CHECK); • the successor must not ALREADY be (transitively) superseded BY a chain that leads back to the target - i.e. following supersededById’s forward superseded_by pointers must never reach knowledgeId (that would close a cycle). The verb WALKS the chain and REJECTS a cycle. (The single-row floor is the DB CHECK; the multi-row acyclicity is this walk - the step-DAG precedent.) The superseded row is RETAINED, never deleted (INV-8).

Input { knowledgeId, supersededById } (fields ending in ? are optional)

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