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
| Property | Value |
|---|---|
| Capability | knowledge.write |
| Risk class | Write - autonomy L1 |
| Min. permission | Member |
| Availability | Admin only (CLI/HTTP; never advertised over MCP) |
| Idempotent | No |
| Egress | None - in-box (pure Postgres, no outbound call) |
| Budget-gated | Refused 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
| Property | Value |
|---|---|
| Capability | knowledge.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 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
| Property | Value |
|---|---|
| Capability | knowledge.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 |
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
| Property | Value |
|---|---|
| Capability | knowledge.write |
| Risk class | Write - autonomy L1 |
| Min. permission | Member |
| Availability | Admin only (CLI/HTTP; never advertised over MCP) |
| Idempotent | No |
| Egress | None - 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
| Property | Value |
|---|---|
| Capability | knowledge.write |
| Risk class | Sensitive - autonomy L2 |
| Min. permission | Admin |
| Availability | On demand (MCP tier 2) |
| Idempotent | Yes |
| Egress | None - 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
| Property | Value |
|---|---|
| Capability | knowledge.admin |
| Risk class | Sensitive - autonomy L2 |
| Min. permission | Admin |
| Availability | Admin only (CLI/HTTP; never advertised over MCP) |
| Idempotent | No |
| Egress | None - 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
| Property | Value |
|---|---|
| Capability | knowledge.admin |
| Risk class | Sensitive - autonomy L2 |
| Min. permission | Admin |
| Availability | Admin only (CLI/HTTP; never advertised over MCP) |
| Idempotent | No |
| Egress | None - 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
| Property | Value |
|---|---|
| Capability | knowledge.write |
| Risk class | Sensitive - autonomy L2 |
| Min. permission | Admin |
| Availability | Admin only (CLI/HTTP; never advertised over MCP) |
| Idempotent | No |
| Egress | None - 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.