The setup.* family (13 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.
Adoptsetup.adopt
| Property | Value |
|---|---|
| Capability | setup.write |
| Risk class | Destructive - autonomy L3 |
| Min. permission | Owner |
| Availability | Admin only (CLI/HTTP; never advertised over MCP) |
| Idempotent | Yes |
| Egress | None - in-box (pure Postgres, no outbound call) |
(catalogue L471). Adopt a
generic/published vertical as the basis for a workspace setup (the consume side of setup.publish). The
repo-provided template bundle is supplied as sourceManifest (the OCF-style portable contents) + its
sourceKey/sourceVersion provenance; adopt lands it as a LOCAL bundle keyed key, PINNING the
adopted version (R11 - the adopting box keeps its pinned version even if the source later publishes a
newer one). IDEMPOTENT (re-adopt = no-op): re-adopting the SAME source key+version onto the SAME local
key is a no-op-shaped success; adopting a DIFFERENT version updates the pin + manifest. The adopted
bundle lands PUBLISHED at version 1 (it is an adoptable artifact), ready for setup.apply (ADR-0011).
Input { key, sourceKey?, sourceManifest?, sourceVersion? } (fields ending in ? are optional)
Call POST /v/setup.adopt with a JSON body; returns JSON (or { error, code }). Not advertised over MCP (admin-only); reachable via the CLI and HTTP doors.
Applysetup.apply
| Property | Value |
|---|---|
| Capability | setup.write |
| Risk class | Destructive - autonomy L3 |
| Min. permission | Owner |
| Availability | Admin only (CLI/HTTP; never advertised over MCP) |
| Idempotent | Yes |
| Egress | None - in-box (pure Postgres, no outbound call) |
The ADR-0011 reconcile-from-PG edge: instantiate/activate the defined
vertical onto THIS workspace by recording the applied version = the bundle’s current_version. IDEMPOTENT
(the catalogue’s load-bearing property): re-applying the already-applied version is a NO-OP-SHAPED
success (applied=false, “nothing to reconcile”), never a re-instantiation. A DRAFT-only bundle
(current_version 0) cannot be applied (there is no pinned version to reconcile from). Any derived
projection (a board materialisation, a Policy activation) is FIRE-AND-FORGET off this record (INV-2):
the applied_version stamp is the transition; the constituents are reconciled off-band from the pinned
snapshot, never gating this write.
Input
| Field | Type | Required | Description |
|---|---|---|---|
key | string | yes |
Call POST /v/setup.apply with a JSON body; returns JSON (or { error, code }). Not advertised over MCP (admin-only); reachable via the CLI and HTTP doors.
Archivesetup.archive
| Property | Value |
|---|---|
| Capability | setup.write |
| Risk class | Destructive - autonomy L3 |
| Min. permission | Owner |
| Availability | Admin only (CLI/HTTP; never advertised over MCP) |
| Idempotent | Yes |
| Egress | None - in-box (pure Postgres, no outbound call) |
(catalogue L469). Withdraw the bundle from new adoption/instantiation: state -> ARCHIVED. PRESENT-IFF-AUTHORED BECOMES ABSENT-BY-ARCHIVE (ADR-0034): an archived vertical’s verbs are then denied by absence (INV-11 still denies an un-authored verb by absence). REVERSIBLE only via a new version (re-author + publish); history + any in-flight matters pinned to a superseded version are RETAINED/immutable (R11, INV-8 - never a hard delete). Idempotent: archiving an already-ARCHIVED bundle is a no-op-shaped success.
Input { key } (fields ending in ? are optional)
Call POST /v/setup.archive with a JSON body; returns JSON (or { error, code }). Not advertised over MCP (admin-only); reachable via the CLI and HTTP doors.
Definesetup.define
| Property | Value |
|---|---|
| Capability | setup.write |
| Risk class | Destructive - autonomy L3 |
| Min. permission | Admin |
| Availability | On demand (MCP tier 2) |
| Idempotent | Yes |
| Egress | None - in-box (pure Postgres, no outbound call) |
Author or edit a vertical’s config bundle: a named set of constituent refs (verb-packs / matter+doc templates / Policy rule-sets / SOULs). UPSERT on (workspace, key): re-defining the same key edits the bundle IN PLACE (idempotent re-author - never a duplicate). A define always lands the bundle in DRAFT-editable terms (it does NOT auto-publish; INV-9 - publish is the separate gated promotion). The manifest shape is validated at the verb (the keys it accepts are the constituent arrays); an unknown top-level manifest key is rejected (fail-closed lint).
Input
| Field | Type | Required | Description |
|---|---|---|---|
key | string | yes | |
name | string | no | |
description | string | no | |
manifest | object | no | {verbPacks, matterTemplates, docTemplates, policies, souls} |
Call POST /v/setup.define with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool setup.define.
Diffsetup.diff
| Property | Value |
|---|---|
| Capability | setup.read |
| Risk class | Read - autonomy L0 |
| Min. permission | Admin |
| Availability | Admin only (CLI/HTTP; never advertised over MCP) |
| Idempotent | Yes |
| Egress | None - in-box (pure Postgres, no outbound call) |
| Render schema | Yes - drives an inline chat artefact and a GUI panel |
What would change: diff the bundle’s CURRENT
authored manifest against a TARGET. The default target is the LIVE-APPLIED state (the snapshot at
applied_version, or empty if never applied) - so the diff answers “what would setup.apply reconcile?”.
A caller may instead supply an explicit target manifest to diff against (a pre-flight comparison). The
diff is a per-constituent-bucket add/remove/keep set over the manifest arrays (verbPacks / matterTemplates
/ docTemplates / policies / souls). Pure-PG read, no mutation.
Input { key, target?: applied|<manifest> } (fields ending in ? are optional)
Call POST /v/setup.diff with a JSON body; returns JSON (or { error, code }). Not advertised over MCP (admin-only); reachable via the CLI and HTTP doors.
Exportsetup.export
| Property | Value |
|---|---|
| Capability | setup.read |
| Risk class | Read - autonomy L0 |
| Min. permission | Member |
| Availability | On demand (MCP tier 2) |
| Idempotent | Yes |
| Egress | None - in-box (pure Postgres, no outbound call) |
| Render schema | Yes - drives an inline chat artefact and a GUI panel |
Serialize the bundle into a portable, self-describing envelope (the transfer twin of setup.status, but shaped for setup.import / cross-box adoption rather than the ops console). The envelope carries the bundle’s KEY, name/description, current state + version, the authored manifest, and the adoption provenance - everything setup.import needs to re-create the bundle on another box. It is a PURE-PG read (no mutation): RLS-scoped, so another workspace’s bundle reads back not-found (anti-enumeration). The envelope is the wire format - it carries NO ids/timestamps (a re-imported bundle gets a fresh local id), only the workspace-portable authoring content.
Input { key } (fields ending in ? are optional)
Call POST /v/setup.export with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool setup.export.
Getsetup.get
| Property | Value |
|---|---|
| Capability | setup.read |
| Risk class | Read - autonomy L0 |
| Min. permission | Member |
| Availability | Admin only (CLI/HTTP; never advertised over MCP) |
| Idempotent | No |
| Egress | None - in-box (pure Postgres, no outbound call) |
| Render schema | Yes - drives an inline chat artefact and a GUI panel |
Read a single vertical-setup bundle by setupId: the bundle’s core (id, key, name, description, state, currentVersion, appliedVersion), the authored manifest, adoption provenance (adoptedFromKey, adoptedFromVersion), and the immutable changelog (version snapshots, newest first). RLS-scoped; a bundle in another workspace reads back not-found (anti-enumeration, the matter.get / permission shape). Pure-PG read, no mutation.
Call POST /v/setup.get with a JSON body; returns JSON (or { error, code }). Not advertised over MCP (admin-only); reachable via the CLI and HTTP doors.
Importsetup.import
| Property | Value |
|---|---|
| Capability | setup.write |
| Risk class | Destructive - autonomy L3 |
| Min. permission | Admin |
| Availability | On demand (MCP tier 2) |
| Idempotent | Yes |
| Egress | None - in-box (pure Postgres, no outbound call) |
The consume side of
setup.export: re-create (or re-author) a bundle on THIS workspace from a portable envelope. An
envelope (the setup.export output) supplies key/name/description/manifest in one blob; explicit
top-level fields override the envelope (a caller may rename on import). UPSERT on (workspace, key) -
importing onto an existing key edits it IN PLACE (idempotent re-import - never a duplicate). An import
always lands the bundle in DRAFT-editable terms (it does NOT auto-publish; INV-9 - publish is the
separate gated promotion, exactly as setup.define). The manifest is validated at the verb (fail-closed
lint - an unknown bucket / non-array is a BadInput). It does NOT carry the source state/version: an
imported bundle is a fresh local DRAFT, re-published locally (R11 - the importing box owns its own
version line), never silently re-stamped PUBLISHED from the wire.
Input { key?, name?, description?, manifest?, envelope? } (fields ending in ? are optional)
Call POST /v/setup.import with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool setup.import.
Listsetup.list
| Property | Value |
|---|---|
| Capability | setup.read |
| Risk class | Read - autonomy L0 |
| Min. permission | Member |
| Availability | Admin only (CLI/HTTP; never advertised over MCP) |
| Idempotent | No |
| Egress | None - in-box (pure Postgres, no outbound call) |
| Render schema | Yes - drives an inline chat artefact and a GUI panel |
List the workspace’s vertical-setup bundles, optionally filtered by status (DRAFT/PUBLISHED/ARCHIVED). Returns an array of bundle summaries: id, key, name, version, state, createdAt. Paginated (limit resolved from input). RLS-scoped; a workspace cannot see another’s bundles (anti-enumeration). Pure-PG read, no mutation.
Input
| Field | Type | Required | Description |
|---|
Call POST /v/setup.list with a JSON body; returns JSON (or { error, code }). Not advertised over MCP (admin-only); reachable via the CLI and HTTP doors.
Publishsetup.publish
| Property | Value |
|---|---|
| Capability | setup.write |
| Risk class | Destructive - autonomy L3 |
| Min. permission | Owner |
| Availability | On demand (MCP tier 2) |
| Idempotent | No |
| Egress | None - in-box (pure Postgres, no outbound call) |
Promote the bundle’s authored manifest to a PUBLISHED
version: bump current_version, flip state to PUBLISHED, and MINT an immutable version snapshot
(ADR-0027, the reuse-the-Version-spine seam - NOT a new versioning engine). The snapshot is the exact
manifest at publish time, so an adopter pins a real immutable cut. publish is the precondition for
adopt (a DRAFT bundle is not adoptable - L240 “promote a version to the adoptable catalogue”). An
ARCHIVED bundle cannot be published (un-archive is via a new define+publish cycle); re-publishing a
PUBLISHED bundle cuts the NEXT version (history-preserving).
Input
| Field | Type | Required | Description |
|---|---|---|---|
key | string | yes | |
changelog | string | no |
Call POST /v/setup.publish with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool setup.publish.
Rollbacksetup.rollback
| Property | Value |
|---|---|
| Capability | setup.write |
| Risk class | Write - autonomy L1 |
| Min. permission | Admin |
| Availability | On demand (MCP tier 2) |
| Idempotent | Yes |
| Egress | None - in-box (pure Postgres, no outbound call) |
The reconcile-recovery edge (ADR-0011): roll the live workspace
back to a PRIOR published version by re-applying the snapshot at version. The target version must
be a real, already-minted version snapshot for this bundle (1 <= version <= current_version) - a
version with no snapshot, or a future/zero version, is a fail-closed BadInput (you cannot reconcile
from a cut that was never published). This does NOT mutate current_version or the published history
(R11 - the version line is immutable); it only re-points applied_version at the chosen prior
snapshot, so the live workspace reconciles to it (the constituents are reconciled off-band, INV-2,
never gating this write). IDEMPOTENT: rolling back to the already-applied version is a no-op-shaped
success (rolledBack:false), never a re-reconcile.
Input { key, version } (fields ending in ? are optional)
Call POST /v/setup.rollback with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool setup.rollback.
Statussetup.status
| Property | Value |
|---|---|
| Capability | setup.read |
| Risk class | Read - autonomy L0 |
| Min. permission | Admin |
| Availability | Admin only (CLI/HTTP; never advertised over MCP) |
| Idempotent | No |
| Egress | None - in-box (pure Postgres, no outbound call) |
| Render schema | Yes - drives an inline chat artefact and a GUI panel |
The TTS-measurable bundle artifact read: the bundle’s state, currentVersion, appliedVersion, DRIFT (is the live workspace reconciled to the current version?), the manifest contents, and the changelog (the immutable version history). RLS-scoped; a bundle in another workspace reads back not-found (anti-enumeration).
Input { key } (fields ending in ? are optional)
Call POST /v/setup.status with a JSON body; returns JSON (or { error, code }). Not advertised over MCP (admin-only); reachable via the CLI and HTTP doors.
Unpublishsetup.unpublish
| Property | Value |
|---|---|
| Capability | setup.write |
| Risk class | Destructive - autonomy L3 |
| Min. permission | Owner |
| Availability | On demand (MCP tier 2) |
| Idempotent | No |
| Egress | None - in-box (pure Postgres, no outbound call) |
Withdraw a PUBLISHED bundle from the adoptable catalogue by demoting
it back to DRAFT (the reverse of setup.publish, the milder twin of setup.archive). A DRAFT bundle is
not adoptable (setup.adopt / a fresh setup.apply key off PUBLISHED), so unpublish takes the bundle off
the catalogue WITHOUT archiving it - it stays editable (setup.define) and re-publishable. The minted
version snapshots + current_version are RETAINED (R11 - the immutable history is never rewound); any
in-flight matter pinned to a published version is unaffected. ONLY a PUBLISHED bundle can be
unpublished: a DRAFT bundle is a fail-closed Conflict (nothing to demote), and an ARCHIVED bundle is a
Conflict (un-archive is a new define+publish cycle, ADR-0034). Not idempotent: a re-unpublish of a now
DRAFT bundle is the same Conflict (it is no longer PUBLISHED).
Input { key } (fields ending in ? are optional)
Call POST /v/setup.unpublish with a JSON body; returns JSON (or { error, code }). Also exposed as the MCP tool setup.unpublish.