opbox

The doc.* family (62 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.

Annotatedoc.annotate

PropertyValue
Capabilitydoc.annotate
Risk classWrite - autonomy L1
Min. permissionMember
AvailabilityCore - always on (MCP tier 1)
IdempotentNo
EgressNone - in-box (pure Postgres, no outbound call)

type ∈ {BOUNDING_BOX, ARROW, COMMENT}; coords normalized 0..1 (INV-6 - pixel positions computed at render, never stored). An out-of-0..1 coord / page<1 / unknown type is a fail-closed BadInput (INV-11) BEFORE any write. The File must exist in THIS workspace (RLS + FK).

Input { fileId, type, pageNumber, x,y,w,h, endX?,endY?, color?, label?, criterion?, comment? } (fields ending in ? are optional)

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

Getdoc.annotation.get

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

Returns every annotation on the File (RLS-scoped), in page+creation order.

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

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

Removedoc.annotation.remove

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

Removes the annotation (RLS-scoped). Not found → BadInput (fail-closed).

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

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

Archivedoc.archive

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

A destructive operation in the doc.* family. Called through the one governed front door: capability, permission tier, autonomy, scope and egress are all resolved before the handler runs, and the call is audited (INV-1, INV-8).

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

Createdoc.comment.create

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

user_id from acting user, workspace_id from ctx. Validates parentId resolves in the same workspace. createdAt may be backdated (docx import); else DB now().

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

Deletedoc.comment.delete

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

RLS fence; idempotent (reactions+replies are FK-cascade).

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

Updatedoc.comment.update

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

content edit and/or resolve toggle. RLS fence id+workspace_id. On resolve transition, sets resolved_by_id (acting user) + resolved_at; on un-resolve clears them.

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

Createdoc.create

PropertyValue
Capabilitydoc.write
Risk classWrite - autonomy L1
Min. permissionMember
AvailabilityCore - always on (MCP tier 1)
IdempotentNo
EgressNone - in-box (pure Postgres, no outbound call)

The DocEngine PARSES the body into (content, structural_map) - the kernel never parses OOXML.

Input

FieldTypeRequiredDescription
titlestringyes
kindstringyese.g. NATIVE
matterIdstringno
contentobjectnothe native doc model, e.g. {paragraphs:[{runs:[{text:”…”}]}]}

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

Createdoc.docversion.create

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

on (document_id,version). Fence the documents table in workspace. NOTE: distinct from doc.version.snapshot (which backs the KERNEL document_version singular).

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

Editdoc.edit

PropertyValue
Capabilitydoc.write
Risk classWrite - autonomy L1
Min. permissionMember
AvailabilityCore - always on (MCP tier 1)
IdempotentNo
EgressDoc engine - the co-located document service (policy-gated rail)
High-risk oversightHuman four-eyes approval in HIGH-risk orgs (EU AI Act Art. 14)

{ id, patches:[{op,…}], trackChanges? }. WRITE/L1.

The edit goes through the DocEngine apply_patches port: it mutates the addressed paragraphs/runs SURGICALLY and PRESERVES the structural_map (the verbatim ~35%-unmodeled blob is byte-identical out as in). It NEVER rebuilds the whole document from the content/StructuralMap (the foreclosed anti-pattern). When track-mode is on, each run-delta becomes a TrackedChange record (rt-006).

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

Extractdoc.extract

PropertyValue
Capabilitydoc.extract
Risk classSensitive - autonomy L2
Min. permissionMember
AvailabilityAdmin only (CLI/HTTP; never advertised over MCP)
IdempotentNo
EgressDoc engine - the co-located document service (policy-gated rail)
High-risk oversightHuman four-eyes approval in HIGH-risk orgs (EU AI Act Art. 14)

{ fileId?, docKind?, mapping, target:{type,id}, fields:{key:{value,confidence,pii?}}, confidenceThreshold? }. SENSITIVE/L2. Reads typed Facts out of a binary doc under an INV-9 quality gate: • a REQUIRED field below the threshold is NOT written - recorded LOW + routed to Review (a stub id). • an OPTIONAL low-confidence field is recorded (visible), not silently dropped. • a high-confidence field is written through the CANONICAL Fact path (INV-1) - encrypt-before-write for any PII field with an explicit encryption_scheme (INV-7 - no plaintext PII column). The coverage/quality report is written to the extraction snapshot on BOTH success and failure (INV-9).

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

Adddoc.favourite.add

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

on (document_id,user_id).

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

Removedoc.favourite.remove

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

Delete own favourite by (document_id,user_id).

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

Listdoc.gen.list

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

Lists the audited generated_document snapshots (the two-phase authoring spine, INV-9/INV-8) scoped to a matterId (the matter’s generation history) or a templateId (every generation off one doc-pack) or the whole workspace. RLS-scoped + an explicit workspace_id = $ predicate (a cross-workspace snapshot is unreachable). Returns metadata only (id/status/mode/template-version cursor/timestamps) - NOT the payload/coverage blobs (those are the gated single-read generated.get). BLOCKED/FAILED snapshots are LISTED too (the audit row exists on success AND failure, INV-9 - never silently dropped). Paginated (NFR-PERF-3). Computes nothing authoritative (INV-14).

Input { matterId?, templateId?, status?, mode?, limit? } (fields ending in ? are optional)

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

Generatedoc.generate

PropertyValue
Capabilitydoc.gen
Risk classSensitive - autonomy L2
Min. permissionMember
AvailabilityCore - always on (MCP tier 1)
IdempotentNo
EgressDoc engine - the co-located document service (policy-gated rail)
High-risk oversightHuman four-eyes approval in HIGH-risk orgs (EU AI Act Art. 14)
Budget-gatedRefused when the workspace AI budget is exceeded (Owner break-glass audited)

Two-phase (INV-9/INV-8): a generation snapshot is written on BOTH success AND failure.

  1. PIN the template’s CURRENT version at generation time (R11 - re-publishing later won’t drift it).
  2. Run the coverage gate through the DocEngine port: an unmapped REQUIRED var → BLOCK (refuse, structured error) before any document is produced; an optional missing var → a visible [MISSING
    ] marker. A coverage report is written on both paths.
  3. The generate↔edit fidelity guard (INV-5 boundary): the generation RE-PARSES its own output; a non-round-tripping generation is FAILED (not silently accepted).
  4. On success, the produced content lands as a first-class Document and the snapshot commits.

Input { templateId, mode?, payload, matterId?, modelUsed?, agentSessionId? } (fields ending in ? are optional)

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

Createdoc.generated.create

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

Persist the generated-document metadata row (rendering + persistFilesToKB stay in FE). created_by_id is the acting user (nullable column).

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

Adddoc.generated.file.add

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

One produced file row; fence parent in workspace.

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

Snapshotdoc.generated.snapshot

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

Post-generation audit write onto an existing row (partial).

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

Getdoc.get

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

An ARCHIVED document is STILL readable (retain-not-delete, INV-8).

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

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

Adddoc.label.add

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

ON CONFLICT(document_id,label) DO NOTHING + re-read.

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

Removedoc.label.remove

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

Targeted single-label delete (document_id+label).

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

Listdoc.list

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

Lists Documents scoped to a matterId (the matter’s doc set) or parentId (a folder subtree) or the whole workspace. Returns metadata only (title/kind/status/cursor/sensitivity) - NOT the content blob (the binary stays SoR; doc.get is the sensitivity-gated single-read). RLS-scoped + an explicit workspace_id = $ predicate (a cross-workspace doc is unreachable). Paginated (NFR-PERF-3). Computes nothing authoritative (INV-14). ARCHIVED docs are still LISTED (retain-not-delete, INV-8).

Input { matterId?, parentId?, kind?, status?, limit? } (fields ending in ? are optional)

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

Createdoc.pack.create

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

workspace_id from ctx, created_by_id acting user.

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

Deletedoc.pack.delete

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

RLS fence; idempotent (child template_pack_documents are FK-cascade).

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

Adddoc.pack.document.add

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

on (pack_id,document_row_id). Fence pack in workspace.

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

Removedoc.pack.document.remove

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

Confirm pack in workspace; delete by composite key.

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

Updatedoc.pack.document.update

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

Variable-extraction cache write; fence via parent pack workspace.

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

Generatedoc.pack.generate

PropertyValue
Capabilitydoc.pack.gen
Risk classSensitive - autonomy L2
Min. permissionMember
AvailabilityCore - always on (MCP tier 1)
IdempotentNo
EgressDoc engine - the co-located document service (policy-gated rail)
High-risk oversightHuman four-eyes approval in HIGH-risk orgs (EU AI Act Art. 14)

[2026] VJS-CC-OPBOX 84: doc.pack.generate (SENSITIVE/Member) - orchestrate per-template doc.generate for a kernel-modeled doc PACK. Loads the package + its package_rule rows (Design B1), runs the rules interpreter (mode=once | mode=forEach over iterateOver, the loop item bound under as_alias), calls doc.generate per template, and accumulates PER-TEMPLATE PARTIAL-SUCCESS results (Design B2): one template BLOCKED/FAILED does NOT abort the pack - doc.generate writes each template’s own generation_snapshot (on success AND failure, INV-8) BEFORE returning its app-level error, so we catch the per-template failure (Conflict/BadInput, tx-safe)

  • record it + continue; a genuine DB/internal error aborts the pack. The caller re-runs just the failed template (VJS-ACT 10 correction floor). Inherits doc.generate’s INV-9 coverage gate + INV-5 fidelity guard; the pack writes NO snapshot itself (doc.generate is the sole writer - DEC-15 one-writer, CC-OPBOX 80).

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

Updatedoc.pack.update

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

Partial conditional set; RLS fence packId+workspace_id.

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

Declaredoc.presence.declare

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

Only (KYC linking + grant lifecycle; no user session). ctx.workspace_id = custodian workspace. Supersede-then-insert when fileId differs; else refresh; else insert. BEARERLESS.

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

Expiredoc.presence.expire

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

Only (reconciliation + grant lifecycle). Mark matching rows EXPIRED in the custodian (ctx) workspace; optionally stamp pruned_at. BEARERLESS.

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

Prunedoc.presence.prune

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

Only. Hard-delete soft-deleted rows past pruned_at cutoff in the custodian (ctx) workspace. BEARERLESS.

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

Cascadedoc.purge.cascade

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

Only. Single-tx deleteMany across the 7 document child tables for one documentId (workspace-fenced where the column exists). Does NOT touch table_row / pdf_signing_field_placement / stored_file (other domains keep those as separate dispatches). Returns counts.

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

Adddoc.reaction.add

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

on (comment_id,user_id,emoji). Fence comment in workspace.

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

Removedoc.reaction.remove

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

Delete own reaction by (comment_id,user_id,emoji).

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

Renderdoc.render

PropertyValue
Capabilitydoc.write
Risk classWrite - autonomy L1
Min. permissionMember
AvailabilityCore - always on (MCP tier 1)
IdempotentNo
EgressDoc engine - the co-located document service (policy-gated rail)
High-risk oversightHuman four-eyes approval in HIGH-risk orgs (EU AI Act Art. 14)

The render goes through the DocEngine port. A render FAILURE lands a FAILED row + a warning and the verb still returns OK (the canonical Document is UNTOUCHED, INV-2 - PDF is a derivative, never authoritative). Nothing on the write path gates on render success.

Input { id, format? } (fields ending in ? are optional)

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

Sharedoc.share

PropertyValue
Capabilityacl.write
Risk classWrite - autonomy L1
Min. permissionMember
AvailabilityCore - always on (MCP tier 1)
IdempotentNo
EgressNone - in-box (pure Postgres, no outbound call)

The doc twin of matter.share - forwards to acl.grant with object_type=‘document’ (INV-1, one write path).

Input { documentId, granteeType, granteeId, level } (fields ending in ? are optional)

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

Adddoc.signer.add

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

Fence parent generated_documents in workspace; refuse if parent status is terminal (SENT|COMPLETED|VOIDED). lowercase email. signer_index defaults to order.

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

Actdoc.signoff.act

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

Same-tx append document_signoff_event + update signoff status. action: sign|reject -> SIGNED|REJECTED (+ signed_at, comment); rescind -> PENDING (clear comment+signed_at).

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

Configuredoc.signoff.configure

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

Set mode on all signoff rows for a document.

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

Createdoc.signoff.create

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

Compute next order, inherit mode from existing rows. Unique (document_id,user_id) -> Conflict ‘already a signatory’.

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

Removedoc.signoff.remove

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

Delete the row then re-sequence remaining rows to contiguous order.

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

Archivedoc.template.archive

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

Withdraw a doc-pack from NEW generation: DRAFT|ACTIVE → ARCHIVED. doc.generate already refuses a non-ACTIVE template, so an ARCHIVED pack can no longer author new documents. It NEVER reshapes an in-flight / already-generated document: each generation PINNED its template Version at generate-time (R11, the immutable snapshot), so the produced Documents + generation history are untouched. The pack’s version spine, the generated_document audit rows, and every produced Document are RETAINED (INV-8) - this is a status flip, never a hard DELETE; reversible only via authoring a new version. Mirrors board.archive/doc.archive (status-not-timestamp, INV-3). Idempotent: a re-archive of an ARCHIVED template is a no-op success (changed

).

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

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

Getdoc.template.get

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

-> { id,key,title,status,currentVersion,mergeVars,body,mapping }. READ/L0/MEMBER. Reads a doc template by id, RLS-scoped.

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

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

Listdoc.template.list

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

Withdraw a Document from active listing/authoring → ARCHIVED. The binary, every DocumentVersion, the tracked-change history, and the audit chain are RETAINED (INV-8); the document is still readable via doc.get. Post-archive edit/track/gen are refused; it is NOT a hard delete (byte retention is the EPIC-FILE sweep). { status?, cursor? } -> { items:[{id,key,title,status,currentVersion,mergeVarCount}], count, nextCursor? }. READ/L0/MEMBER. Lists doc templates in the workspace, RLS-scoped, paginated.

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

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

Publishdoc.template.publish

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

Publish: make a pack version CURRENT (DRAFT→ACTIVE). An in-flight generation pinned to a PRIOR version never re-shapes (R11 - the pin is at generate-time).

Input { id, version? } (fields ending in ? are optional)

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

Registerdoc.template.register

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

{ key, title, mergeVars:[{name,class,type?}], body? }. DESTRUCTIVE/L3/ADMIN. Registers a doc-pack body with merge-vars CLASSIFIED required|optional|computed|system at register (the INV-9 coverage source).

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

Versiondoc.template.version

PropertyValue
Capabilitydoc.template.author
Risk classDestructive - autonomy L3
Min. permissionAdmin
AvailabilityAdmin only (CLI/HTTP; never advertised over MCP)
IdempotentNo
EgressNone - in-box (pure Postgres, no outbound call)

Cut a pack version (delegates to the generic version primitive, parent_type=‘OTHER’). The minted version is what doc.template.publish makes current.

Input { id, changelog? } (fields ending in ? are optional)

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

Createdoc.tmpl.create

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

workspace_id from ctx (workspace-owned), created_by_id acting user.

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

Deletedoc.tmpl.delete

PropertyValue
Capabilitydoc.write
Risk classDestructive - autonomy L3
Min. permissionMember
AvailabilityOn demand (MCP tier 2)
IdempotentNo
EgressNone - in-box (pure Postgres, no outbound call)

HARD delete (preserves FE semantics); RLS fence id+workspace_id.

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

Updatedoc.tmpl.update

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

Partial conditional set; RLS fence id+workspace_id.

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

Createdoc.tmpl.version.create

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

Same-tx: insert template_version (next version) + bump templates.current_version. Fence parent template in workspace.

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

Acceptdoc.track.accept

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

Accept (keep+unwrap) / reject (revert) a tracked change. The OOXML run-delta that accept/reject implies belongs to the DocEngine service; the kernel owns the record’s lifecycle + audit. Atomic guard: only a PENDING change transitions (terminal-immutable).

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

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

Rejectdoc.track.reject

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

A sensitive operation in the doc.* family. Called through the one governed front door: capability, permission tier, autonomy, scope and egress are all resolved before the handler runs, and the call is audited (INV-1, INV-8).

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

Versiondoc.version

PropertyValue
Capabilityversion.author
Risk classDestructive - autonomy L3
Min. permissionAdmin
AvailabilityAdmin only (CLI/HTTP; never advertised over MCP)
IdempotentNo
EgressNone - in-box (pure Postgres, no outbound call)

Snapshot-before-overwrite (INV-8 immutable). Mints the generic version row (parent_type=‘DOCUMENT’) for the changelog spine AND a document_version body (content+map).

Input { id, changelog? } (fields ending in ? are optional)

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

Snapshotdoc.version.snapshot

PropertyValue
Capabilityversion.author
Risk classWrite - autonomy L1
Min. permissionMember
AvailabilityCore - always on (MCP tier 1)
IdempotentYes
EgressNone - in-box (pure Postgres, no outbound call)

The least-privilege member-tier sibling of doc.version (Design O-A, [2026] VJS-CC-OPBOX 85): Authz::Member / RiskClass::Write, REUSING the EXISTING version.author capability (no new grant) so the member-session write sites (reupload pre-snapshot, throttled doc-edit snapshot, pre-restore backup) route through the kernel instead of writing DocumentVersion rows directly via Prisma (VJS-DEC 15: writes via verbs).

INV-5 patch-not-reconstruct: the version row is MINTED from the current document state (content + structural_map + binary key as they stand now); it NEVER reconstructs or rebuilds the document.

Idempotent on (documentId, version): the caller MAY pin the version number it is snapshotting (the frontend computes the current version cursor before overwriting); if that (document, version) snapshot already exists, the verb is a no-op SUCCESS that returns the existing row (no 23505, no duplicate). Omitting version forward-mints MAX(version)+1 (the doc.version behaviour) which is not re-derivable, so an UPSERT only short-circuits when the caller pins a version it already wrote.

INV-15 no-amplification: member autonomy stays L1 (min(session, verb) = min(L1, L1) = L1), the write is workspace-scoped (the same RLS as doc.edit), and no capability beyond version.author (already held by every member who can call doc.edit) is conferred. Reversible to Admin in one line (the registry authz field) without touching the immutable rows.

Input { id, version?, changelog? } (fields ending in ? are optional)

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

Recorddoc.view.record

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

Append-only view log (the 5-min throttle read stays in FE).

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

Adddoc.watch.add

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

on (document_id,user_id).

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

Removedoc.watch.remove

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

Delete own watch by (document_id,user_id).

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

Createdoc.webhook.create

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

Per-document/workspace webhook subscription with an encrypted secret. workspace_id from ctx. Returns id only (never echoes the secret).

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

Deletedoc.webhook.delete

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

RLS fence; idempotent (deliveries are FK-cascade).

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

Updatedoc.webhook.update

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

Partial update; undefined=leave, null=clear (documentId scope, headers JsonNull, secret). RLS fence id+workspace_id.

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