opbox

The table.* family (5 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.

Archivetable.archive

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

Sets the table’s archived flag (the soft-hide lane migration 0026 already carries - line 93). REVERSIBLE: archived=true (default) hides it from the default table.list (which filters archived = false unless includeArchived); archived=false un-archives it. NO data is touched - every column / row / Fact is RETAINED (this is the non-destructive twin of table.delete). RLS-scoped with an EXPLICIT workspace_id = $ predicate; a table in another workspace reads back not-found (anti-enumeration). IDEMPOTENT: re-archiving an already-archived table (or un-archiving an active one) is a no-op-shaped success (the UPDATE simply re-asserts the same flag).

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

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

Createtable.create

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

Authors a typed Table. category defaults to USER (the only hand-built category). A SYSTEM table MUST name its systemType and there may be AT MOST ONE per (workspace, systemType) - a second create of the same SYSTEM type is a friendly Conflict (the raw uq_data_table_workspace_system_type violation mapped, never a raw 23505 leak).

Input { name, category?, systemType?, description?, addonKey? } (fields ending in ? are optional)

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

Deletetable.delete

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

The HARD teardown of a table: the data_table row is deleted and its data_column / data_row / data_fact / data_formula children CASCADE by the FK (migration 0026 ON DELETE CASCADE). This is the DESTRUCTIVE/OWNER twin of the reversible table.archive - it does NOT retain data, so it sits at the highest tier (OWNER) the catalogue gives a teardown.

ENTITY-EDGE CASCADE (the verb’s load-bearing extra work): entity_edge endpoints are POLYMORPHIC - there is NO DB FK from an edge to a data_row / data_table (migration 0026 §7, the regen job owns integrity), so the table-row delete does NOT cascade the edges that point at this table’s rows. A LINK-column-minted edge cleans up via source_column_id ON DELETE CASCADE (the columns drop), but a VERB-minted edge (matter.attach of a TABLE_ROW, NULL source_column_id) would be left DANGLING. So this verb EXPLICITLY deletes every entity_edge whose TABLE_ROW endpoint names this table (src_table_id OR dst_table_id = the table) in the SAME tx, so the derived edge index is never left referencing a torn-down table (INV-2/C9 - the index is rebuilt off canonical rows, never left pointing at the void).

REGULATED-PII EXTRA-GATE: a table that carries ANY is_pii column holds (encrypted) regulated cells. Tearing it down is irreversible destruction of regulated data, so it requires an EXPLICIT confirmRegulated=true acknowledgement (the gateOnConfirm convention) - fail-closed otherwise, so a caller cannot destroy a regulated table by a bare one-arg call. A table with no PII column needs no extra flag (the OWNER tier gate alone governs it).

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

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

Gettable.get

PropertyValue
Capabilitydata.table.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

s one table + its columns (the grid schema). RLS-scoped + an explicit workspace predicate.

Input

FieldTypeRequiredDescription
tableIdstringyes

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

Listtable.list

PropertyValue
Capabilitydata.table.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

Lists tables in the workspace (metadata only; columns are the per-table table.get). All filters optional and inert when absent - empty input keeps the historical full list. ids / names / systemType accept an array (the frontend’s { in: [...] } reads); systemType is case-folded to match the stored enum text. q is a case-insensitive name substring (ILIKE, wildcard-escaped - never a SQL error on user text). Filter + projection parity for the frontend’s prisma.table.findMany reads (the data_table SPINE; opbox-prod/PARITY-LEDGER.md track C, disposed by [2026] CC-OPBOX 24/25/34 - reuse/extend the existing reader, no new verb/store/permission-model). RLS-scoped + an explicit workspace predicate (a cross-workspace table is unreachable). Computes nothing authoritative.

Input

FieldTypeRequiredDescription
categorystringnofilter by table category (case-insensitive)
includeArchivedbooleannoinclude archived tables (default false)
idsarraynofilter to these table ids
namesarraynofilter to these exact table names
systemTypearraynofilter by SystemTableType (case-insensitive)
addonKeystringnofilter by owning addon key
qstringnocase-insensitive name substring search
limitintegernopage size (1..500, default 50)
offsetintegernopage offset (default 0)

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