MCP Tools Reference
Moira exposes workflow execution capabilities through MCP tools. The catalog below is the authoritative reference for tool names, actions, input schemas, and valid example inputs. The documentation build reads the same pure typed contract used by MCP registration and runtime help directly.
Tool descriptions and their supported agent/model variants are static parts of this catalog and cannot be overridden through database settings. Runtime system instructions are delivered separately through MCP initialization and never alter a tool description.
MCP tools
list
Discover workflows available to the current user.
Input schema
{
"type": "object",
"properties": {
"search": {
"type": "string",
"description": "Search in workflow name and description"
},
"visibility": {
"type": "string",
"enum": [
"public",
"private",
"all"
],
"description": "Filter by visibility (default: all accessible)"
},
"sort": {
"type": "string",
"enum": [
"createdAt",
"name"
],
"description": "Sort field (default: createdAt)"
},
"sortOrder": {
"type": "string",
"enum": [
"asc",
"desc"
],
"description": "Sort order (default: desc)"
},
"limit": {
"type": "number",
"minimum": 1,
"maximum": 100,
"description": "Number of results (default: 20, max: 100)"
},
"offset": {
"type": "number",
"minimum": 0,
"description": "Offset for pagination (default: 0)"
}
},
"additionalProperties": false,
"$schema": "http://json-schema.org/draft-07/schema#"
}Result: A workflow page with explicit offset, limit, returnedCount, hasMore, and nextOffset.
{
"limit": 20,
"offset": 0
}{
"limit": 20,
"offset": 20
}reconciliation
Inspect or resolve bundled-workflow reconciliation errors. Status returns candidate references to every agent and full candidate states to administrators. Get and resolve are administrator-only; use Workflow Management Flow to semantically merge candidates, then submit the merged graph.
Actions: status, get, resolve.
Input schema
{
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": [
"status",
"get",
"resolve"
]
},
"reference": {
"type": "string"
},
"selection": {
"type": "string",
"enum": [
"current",
"incoming",
"previous"
]
},
"revision": {
"type": "string",
"pattern": "^[a-f0-9]{64}$"
},
"rationale": {
"type": "string",
"minLength": 1,
"maxLength": 2000
},
"mergedGraph": {
"type": "object",
"additionalProperties": {}
},
"visibility": {
"type": "string",
"enum": [
"public",
"private"
]
}
},
"required": [
"action"
],
"additionalProperties": false,
"$schema": "http://json-schema.org/draft-07/schema#"
}Result: Conflict status, a candidate, or a resolution result.
{
"action": "status"
}start
Prepare, then execute, a replay-safe workflow start.
Actions: prepare, execute.
Input schema
{
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": [
"prepare",
"execute"
],
"description": "Start phase: prepare reserves an attempt; execute consumes that attempt"
},
"workflowId": {
"type": "string",
"description": "Workflow ID to prepare (required for prepare; use list() for available workflows)"
},
"note": {
"type": "string",
"maxLength": 500,
"description": "Optional prepare execution note (max 500 chars)"
},
"parentExecutionId": {
"type": "string",
"description": "Required for prepare. Use \"none\" for standalone, or a parent process UUID."
},
"skipNotificationCheck": {
"type": "boolean",
"description": "Prepare only. Skip optional ordinary channel checks; lock PIN delivery remains mandatory"
},
"skipTelegramCheck": {
"type": "boolean",
"description": "Prepare only. Deprecated alias for skipNotificationCheck"
},
"startAttemptId": {
"type": "string",
"format": "uuid",
"description": "Required for execute. Start attempt ID returned by prepare"
}
},
"required": [
"action"
],
"additionalProperties": false,
"$schema": "http://json-schema.org/draft-07/schema#"
}Result: A start attempt receipt or the process ID and first instruction.
{
"action": "prepare",
"workflowId": "moira/quick-task",
"parentExecutionId": "none"
}{
"action": "execute",
"startAttemptId": "00000000-0000-4000-8000-000000000000"
}step
Continue an existing workflow execution.
Input schema
{
"type": "object",
"properties": {
"processId": {
"type": "string",
"description": "Process ID from start() or previous step() response"
},
"attemptId": {
"type": "string",
"description": "Step attempt ID from the current start(), step(), or session current_step response"
},
"input": {
"anyOf": [
{
"type": "string"
},
{
"type": "object",
"additionalProperties": {}
},
{
"type": "array",
"items": {}
},
{
"type": "number"
},
{
"type": "boolean"
},
{
"type": "null"
}
],
"description": "Input data matching the step's inputSchema. Structure depends on current step requirements."
},
"teleportTo": {
"type": "string",
"description": "Optional teleport node ID to jump execution to. Only teleport-type nodes can be targets. When provided, execution jumps to the teleport node instead of following normal flow. Do NOT provide input when teleporting."
}
},
"required": [
"processId",
"attemptId"
],
"additionalProperties": false,
"$schema": "http://json-schema.org/draft-07/schema#"
}Result: The next instruction with its step attempt ID, or a terminal result.
{
"processId": "00000000-0000-4000-8000-000000000000",
"attemptId": "11111111-1111-4111-8111-111111111111",
"input": {
"outcome": "completed"
}
}manage
Create, inspect, validate, and modify workflows. Express a decision as `cases` on the node that has the evidence (a directive routes on its own answer, `success` when no case holds) with single-purpose arithmetic as its `expressions`; keep a separate condition or expression node only for a shared or standalone decision. Bind a progress block to the list it works through with `list`.
Actions: create, edit, get, get-structure, get-node, search-nodes, validate, get-variable, set-variable, list-variables, delete-variable, diff, copy, clone-node, move-node, list-nodes, get-nodes, analyze-variables, set-visibility, create-invite, list-access, list-invites, revoke-access, revoke-invite.
Input schema
{
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": [
"create",
"edit",
"get",
"get-structure",
"get-node",
"search-nodes",
"validate",
"get-variable",
"set-variable",
"list-variables",
"delete-variable",
"diff",
"copy",
"clone-node",
"move-node",
"list-nodes",
"get-nodes",
"analyze-variables",
"set-visibility",
"create-invite",
"list-access",
"list-invites",
"revoke-access",
"revoke-invite"
],
"description": "Action to perform on workflow"
},
"workflowId": {
"type": "string",
"description": "Target workflow ID (required for most actions except create)"
},
"workflow": {
"type": "object",
"properties": {
"id": {
"type": "string",
"description": "Workflow ID (auto-generated if not provided)"
},
"metadata": {
"type": "object",
"properties": {
"name": {
"type": "string",
"description": "Human-readable workflow name"
},
"version": {
"type": "string",
"description": "Semantic version (e.g., '1.0.0')"
},
"description": {
"type": "string",
"description": "Brief workflow description"
},
"author": {
"type": "string",
"description": "Workflow author"
},
"tags": {
"type": "array",
"items": {
"type": "string"
},
"description": "Workflow tags"
}
},
"required": [
"name",
"version",
"description"
],
"additionalProperties": false
},
"nodes": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": {}
},
"description": "Array of workflow nodes. Decisions are `cases` on the deciding node (condition or agent-directive) with a default output; a separate condition or expression node serves shared or standalone decisions."
},
"variableRegistry": {
"type": "object",
"additionalProperties": {},
"description": "Declared global variables (JSON-Schema-shaped: name -> {type, description, default?}). Required for any variable referenced by bare name in directives, routing cases, expressions, progress list bindings and templates."
},
"runtimePolicy": {
"type": "object",
"properties": {
"externalVariableWrites": {
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"allowedNodeIds": {
"type": "array",
"items": {
"type": "string"
}
}
},
"additionalProperties": false
}
}
},
"additionalProperties": false
},
"progress": {
"type": "object",
"properties": {
"title": {
"type": "string",
"minLength": 1,
"maxLength": 200
},
"goal": {
"type": "string",
"minLength": 1,
"maxLength": 1000
},
"facts": {
"type": "array",
"items": {
"type": "object",
"properties": {
"label": {
"type": "string",
"minLength": 1,
"maxLength": 100
},
"value": {
"type": "string",
"minLength": 1,
"maxLength": 500
},
"tone": {
"type": "string",
"enum": [
"neutral",
"positive",
"warning",
"critical"
]
}
},
"required": [
"label",
"value"
],
"additionalProperties": false
},
"maxItems": 8
},
"nodes": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"minLength": 1
},
"label": {
"type": "string",
"minLength": 1,
"maxLength": 200
},
"content": {
"type": "object",
"properties": {
"summary": {
"type": "string",
"minLength": 1,
"maxLength": 1000
},
"details": {
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"maxLength": 500
},
"maxItems": 12
},
"outcome": {
"type": "string",
"minLength": 1,
"maxLength": 1000
},
"next": {
"type": "string",
"minLength": 1,
"maxLength": 500
}
},
"required": [
"summary"
],
"additionalProperties": false
},
"connections": {
"type": "object",
"properties": {
"default": {
"type": "string",
"minLength": 1
}
},
"additionalProperties": false
},
"list": {
"type": "object",
"properties": {
"items": {
"type": "string",
"minLength": 1
},
"title": {
"type": "string",
"minLength": 1
},
"current": {
"type": "string",
"minLength": 1
},
"done": {
"type": "string",
"minLength": 1
},
"total": {
"type": "string",
"minLength": 1
},
"indexBase": {
"type": "number",
"enum": [
0,
1
]
}
},
"additionalProperties": false
}
},
"required": [
"id",
"label",
"content"
],
"additionalProperties": false
},
"minItems": 1,
"maxItems": 18
}
},
"required": [
"nodes"
],
"additionalProperties": false
},
"visibility": {
"type": "string",
"enum": [
"public",
"private"
],
"description": "Workflow visibility (default: private)"
},
"systemReminder": {
"type": "string",
"description": "System reminder shown to agent on each step"
}
},
"required": [
"metadata",
"nodes"
],
"additionalProperties": false,
"description": "Full workflow object for create action"
},
"overwrite": {
"type": "boolean",
"description": "Overwrite existing workflow with same ID (default: false)"
},
"changes": {
"type": "object",
"properties": {
"metadata": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"version": {
"type": "string"
},
"description": {
"type": "string"
},
"author": {
"type": "string"
},
"tags": {
"type": "array",
"items": {
"type": "string"
}
}
},
"additionalProperties": false,
"description": "Metadata fields to update"
},
"variableRegistry": {
"type": "object",
"additionalProperties": {},
"description": "Replace the workflow's declared global variable registry"
},
"runtimePolicy": {
"type": "object",
"properties": {
"externalVariableWrites": {
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"allowedNodeIds": {
"type": "array",
"items": {
"type": "string"
}
}
},
"additionalProperties": false
}
}
},
"additionalProperties": false
},
"progress": {
"type": "object",
"properties": {
"title": {
"type": "string",
"minLength": 1,
"maxLength": 200
},
"goal": {
"type": "string",
"minLength": 1,
"maxLength": 1000
},
"facts": {
"type": "array",
"items": {
"type": "object",
"properties": {
"label": {
"type": "string",
"minLength": 1,
"maxLength": 100
},
"value": {
"type": "string",
"minLength": 1,
"maxLength": 500
},
"tone": {
"type": "string",
"enum": [
"neutral",
"positive",
"warning",
"critical"
]
}
},
"required": [
"label",
"value"
],
"additionalProperties": false
},
"maxItems": 8
},
"nodes": {
"type": "array",
"items": {
"type": "object",
"properties": {
"id": {
"type": "string",
"minLength": 1
},
"label": {
"type": "string",
"minLength": 1,
"maxLength": 200
},
"content": {
"type": "object",
"properties": {
"summary": {
"type": "string",
"minLength": 1,
"maxLength": 1000
},
"details": {
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"maxLength": 500
},
"maxItems": 12
},
"outcome": {
"type": "string",
"minLength": 1,
"maxLength": 1000
},
"next": {
"type": "string",
"minLength": 1,
"maxLength": 500
}
},
"required": [
"summary"
],
"additionalProperties": false
},
"connections": {
"type": "object",
"properties": {
"default": {
"type": "string",
"minLength": 1
}
},
"additionalProperties": false
},
"list": {
"type": "object",
"properties": {
"items": {
"type": "string",
"minLength": 1
},
"title": {
"type": "string",
"minLength": 1
},
"current": {
"type": "string",
"minLength": 1
},
"done": {
"type": "string",
"minLength": 1
},
"total": {
"type": "string",
"minLength": 1
},
"indexBase": {
"type": "number",
"enum": [
0,
1
]
}
},
"additionalProperties": false
}
},
"required": [
"id",
"label",
"content"
],
"additionalProperties": false
},
"minItems": 1,
"maxItems": 18
}
},
"required": [
"nodes"
],
"additionalProperties": false
},
"addNodes": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": {}
},
"description": "New nodes to add"
},
"removeNodes": {
"type": "array",
"items": {
"type": "string"
},
"description": "Node IDs to remove"
},
"updateNodes": {
"type": "array",
"items": {
"type": "object",
"properties": {
"nodeId": {
"type": "string",
"description": "ID of node to update"
},
"changes": {
"description": "Fields to update on the node"
}
},
"required": [
"nodeId"
],
"additionalProperties": false
},
"description": "Nodes to update with specific changes"
},
"removeConnections": {
"type": "array",
"items": {
"type": "object",
"properties": {
"nodeId": {
"type": "string",
"description": "ID of node with connection to remove"
},
"connectionKey": {
"type": "string",
"description": "Connection key to remove (e.g., 'default', 'true', 'false')"
}
},
"required": [
"nodeId",
"connectionKey"
],
"additionalProperties": false
},
"description": "Connections to remove from nodes"
},
"systemReminder": {
"type": "string",
"description": "New system reminder text"
}
},
"additionalProperties": false,
"description": "Changes to apply for edit action"
},
"expectedRevision": {
"type": "integer",
"minimum": 0,
"description": "edit only: the workflow revision the changes were prepared against (from get); the edit is refused when the stored revision differs"
},
"includeNodes": {
"type": "boolean",
"description": "Include full node definitions in get response"
},
"includeValidation": {
"type": "boolean",
"description": "Include validation results in response"
},
"offset": {
"type": "number",
"description": "Pagination offset for node listing"
},
"limit": {
"type": "number",
"description": "Maximum nodes to return"
},
"nodeId": {
"type": "string",
"description": "Specific node ID for get-node and clone-node actions"
},
"query": {
"type": "string",
"description": "Search query for search-nodes action"
},
"variableName": {
"type": "string",
"description": "Variable name for get/set/delete-variable actions"
},
"variableValue": {
"description": "Variable value for set-variable action"
},
"variableNames": {
"type": "array",
"items": {
"type": "string"
}
},
"variableTypes": {
"type": "array",
"items": {
"type": "string"
}
},
"hasDefault": {
"type": "boolean"
},
"externallyWritable": {
"type": "boolean"
},
"compareWorkflowId": {
"type": "string",
"description": "Second workflow ID for diff action"
},
"newName": {
"type": "string",
"description": "New name for copied workflow (copy action)"
},
"newId": {
"type": "string",
"description": "New ID for cloned node (clone-node action)"
},
"targetIndex": {
"type": "number",
"description": "Target position for node (move-node action)"
},
"afterNodeId": {
"type": "string",
"description": "Place node after this node ID (move-node only, alternative to targetIndex)"
},
"typeFilter": {
"type": "string",
"description": "Filter nodes by type (list-nodes only)"
},
"includePreview": {
"type": "boolean",
"description": "Include directive preview (list-nodes only)"
},
"previewLength": {
"type": "number",
"description": "Length of directive preview (list-nodes only, default 100)"
},
"nodeIds": {
"type": "array",
"items": {
"type": "string"
},
"description": "Array of node IDs to retrieve (get-nodes only)"
},
"includeVariables": {
"type": "boolean",
"description": "Include variables in search (search-nodes only)"
},
"snippetMode": {
"type": "boolean",
"description": "Return only snippets, not full nodes (search-nodes only)"
},
"graph": {
"type": "boolean",
"description": "Return ASCII flow graph (get-structure only)"
},
"detailed": {
"type": "boolean",
"description": "Include directive preview in structure (get-structure only)"
},
"visibility": {
"type": "string",
"enum": [
"public",
"private"
],
"description": "New visibility setting (set-visibility only)"
},
"inviteId": {
"type": "string",
"description": "Invite ID (required for revoke-invite)"
},
"targetUserId": {
"type": "string",
"description": "User ID to revoke access from (revoke-access only)"
},
"ttlMs": {
"type": "number",
"description": "Invite expiration time in milliseconds (create-invite only, default 7 days)"
},
"activeOnly": {
"type": "boolean",
"description": "Filter to active (unused) invites only (list-invites only, default true)"
}
},
"required": [
"action"
],
"additionalProperties": false,
"$schema": "http://json-schema.org/draft-07/schema#"
}Result: Action-specific workflow data.
{
"action": "get",
"workflowId": "moira/quick-task",
"includeNodes": false,
"includeValidation": false
}{
"action": "list-nodes",
"workflowId": "moira/quick-task",
"includePreview": true
}{
"action": "get-nodes",
"workflowId": "moira/quick-task",
"nodeIds": [
"start",
"end"
]
}{
"action": "analyze-variables",
"workflowId": "moira/quick-task"
}{
"action": "set-visibility",
"workflowId": "my-workflow",
"visibility": "private"
}help
Read runtime documentation and the factual tool reference.
Input schema
{
"type": "object",
"properties": {
"topic": {
"anyOf": [
{
"type": "string"
},
{
"type": "array",
"items": {
"type": "string"
}
}
],
"description": "Documentation topic(s) to retrieve. Call without a topic to discover the current topics and accepted aliases."
}
},
"additionalProperties": false,
"$schema": "http://json-schema.org/draft-07/schema#"
}Result: Markdown documentation.
{
"topic": "tools"
}settings
Read or update user settings.
Actions: get, set, list.
Input schema
{
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": [
"get",
"set",
"list"
],
"description": "Action: get (one key, one category, or all values), set (update one value), list (definitions by category or all)"
},
"category": {
"type": "string",
"minLength": 1,
"pattern": "\\S",
"description": "Category filter for get and list; do not combine with key for get"
},
"key": {
"type": "string",
"minLength": 1,
"pattern": "\\S",
"description": "Exact setting key for get or set (e.g., 'telegram.bot_token')"
},
"value": {
"description": "New value for set action"
}
},
"required": [
"action"
],
"additionalProperties": false,
"$schema": "http://json-schema.org/draft-07/schema#"
}Result: Masked setting data or an update result.
{
"action": "get",
"key": "telegram.enabled"
}{
"action": "get",
"category": "notifications"
}{
"action": "get"
}token
Create short-lived workflow upload or download tokens.
Actions: upload, download.
Input schema
{
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": [
"upload",
"download"
],
"description": "Token type: upload (for creating workflows), download (for retrieving)"
},
"workflowId": {
"type": "string",
"description": "Workflow ID (required for download action)"
},
"ttlMinutes": {
"type": "number",
"default": 60,
"description": "Token expiration time in minutes (default: 60)"
}
},
"required": [
"action"
],
"additionalProperties": false,
"$schema": "http://json-schema.org/draft-07/schema#"
}Result: A formatted URL and usage instructions.
{
"action": "upload",
"ttlMinutes": 60
}communication
Send ordinary text or deliver a native/owner-held file through configured channels. Binary delivery requires an original ws1 request_id and an available source owner; operation collects its receipt without resending.
Actions: send, deliver-file, operation.
Input schema
{
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": [
"send",
"deliver-file",
"operation"
]
},
"message": {
"type": "string"
},
"format": {
"type": "string",
"enum": [
"plain",
"markdown",
"html"
]
},
"silent": {
"type": "boolean"
},
"kind": {
"type": "string",
"enum": [
"image",
"document"
]
},
"request_id": {
"type": "string",
"pattern": "^ws1-[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$",
"description": "Choose the original ws1 delivery identity before submission; collect it with operation after uncertainty, without resending"
},
"device_id": {
"type": "string",
"format": "uuid",
"description": "Paired source controller; required when more than one live controller is eligible, and for its original operation collection"
},
"codespace_id": {
"type": "string",
"format": "uuid",
"description": "Original workspace owner for operation collection"
},
"referenceId": {
"type": "string",
"pattern": "^owner-file:\\/\\/(workspace|controller)\\/[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}\\/[A-Za-z0-9_-]{43}$",
"description": "Immutable owner-file:// workspace/controller reference from publication; bytes stay with that owner"
},
"file": {
"type": "object",
"properties": {
"file_id": {
"type": "string",
"maxLength": 512,
"pattern": "^(?:sediment:\\/\\/)?file_[A-Za-z0-9]+$"
},
"download_url": {
"type": "string",
"format": "uri"
},
"file_name": {
"type": "string",
"minLength": 1,
"maxLength": 255
},
"mime_type": {
"type": "string",
"maxLength": 127,
"pattern": "^[a-z0-9][a-z0-9!#$&^_.+-]*\\/[a-z0-9][a-z0-9!#$&^_.+-]*$"
},
"size_bytes": {
"type": "integer",
"minimum": 0
}
},
"required": [
"file_id",
"download_url"
],
"additionalProperties": false,
"description": "Native ChatGPT file acquired directly by the selected paired owner, without cloud download"
},
"channelId": {
"type": "string",
"pattern": "^[a-z0-9][a-z0-9._-]*$",
"description": "One configured channel; omit to use configured eligible channels"
}
},
"required": [
"action"
],
"additionalProperties": false,
"$schema": "http://json-schema.org/draft-07/schema#"
}Result: A text delivery summary or an owner receipt with its original request and assigned device/workspace identity. Uncertainty preserves that identity; no cloud file grant is issued.
{
"action": "send",
"message": "The report is ready."
}{
"action": "deliver-file",
"request_id": "ws1-11111111-1111-4111-8111-111111111111",
"message": "Report",
"kind": "document",
"referenceId": "owner-file://workspace/00000000-0000-4000-8000-000000000000/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
}{
"action": "operation",
"request_id": "ws1-11111111-1111-4111-8111-111111111111",
"device_id": "00000000-0000-4000-8000-000000000000"
}session
Inspect and update execution-scoped state.
Actions: user, executions, execution_context, current_step, diagnose, recover, cancel-execution, stop-execution, update-note, update-task-title, set-parent, add-reminder, reminders, update-reminder, remove-reminder, variables, set-variable, await-user, progress, progress-image-token, materialize.
Input schema
{
"type": "object",
"properties": {
"device_id": {
"type": "string",
"format": "uuid",
"description": "Selected paired controller for progress-image-token; omit only when exactly one live controller is eligible"
},
"action": {
"type": "string",
"enum": [
"user",
"executions",
"execution_context",
"current_step",
"diagnose",
"recover",
"cancel-execution",
"stop-execution",
"update-note",
"update-task-title",
"set-parent",
"add-reminder",
"reminders",
"update-reminder",
"remove-reminder",
"variables",
"set-variable",
"await-user",
"progress",
"progress-image-token",
"materialize"
],
"description": "Action to perform"
},
"executionId": {
"type": "string",
"description": "Execution ID for execution_context, current_step, diagnose, recover, update-note, or materialize actions"
},
"nodeId": {
"type": "string",
"description": "Node the run must resume from (required for recover)"
},
"variableValues": {
"type": "object",
"additionalProperties": {},
"description": "Variable values written into the execution context while recovering (recover only)"
},
"status": {
"type": "array",
"items": {
"type": "string",
"enum": [
"running",
"waiting",
"completed",
"failed",
"locked"
]
},
"description": "Filter executions by status (array of statuses)"
},
"workflowId": {
"type": "string",
"description": "Filter by workflow ID"
},
"search": {
"type": "string",
"description": "Search in execution notes"
},
"sort": {
"type": "string",
"enum": [
"createdAt",
"updatedAt"
],
"description": "Sort field for executions list"
},
"sortOrder": {
"type": "string",
"enum": [
"asc",
"desc"
],
"description": "Sort order (ascending or descending)"
},
"limit": {
"type": "number",
"minimum": 1,
"maximum": 100,
"description": "Maximum executions to return (1-100)"
},
"offset": {
"type": "number",
"minimum": 0,
"description": "Pagination offset"
},
"note": {
"type": "string",
"maxLength": 500,
"description": "New note text for update-note action (max 500 chars)"
},
"taskTitle": {
"type": "string",
"maxLength": 500,
"description": "Concise actual task name for update-task-title; independent of note and flow name"
},
"expectedTaskIdentityRevision": {
"type": "string",
"minLength": 64,
"maxLength": 64,
"description": "Task identity revision from execution_context or the Progress API"
},
"parentExecutionId": {
"type": "string",
"description": "Parent execution UUID or \"none\" for set-parent"
},
"expectedRevision": {
"type": "integer",
"minimum": 0,
"description": "Expected workflow-step revision"
},
"reason": {
"type": "string",
"minLength": 1,
"maxLength": 500,
"description": "Required explanation for stop-execution (1–500 characters)"
},
"expectedParentRevision": {
"type": "string",
"minLength": 64,
"maxLength": 64,
"description": "Parent target revision returned by execution_context or set-parent"
},
"expectedRemindersRevision": {
"type": "string",
"minLength": 64,
"maxLength": 64,
"description": "Reminder collection revision returned by reminders or a reminder mutation"
},
"expectedContextRevision": {
"type": "string",
"minLength": 64,
"maxLength": 64,
"description": "Context target revision returned by variables, execution_context, or set-variable"
},
"reminderId": {
"type": "string",
"description": "Reminder ID"
},
"reminderText": {
"type": "string",
"description": "Reminder text"
},
"idempotencyKey": {
"type": "string",
"description": "Idempotency key for add-reminder"
},
"reminderStatus": {
"type": "string",
"enum": [
"active",
"cancelled"
],
"description": "Reminder status filter"
},
"names": {
"type": "array",
"items": {
"type": "string"
}
},
"types": {
"type": "array",
"items": {
"type": "string"
}
},
"editable": {
"type": "boolean"
},
"hasValue": {
"type": "boolean"
},
"writePhase": {
"type": "string",
"enum": [
"current",
"other"
]
},
"variableName": {
"type": "string"
},
"variableValue": {},
"question": {
"type": "string",
"minLength": 1,
"maxLength": 500,
"description": "await-user: what you need from the person, in a sentence or two"
},
"options": {
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"maxLength": 200
},
"minItems": 1,
"maxItems": 4,
"description": "await-user: the choices, when the question is a choice"
},
"resolve": {
"type": "boolean",
"const": true,
"description": "await-user: clear your open question instead of raising one"
},
"theme": {
"type": "string",
"enum": [
"light",
"dark"
]
},
"viewportWidth": {
"type": "integer",
"minimum": 480,
"maximum": 4096
},
"view": {
"type": "string",
"enum": [
"cards",
"process"
],
"description": "progress-image-token: cards (default) draws every block as a content card; process draws the aggregated block view with labelled transitions and loops"
},
"hide": {
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"maxLength": 200
},
"maxItems": 100,
"description": "progress-image-token: block ids or authored node ids (resolved to their block) left out of the image; their transitions collapse"
},
"collapse": {
"type": "array",
"items": {
"type": "string",
"minLength": 1,
"maxLength": 200
},
"maxItems": 100,
"description": "progress-image-token: block ids or authored node ids drawn as a label-only chip"
},
"at": {
"type": "integer",
"minimum": 0,
"description": "Route cursor for progress: project the run as of this visit sequence number (the route is cut there, variables carry the values written up to it)"
}
},
"required": [
"action"
],
"additionalProperties": false,
"$schema": "http://json-schema.org/draft-07/schema#"
}Result: Action-specific session or execution data.
{
"action": "executions",
"limit": 20,
"offset": 0
}notes
Store and retrieve versioned notes.
Actions: list, get, save, delete, history, stats.
Input schema
{
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": [
"list",
"get",
"save",
"delete",
"history",
"stats"
],
"description": "Action to perform on notes"
},
"tag": {
"type": "string",
"description": "Filter notes by tag (for list action)"
},
"keySearch": {
"type": "string",
"description": "Search notes by key pattern (for list action)"
},
"limit": {
"type": "number",
"minimum": 1,
"maximum": 100,
"description": "Maximum notes to return (1-100, default 50)"
},
"offset": {
"type": "number",
"minimum": 0,
"description": "Pagination offset (default 0)"
},
"key": {
"type": "string",
"description": "Note key (required for get, save, delete, history actions)"
},
"version": {
"type": "number",
"description": "Specific version number to retrieve (for get action)"
},
"value": {
"type": "string",
"description": "Note content (required for save action)"
},
"tags": {
"type": "array",
"items": {
"type": "string"
},
"description": "Tags for the note (for save action, max 10 tags)"
}
},
"required": [
"action"
],
"additionalProperties": false,
"$schema": "http://json-schema.org/draft-07/schema#"
}Result: Action-specific note data.
{
"action": "list",
"limit": 20,
"offset": 0
}playbooks
Keep named, reusable behaviour text an agent can read where it is needed.
Actions: list, get, save, delete, history, compare, restore, visibility.
Input schema
{
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": [
"list",
"get",
"save",
"delete",
"history",
"compare",
"restore",
"visibility"
],
"description": "Action to perform on playbooks"
},
"name": {
"type": "string",
"description": "Playbook machine name (required for every action except list)"
},
"owner": {
"type": "string",
"description": "Owner handle or id when reading someone else's public playbook; defaults to you"
},
"search": {
"type": "string",
"description": "Search playbooks by name or description (for list)"
},
"limit": {
"type": "number",
"minimum": 1,
"maximum": 100,
"description": "Maximum playbooks to return (1-100, default 50)"
},
"offset": {
"type": "number",
"minimum": 0,
"description": "Pagination offset (default 0)"
},
"content": {
"type": "string",
"description": "Playbook text (required for save)"
},
"title": {
"type": "string",
"description": "Human-readable name (for save)"
},
"description": {
"type": "string",
"description": "What this playbook is for (for save)"
},
"revision": {
"type": "number",
"description": "Revision number to read or restore (for get and restore)"
},
"fromRevision": {
"type": "number",
"description": "Older revision to compare (for compare)"
},
"toRevision": {
"type": "number",
"description": "Newer revision to compare (for compare)"
},
"visibility": {
"type": "string",
"enum": [
"private",
"public"
],
"description": "Who may read the playbook (for visibility)"
}
},
"required": [
"action"
],
"additionalProperties": false,
"$schema": "http://json-schema.org/draft-07/schema#"
}Result: Action-specific playbook data.
{
"action": "list",
"limit": 20,
"offset": 0
}artifacts
Manage static HTML artifacts.
Actions: upload, update, delete, list, stats, token.
Input schema
{
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": [
"upload",
"update",
"delete",
"list",
"stats",
"token"
],
"description": "Action to perform on artifacts"
},
"name": {
"type": "string",
"description": "Artifact name (required for upload action)"
},
"content": {
"type": "string",
"description": "HTML content (required for upload and update actions)"
},
"executionId": {
"type": "string",
"description": "Link artifact to workflow execution (optional for upload)"
},
"uuid": {
"type": "string",
"description": "Artifact UUID (required for update and delete actions)"
},
"limit": {
"type": "number",
"minimum": 1,
"maximum": 100,
"description": "Maximum artifacts to return (1-100, default 50)"
},
"offset": {
"type": "number",
"minimum": 0,
"description": "Pagination offset (default 0)"
},
"ttlMinutes": {
"type": "number",
"minimum": 1,
"maximum": 1440,
"description": "Token expiration in minutes (1-1440, default 60)"
}
},
"required": [
"action"
],
"additionalProperties": false,
"$schema": "http://json-schema.org/draft-07/schema#"
}Result: Artifact metadata, quota data, or a token.
{
"action": "list",
"limit": 20,
"offset": 0
}lock
Inspect, create, or unlock execution locks.
Actions: status, list, unlock, lock.
Input schema
{
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": [
"status",
"list",
"unlock",
"lock"
],
"description": "Action to perform on locks"
},
"executionId": {
"type": "string",
"description": "Execution ID (required for all actions)"
},
"pin": {
"type": "string",
"description": "PIN code to unlock (required for unlock action)"
},
"reason": {
"type": "string",
"description": "Reason for locking the execution (required for lock action)"
}
},
"required": [
"action",
"executionId"
],
"additionalProperties": false,
"$schema": "http://json-schema.org/draft-07/schema#"
}Result: Lock state without a secret PIN.
{
"action": "status",
"executionId": "00000000-0000-4000-8000-000000000000"
}codespace
Work in a persistent GitHub or local Docker Sandboxes codespace: lifecycle, commands and files, by action. Both providers' lifecycle mutations require a caller-selected ws1 request_id; start/stop/delete and adoption by codespace_id require the observed generation from get/list. GitHub create/adopt runs through the selected available paired controller. Recover through operation with device_id and the original request_id, including a lost create reply before a codespace_id is known.
Actions: local_devices, operation, repository_add, repository_create, preview_image, pull_request_create, pull_request_get, pull_request_find, list, repositories, setup_help, create, adopt, get, start, stop, delete, exec, stat, search, read, write, apply_patch, upload, download.
Input schema
{
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": [
"local_devices",
"operation",
"repository_add",
"repository_create",
"preview_image",
"pull_request_create",
"pull_request_get",
"pull_request_find",
"list",
"repositories",
"setup_help",
"create",
"adopt",
"get",
"start",
"stop",
"delete",
"exec",
"stat",
"search",
"read",
"write",
"apply_patch",
"upload",
"download"
],
"description": "Codespace operation to perform"
},
"device_id": {
"type": "string",
"format": "uuid",
"description": "Paired controller device ID from local_devices or resource discovery"
},
"request_id": {
"anyOf": [
{
"type": "string",
"pattern": "^ws1-[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$",
"description": "Original ws1 controller lifecycle/provisioning/settings request ID for either provider. Inspect even when create returned no codespace ID; collection never resubmits the effect"
},
{
"type": "string",
"format": "uuid",
"description": "Stable admission identity; reuse it until applied"
}
]
},
"repository_id": {
"anyOf": [
{
"type": "string",
"pattern": "^[1-9][0-9]*$",
"description": "Verified GitHub repository ID"
},
{
"type": "string",
"minLength": 1,
"maxLength": 255,
"description": "Repository provider ID to diagnose, when the task already names one"
}
]
},
"repository_name": {
"type": "string",
"minLength": 1,
"maxLength": 100,
"pattern": "^[A-Za-z0-9_.-]+$",
"description": "New private repository name in the connected personal GitHub account"
},
"installation_id": {
"type": "string",
"pattern": "^[1-9][0-9]{0,39}$",
"description": "Approved GitHub App installation on that personal account"
},
"codespace_id": {
"type": "string",
"format": "uuid",
"description": "Persistent codespace ID"
},
"path": {
"type": "string",
"minLength": 1,
"maxLength": 4096,
"description": "Repository-relative path"
},
"max_bytes": {
"anyOf": [
{
"type": "integer",
"minimum": 1,
"description": "Optional whole-file observation bound for download or image preview; no fixed owner preview quota"
},
{
"type": "integer",
"minimum": 1,
"maximum": 9007199254740991,
"description": "Optional caller-selected download bound; the workspace streams the file"
}
]
},
"head": {
"type": "string",
"minLength": 1,
"maxLength": 255,
"description": "Pushed branch in this codespace's approved repository"
},
"base": {
"type": "string",
"minLength": 1,
"maxLength": 255,
"description": "Existing target branch in the same approved repository"
},
"title": {
"type": "string",
"minLength": 1
},
"body": {
"type": "string"
},
"draft": {
"type": "boolean"
},
"pull_request_number": {
"type": "integer",
"exclusiveMinimum": 0
},
"refresh": {
"type": "boolean",
"description": "Re-read the approved repositories from the provider before answering"
},
"ref": {
"type": "string",
"minLength": 1,
"maxLength": 255
},
"devcontainer_path": {
"type": "string",
"minLength": 1,
"description": "GitHub-only path to an existing repository devcontainer configuration"
},
"generation": {
"type": "integer",
"exclusiveMinimum": 0
},
"provider_resource_name": {
"type": "string",
"pattern": "^[A-Za-z0-9][A-Za-z0-9-]*$",
"description": "Exact owned GitHub Codespace name; provider identity is verified before registration"
},
"confirm_delete": {
"type": "boolean",
"const": true,
"description": "Required explicit destructive confirmation"
},
"argv": {
"type": "array",
"items": {
"type": "string"
},
"minItems": 1
},
"session_end": {
"type": "boolean",
"description": "End the named session after this call, or alone with no command"
},
"cwd": {
"type": "string",
"maxLength": 4096
},
"session": {
"type": "string",
"pattern": "^[A-Za-z0-9][A-Za-z0-9_-]*$",
"description": "Continue the working directory and variables of this named session"
},
"session_start": {
"type": "boolean",
"description": "Open the named session instead of continuing it"
},
"env": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"propertyNames": {
"pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
},
"description": "Variables for this command, and for later commands in the same session"
},
"timeout_seconds": {
"type": "integer",
"minimum": 1
},
"max_stdout_bytes": {
"type": "integer",
"minimum": 1
},
"max_stderr_bytes": {
"type": "integer",
"minimum": 1
},
"stdin_text": {
"type": "string"
},
"stdin_file": {
"type": "object",
"properties": {
"file_id": {
"type": "string",
"maxLength": 512,
"pattern": "^(?:sediment:\\/\\/)?file_[A-Za-z0-9]+$"
},
"download_url": {
"type": "string",
"format": "uri"
},
"file_name": {
"type": "string",
"minLength": 1,
"maxLength": 255
},
"mime_type": {
"type": "string",
"maxLength": 127,
"pattern": "^[a-z0-9][a-z0-9!#$&^_.+-]*\\/[a-z0-9][a-z0-9!#$&^_.+-]*$"
},
"size_bytes": {
"type": "integer",
"minimum": 0
}
},
"required": [
"file_id",
"download_url"
],
"additionalProperties": false,
"description": "Native ChatGPT reference acquired by the workspace owner; pass it without base64. Source refusal before admission is confirmed, not a lost accepted mutation"
},
"script": {
"type": "string",
"minLength": 1
},
"query": {
"type": "string",
"minLength": 1
},
"mode": {
"type": "string",
"enum": [
"literal",
"regex"
]
},
"max_matches": {
"type": "integer",
"minimum": 1
},
"offset": {
"type": "integer",
"minimum": 0
},
"length": {
"type": "integer",
"minimum": 1
},
"stream": {
"type": "string",
"enum": [
"stdout",
"stderr"
]
},
"text": {
"type": "string"
},
"expected": {
"type": "object",
"properties": {
"exists": {
"type": "boolean",
"description": "Whether the target must already exist"
},
"size_bytes": {
"type": "integer",
"minimum": 0
},
"sha256": {
"type": "string",
"pattern": "^[a-f0-9]{64}$"
}
},
"required": [
"exists"
],
"additionalProperties": false
},
"files": {
"type": "array",
"items": {
"type": "object",
"properties": {
"path": {
"type": "string",
"minLength": 1,
"maxLength": 4096,
"description": "Repository-relative path"
},
"expected": {
"type": "object",
"properties": {
"exists": {
"type": "boolean",
"description": "Whether the target must already exist"
},
"size_bytes": {
"type": "integer",
"minimum": 0
},
"sha256": {
"type": "string",
"pattern": "^[a-f0-9]{64}$"
}
},
"required": [
"exists"
],
"additionalProperties": false
},
"edits": {
"type": "array",
"items": {
"type": "object",
"properties": {
"start": {
"type": "integer",
"minimum": 0
},
"end": {
"type": "integer",
"minimum": 0
},
"text": {
"type": "string"
}
},
"required": [
"start",
"end",
"text"
],
"additionalProperties": false
},
"minItems": 1
}
},
"required": [
"path",
"expected",
"edits"
],
"additionalProperties": false
},
"minItems": 1
},
"file": {
"type": "object",
"properties": {
"file_id": {
"type": "string",
"maxLength": 512,
"pattern": "^(?:sediment:\\/\\/)?file_[A-Za-z0-9]+$"
},
"download_url": {
"type": "string",
"format": "uri"
},
"file_name": {
"type": "string",
"minLength": 1,
"maxLength": 255
},
"mime_type": {
"type": "string",
"maxLength": 127,
"pattern": "^[a-z0-9][a-z0-9!#$&^_.+-]*\\/[a-z0-9][a-z0-9!#$&^_.+-]*$"
},
"size_bytes": {
"type": "integer",
"minimum": 0,
"maximum": 9007199254740991,
"description": "Declared binary file size; bytes are streamed to the workspace"
}
},
"required": [
"file_id",
"download_url"
],
"additionalProperties": false,
"description": "Native ChatGPT reference acquired by the workspace owner; pass it without base64. Source refusal before admission is confirmed, not a lost accepted mutation"
},
"file_name": {
"type": "string",
"minLength": 1,
"maxLength": 255
},
"mime_type": {
"type": "string",
"maxLength": 127,
"pattern": "^[a-z0-9][a-z0-9!#$&^_.+-]*\\/[a-z0-9][a-z0-9!#$&^_.+-]*$"
}
},
"required": [
"action"
],
"additionalProperties": false,
"$schema": "http://json-schema.org/draft-07/schema#"
}Result: Discovery, lifecycle state, owner operation receipts, workspace-owned command state and output, guarded file results, a private download link or PNG/JPEG preview. Lifecycle collection never resubmits or provisions an effect; accepted/unconfirmed receipts retain the original identity. An offline Local owner returns unavailable to MCP, without queuing; direct owner/guest CLI access to existing VMs remains subject to local grants and leases. New creation requires cloud route registration and initial Git authority. Choose a fresh ws1-<lowercase UUID> request_id for commands and file mutations; legacy UUIDs cannot execute. Collect a command through exec with the original request_id and no command fields. Background commands use codespace_process.
{
"action": "list"
}{
"action": "repositories"
}{
"action": "setup_help"
}{
"action": "local_devices"
}{
"action": "operation",
"device_id": "00000000-0000-4000-8000-000000000000",
"request_id": "ws1-11111111-1111-4111-8111-111111111111"
}{
"action": "repository_add",
"device_id": "00000000-0000-4000-8000-000000000000",
"repository_id": "123456",
"request_id": "11111111-1111-4111-8111-111111111111"
}{
"action": "repository_create",
"device_id": "00000000-0000-4000-8000-000000000000",
"request_id": "11111111-1111-4111-8111-111111111111",
"repository_name": "private-app",
"installation_id": "123456"
}{
"action": "preview_image",
"codespace_id": "00000000-0000-4000-8000-000000000000",
"path": "screenshots/app.png"
}{
"action": "create",
"repository_id": "123456",
"ref": "main",
"request_id": "ws1-11111111-1111-4111-8111-111111111111"
}{
"action": "adopt",
"provider_resource_name": "owned-space-123",
"request_id": "ws1-11111111-1111-4111-8111-111111111111"
}{
"action": "adopt",
"codespace_id": "00000000-0000-4000-8000-000000000000",
"generation": 2,
"device_id": "22222222-2222-4222-8222-222222222222",
"request_id": "ws1-11111111-1111-4111-8111-111111111111"
}{
"action": "create",
"repository_id": "local:00000000-0000-4000-8000-000000000000:22222222-2222-4222-8222-222222222222",
"ref": "main",
"request_id": "ws1-11111111-1111-4111-8111-111111111111"
}{
"action": "get",
"codespace_id": "00000000-0000-4000-8000-000000000000"
}{
"action": "pull_request_create",
"codespace_id": "00000000-0000-4000-8000-000000000000",
"request_id": "ws1-11111111-1111-4111-8111-111111111111",
"head": "feature/change",
"base": "main",
"title": "Change"
}{
"action": "pull_request_create",
"codespace_id": "00000000-0000-4000-8000-000000000000",
"request_id": "ws1-11111111-1111-4111-8111-111111111111"
}{
"action": "start",
"codespace_id": "00000000-0000-4000-8000-000000000000",
"generation": 3,
"request_id": "ws1-22222222-2222-4222-8222-222222222222"
}{
"action": "stop",
"codespace_id": "00000000-0000-4000-8000-000000000000",
"generation": 4,
"request_id": "ws1-33333333-3333-4333-8333-333333333333"
}{
"action": "exec",
"codespace_id": "00000000-0000-4000-8000-000000000000",
"request_id": "ws1-11111111-1111-4111-8111-111111111111",
"argv": [
"git",
"status",
"--short"
],
"cwd": ".",
"timeout_seconds": 60
}{
"action": "exec",
"codespace_id": "00000000-0000-4000-8000-000000000000",
"request_id": "ws1-11111111-1111-4111-8111-111111111111"
}{
"action": "read",
"codespace_id": "00000000-0000-4000-8000-000000000000",
"path": "src/index.ts",
"offset": 0,
"length": 65536
}{
"action": "delete",
"codespace_id": "00000000-0000-4000-8000-000000000000",
"generation": 5,
"request_id": "ws1-44444444-4444-4444-8444-444444444444",
"confirm_delete": true
}{
"action": "search",
"codespace_id": "00000000-0000-4000-8000-000000000000",
"path": ".",
"query": "TODO",
"mode": "literal"
}{
"action": "write",
"codespace_id": "00000000-0000-4000-8000-000000000000",
"request_id": "ws1-11111111-1111-4111-8111-111111111111",
"path": "notes.txt",
"text": "done\n",
"expected": {
"exists": false
}
}{
"action": "download",
"codespace_id": "00000000-0000-4000-8000-000000000000",
"path": "result.pdf",
"file_name": "result.pdf",
"mime_type": "application/pdf"
}codespace_process
Start, inspect, read and stop a background command in an owned codespace.
Actions: start, get, read, stop.
Input schema
{
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": [
"start",
"get",
"read",
"stop"
],
"description": "Start, inspect, read or stop one background command"
},
"codespace_id": {
"type": "string",
"format": "uuid",
"description": "Persistent codespace ID"
},
"request_id": {
"type": "string",
"pattern": "^ws1-[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$",
"description": "Choose before submission; after a lost reply inspect this identity without resubmitting the command"
},
"argv": {
"type": "array",
"items": {
"type": "string"
},
"minItems": 1
},
"session_end": {
"type": "boolean",
"description": "End the named session after this call, or alone with no command"
},
"cwd": {
"type": "string",
"maxLength": 4096
},
"session": {
"type": "string",
"pattern": "^[A-Za-z0-9][A-Za-z0-9_-]*$",
"description": "Continue the working directory and variables of this named session"
},
"session_start": {
"type": "boolean",
"description": "Open the named session instead of continuing it"
},
"env": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"propertyNames": {
"pattern": "^[A-Za-z_][A-Za-z0-9_]*$"
},
"description": "Variables for this command, and for later commands in the same session"
},
"timeout_seconds": {
"type": "integer",
"minimum": 1
},
"max_stdout_bytes": {
"type": "integer",
"minimum": 1
},
"max_stderr_bytes": {
"type": "integer",
"minimum": 1
},
"stdin_text": {
"type": "string"
},
"stdin_file": {
"type": "object",
"properties": {
"file_id": {
"type": "string",
"maxLength": 512,
"pattern": "^(?:sediment:\\/\\/)?file_[A-Za-z0-9]+$"
},
"download_url": {
"type": "string",
"format": "uri"
},
"file_name": {
"type": "string",
"minLength": 1,
"maxLength": 255
},
"mime_type": {
"type": "string",
"maxLength": 127,
"pattern": "^[a-z0-9][a-z0-9!#$&^_.+-]*\\/[a-z0-9][a-z0-9!#$&^_.+-]*$"
},
"size_bytes": {
"type": "integer",
"minimum": 0
}
},
"required": [
"file_id",
"download_url"
],
"additionalProperties": false,
"description": "Native ChatGPT reference acquired by the workspace owner; pass it without base64. Source refusal before admission is confirmed, not a lost accepted mutation"
},
"script": {
"type": "string",
"minLength": 1
},
"process_id": {
"type": "string",
"pattern": "^ws1-[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}$",
"description": "Background process ID returned by start"
},
"stream": {
"type": "string",
"enum": [
"stdout",
"stderr"
]
},
"offset": {
"type": "integer",
"minimum": 0
},
"length": {
"type": "integer",
"minimum": 1
}
},
"required": [
"action",
"codespace_id"
],
"additionalProperties": false,
"$schema": "http://json-schema.org/draft-07/schema#"
}Result: Workspace-owned process state with request_id/process_id and readable output ranges. Recover a lost start reply through get with the original identity; stop explicitly cancels that process. A caller-selected deadline is optional.
{
"action": "start",
"codespace_id": "00000000-0000-4000-8000-000000000000",
"request_id": "ws1-11111111-1111-4111-8111-111111111111",
"argv": [
"npm",
"run",
"dev"
]
}{
"action": "get",
"codespace_id": "00000000-0000-4000-8000-000000000000",
"process_id": "ws1-11111111-1111-4111-8111-111111111111"
}{
"action": "get",
"codespace_id": "00000000-0000-4000-8000-000000000000",
"request_id": "ws1-11111111-1111-4111-8111-111111111111"
}{
"action": "read",
"codespace_id": "00000000-0000-4000-8000-000000000000",
"process_id": "ws1-11111111-1111-4111-8111-111111111111",
"stream": "stdout",
"offset": 0,
"length": 65536
}{
"action": "stop",
"codespace_id": "00000000-0000-4000-8000-000000000000",
"process_id": "ws1-11111111-1111-4111-8111-111111111111"
}Behavioral guidance
Section titled “Behavioral guidance”The typed catalog defines what clients can send. The following notes describe authorization, state changes, and operational behavior that is not encoded in JSON Schema.
User communication
Section titled “User communication”communication delivers only to the authenticated user’s enabled channels. The server selects
providers and recipients; callers cannot supply a user, provider, destination, credential, local
path, remote URL, or arbitrary request header. send accepts a non-empty message and returns
a sanitized aggregate status for all configured channels. Text limits belong to the selected
provider; Telegram limits an ordinary message to 4096 characters.
A file owner is an enrolled workspace service or a paired controller on the user’s computer.
It retains the immutable source and original delivery receipt. Cloud Moira authorizes the channel
and streams its source to a fixed vendor transport without downloading native attachments or
keeping a temporary file copy. Ordinary text through send needs no file owner.
Before deliver-file, choose a fresh request_id in ws1-<lowercase UUID> form. Supply exactly
one source: a returned file.reference_id in referenceId, or the host’s native descriptor in
file. A native source needs a paired controller with an active registration. Select device_id
if several are registered, even when only one is online. Omit it only when exactly one is registered.
Availability is checked by the actual dispatch; an unavailable selected controller is not replaced.
A publication reference identifies its owner:
communication({ action: "deliver-file", request_id: "ws1-11111111-1111-4111-8111-111111111111", referenceId: "<file.reference_id>", message: "The requested recording", kind: "document",});For a native attachment, replace referenceId with file: nativeFile, using the exact descriptor
supplied by the host: file_id, download_url and any available file_name, mime_type,
size_bytes. Do not invent an ID or substitute an arbitrary URL. An optional channelId selects
one configured channel. Filename, MIME and size come from the source.
Retain the original ID and returned device_id or codespace_id. The owner receipt names the ID
requestId; tool input uses request_id. After an uncertain reply, collect without resending:
communication({ action: "operation", request_id: "ws1-11111111-1111-4111-8111-111111111111", device_id: "<device_id returned for this delivery>",});For a workspace source, use its codespace_id instead of device_id; never provide both.
Collection does not upload, render or send again. absent, accepted, completed and
unconfirmed describe the original receipt; a completed receipt can contain an uncertain error.
Absence or uncertainty does not authorize an automatic new delivery. For
COMMUNICATION_OWNER_UNAVAILABLE, connect the original owner and inspect the same request if
an earlier submission may have been admitted.
Publications contain complete immutable bytes and support repeated reads until expiry under current authority; later source edits do not change them. Publishing does not send a message, and delivery neither consumes the publication nor renews it. Telegram’s own image/document bounds and installed extensions’ declared binary transports apply without a generic cloud attachment quota.
Workflow discovery and execution
Section titled “Workflow discovery and execution”list returns only workflows accessible to the authenticated user. Search, visibility, ordering, and pagination filters are combined; total describes all matches, not only the returned page. Every response includes the effective offset and limit, returnedCount, and hasMore. When another page exists, pass nextOffset as the next request’s offset; the terminal page returns nextOffset: null.
All tools publish a root-object input schema so MCP clients can discover the complete catalog. The
public start schema therefore exposes action directly and lists the fields accepted by either
phase. Runtime validation still enforces the selected phase exactly: prepare requires workflowId
and parentExecutionId, while execute requires startAttemptId; fields belonging only to the other
phase and unknown fields are rejected as MCP errors. The codespace tool follows the same pattern:
one flat object carries action and the catalog’s fields, while dispatch validates the exact selected
action and applies its defaults. Collect an admitted command with codespace_id and its original
request_id, without submitting command fields again. An execution accepts at most one of
stdin_text and stdin_file. Unknown fields are MCP errors; fields belonging only to another action
return CODESPACE_REQUEST_INVALID. Caller-selected search/output windows bound observations;
image preview validates the complete container within optional max_bytes, and native download streams a complete file by path.
start({ action: "prepare" }) resolves and validates an authorized workflow, binds the workflow version and request options, and returns a Start attempt ID that expires after 15 minutes without creating an execution. parentExecutionId links a child to an existing parent; use "none" for a standalone execution. skipNotificationCheck records a policy to bypass only optional ordinary-notification preflight during execute. skipTelegramCheck remains a deprecated alias with the same behavior, and conflicting values are rejected.
start({ action: "execute", startAttemptId }) revalidates mutable workflow, parent, account, lock-delivery, and communication preconditions before consuming that exact reservation. A user-notification workflow with no configured channel returns channel-neutral Settings guidance; a legacy telegram-notification workflow returns Telegram setup guidance. A workflow containing a lock node always requires a valid Telegram bot token and chat ID for the current user; neither skip field bypasses trusted PIN delivery. A failed mutable precondition stores one replayable START_PRECONDITION_CHANGED receipt and creates no execution. Success returns the Process ID, first Step attempt ID, and first directive. A duplicate execute call replays the exact stored response and cannot create another execution; a separate preparation is an intentional separate start.
step requires both the Process ID and Step attempt ID from the current presentation, even when the node accepts empty input. The attempt identifies the presented step; it is not workflow input. Submitting the same attempt with the same input returns its durably stored result without applying the transition again. Concurrent identical calls coalesce behind one owner: duplicates either receive that owner’s stored receipt within the bounded wait or receive ATTEMPT_PROCESSING; the handler is not executed sequentially for each duplicate. A different input for a completed attempt, an attempt from another execution, and an older attempt after the process has advanced are rejected.
ATTEMPT_PROCESSING means another caller still owns the mutation; retry the same attempt and input. ATTEMPT_STALE is rejected before handler work: automatically read session({ action: "current_step", executionId }) and retry the intended submission once with the returned Step attempt ID. ATTEMPT_CONFLICT is rejected because that attempt is already bound to different input: automatically read current_step, discard the conflicting attempt, and continue from the returned directive and schema without replaying its old input. A step-level ATTEMPT_INVALID_OR_EXPIRED that explicitly directs the caller to current_step uses the same state-refresh recovery; discard the unavailable attempt. An unavailable start attempt does not provide this recovery. ATTEMPT_OUTCOME_UNKNOWN means an external effect may already have happened, so inspect the returned Process ID and do not automatically retry. An owner may retire a blocked execution with its current revision through session({ action: "cancel-execution", executionId, expectedRevision }). Each later paused presentation has a new attempt ID. A workflow may expose named teleport entries; teleporting and ordinary node input are mutually exclusive. If input contains the reserved execution_note field, Moira updates the execution note shown in execution lists. Tool failures remain failures and are not rendered as successful steps.
session is scoped to executions owned by the current user. It can inspect the current user, list or inspect executions, repeat the current step without advancing it, diagnose why a paused run cannot continue, update an execution note or parent, manage caller-owned reminders, inspect or update declared runtime variables subject to workflow policy, read progress or request a one-use progress-image download, raise the agent’s question to the user, and deliver a paused materialization node’s files into the response when this host cannot run the presented command. await-user is for the moment an agent cannot continue without the user: it records question (up to 500 characters) and optional options (up to four choices) on the running execution, bound to the step the run stands on, so the run is shown as waiting for the user with that question, and the user is notified through their notification channels with the question, its choices and a link to the run (a new question sooner than ten minutes after the previous notification is held until then); the user answers the agent in its chat, not in Moira. A new call replaces the question and resolve: true clears it. The agent’s next step (accepted or refused), a variable it sets with set-variable, recovery, cancellation and completion clear it too, and so does the run leaving that step; a person’s edit on the run page does not. The call does not change the step revision, so the presented Step attempt stays valid, and execution_context returns the open question as awaitingUser. After an interruption, current_step returns the authoritative current presentation and its Step attempt ID. If a paused execution has no persisted Step attempt, current_step creates a bound presentation without executing or advancing the node. It also repairs a presented attempt whose only stale binding is the execution revision. A live attempt bound to another node, or to a continuation surface the current definition no longer has, returns CURRENT_PRESENTATION_STALE; its old ID is not recommended or replayable, and the error points at diagnose. diagnose reports whether a paused run can still continue against the workflow as it stands and names every reason it cannot — the node it is on and whether that node still exists, which facts of its continuation surface changed, which references the presented step cannot resolve from the context, a recorded execution error, and an attempt that is foreign, unbound or not presented. Each cause says whether it blocks: a blocking cause means the run cannot reach its next step without repair, while a non-blocking one — a missing or revision-stale presentation, an attempt another caller is executing, an unresolved reference, a recorded error — explains what you are seeing while the run stays usable. continuable is true when no cause blocks. The action changes nothing, and a healthy run reports itself continuable with no causes. recover then returns such a run to a step it can resume from: give it nodeId for a node a run can wait on — an agent-directive, teleport, materialize, lock or subgraph node — and variableValues for what that step needs, and it moves the run there, writes those values into the context and presents the node afresh, so the next call is an ordinary step(). It is refused for a run that is already over: a completed or cancelled run stays finished, since recovery repairs a run that is trying to continue and cannot, and diagnose still explains why such a run cannot continue. Among runs that are still going, it is refused unless diagnose reports at least one blocking cause — a healthy run is refused on purpose — and every refusal leaves the run untouched and names what to call next. Both outcomes are audited, the refusals as well as the repairs. The continuation surface is what the paused step still depends on: everything that node declares except how it is displayed (including a humanGate mark, which only changes who the run is shown as waiting for), plus the registry entries for the global variables it declares as inputs. An updated workflow therefore leaves a paused run usable unless the change reaches it — a new version, new tags, a rewritten description, an edit to another node, or a purely cosmetic change to the paused node all leave it usable.
For an agent-directive step whose expression reads a saved top-level variable absent from the execution, diagnose reports missing_expression_variables as blocking when Moira can establish that no answer field accepted by both the input schema and the node’s top-level output declaration can supply the value, and the node has no authored error route. An open input schema alone does not make an undeclared answer field usable. A declared output field also cannot supply the value if the input schema forbids it, for example with maxProperties: 0, a false property schema, or a prohibition inside allOf. For schema constraints Moira cannot establish as a prohibition, the field remains answer-capable and an invalid answer must be corrected normally. A failed step caused by that missing read and current_step point the agent to diagnose and recover. Supply the named values through recover with the current nodeId; declared variables must match their registry schemas. Recovery refuses missing or invalid values without changing the execution. A successful recovery presents the same node with a fresh Step attempt ID; submit the step’s ordinary answer to continue. A malformed answer or an expression error caused by answer data remains retryable, even when diagnosis also names a later missing saved value; correct the current answer error first. An authored error route still runs as defined. A historical recorded error alone does not make a healthy run recoverable.
During ordinary progression, an original step advances the execution revision when it persists workflow state; stop-execution also advances it once when ending the run. Parent, reminder, note, and runtime-variable mutations do not advance it or invalidate the current Step attempt. Parent, reminder, and runtime-variable writes require both expectedRevision and the corresponding opaque revision returned by execution_context, reminders, variables, or the previous mutation (expectedParentRevision, expectedRemindersRevision, or expectedContextRevision). These target revisions prevent an older metadata snapshot from overwriting a newer one within the same step generation. Parent changes accept "none" to detach, require same-owner running executions, and reject ancestry cycles. Reminders do not change the workflow plan or grant authority; active reminders are returned when an execution completes. Runtime variable writes are default-deny, must satisfy the variable schema, and never advance the graph. A write whose revision is no longer current is rejected before anything is written; its AGENT INSTRUCTIONS tell the caller to re-read that state and retry with the current revisions, without involving the user.
For a paused materialize node, current_step returns a five-minute archive command rather than
file bodies. Run it as issued, then complete the step with null or {} after extraction succeeds.
The first materialize archive request resolves authorized text and pins the selected paired
controller’s complete identity plus an original publication request ID. Repeating the same
five-minute grant collects that publication without resolving sources, rendering or submitting again.
Its bytes remain immutable if the workflow definition changes. An absent or unconfirmed original
returns HTTP 409 with COMMUNICATION_OUTCOME_UNCONFIRMED and request_id; collection never replays.
A completed owner error returns HTTP 422, and an unavailable controller returns HTTP 503 with
COMMUNICATION_OWNER_UNAVAILABLE. Obtain a fresh current-step presentation only for a separate
explicit retry. Current user/node/context checks remain required. The materialize text fallback
requires no file owner and keeps its separate 256 KiB observation budget.
update-task-title establishes or renames the owner’s active task independently of arbitrary notes.
Read execution_context and pass its revision and metadataRevisions.taskIdentity as
expectedRevision and expectedTaskIdentityRevision. The normalized nonempty title is bounded to
500 JavaScript string code units; Unicode control/formatting characters are rejected before trimming.
Both guards apply even to an identical normalized name, whose successful no-op changes no activity
or events. Naming preserves the step attempt and other metadata. Completed/stopped runs refuse it.
See execution task naming for the call and fallback.
Progress reads without an authored process return source: "metadata", not invented blocks or an
error; authored projections retain source: "trace".
Recovery to a materialize target keeps that node paused for delivery. Its grant resolves current registry defaults; context changes alone do not refresh caller files. Execute the delivery before completing the node.
Progress-image grants require authored progress and bind the execution owner, workflow version,
step revision, context revision, independent task identity revision and normalized render options.
A rename, including a same-clock change back to the original text, invalidates a prior grant.
Stale redemption does not successfully consume it; obtain a fresh grant, also when its identity
binding is absent. Failed rendering or HTTP delivery releases reservation; successful response
completion consumes the grant once.
Rendering requires a paired controller with an active registration. Supply device_id when several
are registered, even when only one is online; omission requires exactly one registered owner.
Actual dispatch checks availability without substituting another controller. COMMUNICATION_OWNER_UNAVAILABLE is an
operational HTTP 503 from mint/public read and a coded MCP failure. Connect that controller rather
than recreating a VM. The one-use progress URL is distinct from the repeatable owner publication;
an error response finishing does not consume the progress grant. Ordinary progress reads and text
notifications need no file owner.
Stopping a run
Section titled “Stopping a run”Use session({ action: "stop-execution", executionId, expectedRevision, reason }) when the user
cancels a running workflow or wants to continue outside it. Use the current execution_context
response’s revision as expectedRevision. The caller must own the execution, and reason must contain 1–500
characters after trimming. The operation permanently ends the run, records stopReason, clears
its waits and advances its revision once; it does not report successful task completion.
Pending notifications are superseded, but a notification delivery already begun may finish.
An execution operation still in progress, including recovery or a run-page answer, prevents stopping; wait for it to
finish and reload the context. A stale revision or an already finished run is refused without a
change. Repeating the successful stop with the original revision and the same trimmed reason
returns the same result without another write. execution_context and executions expose
stopReason; the overview displays these runs as Stopped, hidden in its default active view
even when they are children. Select Stopped or All to find them. An active child of a
stopped parent remains active and is shown independently with its parent link.
cancel-execution remains the separate operation for retiring a blocked start.
Workflow definitions and reconciliation
Section titled “Workflow definitions and reconciliation”manage resolves workflow identities only within the caller’s access. Create and edit validate the resulting definition before persistence. An existing identifier is overwritten only when explicitly requested; edit rejects empty changes, missing or duplicate nodes, and invalid resulting graphs.
The get action returns the workflow’s complete authored metadata, variable registry, runtime policy, progress projection, reminder, and structural facts. includeNodes: false omits only node definitions, while includeValidation: false omits only validation results. Use list-nodes for compact discovery, get-nodes for a selected batch, analyze-variables for definition-wide variable usage, and set-visibility to change an owned workflow between public and private.
Node search uses bounded RE2-compatible expressions when the query contains regular-expression syntax and falls back to case-insensitive literal search for malformed or unsupported patterns. Cloning rejects a missing source or duplicate target identifier. Moving changes array order without rewriting authored connections and rejects a result that no longer validates.
Workflow variable operations act on the definition’s declared variableRegistry. Sharing and invite creation, listing, and revocation require owner authority. Failed mutations return an MCP error without partially applying the requested change.
reconciliation handles conflicts among the previous bundled workflow, the current database workflow, and the incoming image workflow. Status is visible to agents but exposes full candidate states only to administrators; candidate retrieval and resolution are administrator-only. Resolve conflicts semantically through Workflow Management Flow—do not mechanically merge graph JSON.
lock accepts only executions owned by the caller. Status returns the active lock, list returns public lock history, and unlock validates the supplied PIN against the active record. MCP lock creation requires a running execution with no active lock and valid Telegram settings for the current user. It sends the generated PIN only to that configured chat and returns non-secret lock metadata after delivery succeeds. Missing or invalid settings and send failure leave no usable active lock from that attempt; MCP responses and errors never include the PIN.
The separately authenticated Web lock-creation route presents its one-time PIN to the human execution owner. That human response is not available through MCP or workflow-node output.
Settings and notes
Section titled “Settings and notes”settings reads one exact key, one category, or the complete accessible set. Do not combine key and category in a get request. Definitions include database-backed settings and settings declared by installed extension manifests. Encrypted values are always masked: database-backed values use [encrypted], while extension values use a bullet mask that retains only the last four characters. Admin-only values and definitions are hidden from non-admin users. Setting a value requires an existing definition and enforces administrative restrictions, the declared type, optional JSON Schema validation, the declared minimum and maximum of a built-in number setting, encryption, and Telegram webhook registration when a bot token is saved. A structured JSON value must round-trip without values being omitted or transformed. Extension defaults must satisfy the same type and schema before the manifest is accepted. Listing returns the currently available definitions rather than stored values; removing an extension hides its definitions but keeps its per-user values for a later reinstall.
notes stores user-isolated, versioned text. Reads may select a retained version; deletion is soft. Save enforces the configured per-note size, total storage, retained-version, key, and tag limits. Administrators may change the active storage limits.
Playbooks
Section titled “Playbooks”playbooks keeps named, reusable behaviour text — a review standard, a tone of voice, a definition
of done — in one place instead of inside the workflows that rely on it, so the same text can be
edited once and read by an agent wherever it is needed.
A name uses lower-case letters, digits and hyphens and is unique inside one account; writing under a
name another user also has creates your own playbook rather than changing theirs. Every save writes a revision, restore writes a new revision
carrying the older text, and compare reports the difference between two of them line by line.
Revisions are kept up to the configured retention, and content is bounded per playbook.
visibility publishes a playbook or makes it private again. A published playbook is readable by any
signed-in user who names its owner and changeable only by its owner: publishing shares the text, not
control over it. Reading somebody else’s published playbook means naming them through owner, by handle or by user
id.
Hosted artifacts and workflow files
Section titled “Hosted artifacts and workflow files”artifacts manages public static HTML outputs with per-user count and storage quotas, per-file size limits, and expiry. Upload may associate an artifact with an execution; update and delete require ownership. The token operation creates a one-use HTTP upload grant for external upload clients. Administrators may change active quotas globally or per user.
token is reserved for file-based workflow import and export. Upload grants accept a workflow JSON file as multipart form field workflow; download grants require an authorized workflow. Both are short-lived. Use manage for ordinary workflow inspection and mutation.
For an upload grant returned by token, submit the selected file to its uploadUrl:
curl -X POST "${uploadUrl}" -F "workflow=@your-workflow.json"Development codespaces
Section titled “Development codespaces”codespace operates an owned persistent GitHub Codespace or Local VM. Each Local codespace has
its own VM, and a repository may have several independent environments. Reuse its codespace_id
across clients; collaboration uses repository branches. The typed catalog above lists the supported
actions and their exact inputs.
Both providers install the same workspace service with its own Node.js and ripgrep runtime.
Commands, named sessions, guarded file operations and durable results belong to that service.
The direct moira-workspace CLI uses its private Unix socket. Remote MCP calls reach the same
owner through authenticated streaming routing; cloud Moira stores neither command queues nor
command/file results. Provider bootstrap establishes the service before ordinary work is admitted.
Git and pull requests
Section titled “Git and pull requests”Use ordinary git fetch/git push in the workspace. A trusted owner broker executes fixed
HTTPS Git and typed PR requests directly; cloud Moira issues a child credential limited to
the approved repository/action. Original OAuth/refresh credentials stay in its vault, and
tools receive no GitHub token. The broker’s same-UID trust boundary is not an OS sandbox.
For pull_request_create, choose a fresh ws1-<lowercase UUID> request_id before
submission. After an unconfirmed result, collect with only codespace_id and that original
request_id, then use pull_request_find for the pushed head/base before considering another
create. Collection never creates a PR; get/find are reads. An unknown create is an error
carrying the original PR ID and any security_request_id. The latter identifies credential
issuance/disposal separately from the PR effect. Custody or disposal pending remains
uncertain; collecting that security identity cannot mint another token or replay Git.
The direct CLI supports pull-request-create --request-id ID pr.json, collect-only
pull-request-create --request-id ID, pull-request-get NUMBER and
pull-request-find HEAD BASE on the same owner.
Access and lifecycle
Section titled “Access and lifecycle”GitHub authorization happens on the Moira website. Install the Moira GitHub App and grant the
repositories the agent may use; accept permission updates on GitHub. setup_help returns the
current missing condition, provider instruction and applicable configured links without provisioning
anything. repositories discovers approved targets and local_devices discovers owned computers.
Local pairing, repository admission and finite work permission remain owner-controlled and do not
require the GitHub Codespaces provider to be enabled.
For both providers, create, start, stop, delete and GitHub adopt require a caller-chosen request_id in
ws1-<lowercase UUID> form. Start/stop/delete also require the resource’s observed generation;
the owner refuses a stale generation with CODESPACE_GENERATION_CONFLICT, rather than repairing
authorization or using a newer value on the caller’s behalf. Get/list expose that generation and
pending_request_ids from the live owner. Collect the original receipt with
codespace({ action: "operation", device_id, request_id }), even if create returned no ID.
absent, accepted, completed and unconfirmed distinguish original outcomes; collection
never repeats the mutation. Neither absence nor a newer snapshot permits automatic replay.
An unavailable owner supplies no current policy or grants and accepts no queued offline mutations.
Local resource summaries use the live owner’s machine, current lifecycle generation and state;
route registration alone cannot supply them. The public machine field is nullable, including
after confirmed deletion. Without an owner resource observation, get/list refuse as
CODESPACE_PROVIDER_UNAVAILABLE instead of inventing a profile or generation. If the owner journal
retains pending creation work, CODESPACE_LOCAL_CREATION_UNKNOWN carries the original request_id,
device_id and codespace_id for collection even before a summary is available. A completed receipt
with an uncertain error remains uncertain on explicit repetition; collection never creates another VM.
On the computer, the host CLI uses the running private controller for create, start, stop,
remove --confirm and collect. Fresh creation needs live cloud route registration and initial
Git authority; admitted VMs can be managed offline under applicable current owner rights.
Starting requires the finite work lease; owner-confirmed cleanup does not renew it. Ordinary
commands/files use the guest moira-workspace CLI.
GitHub create/adopt runs at a paired controller with an active registration; choose device_id
when several are registered, even when only one is online. Actual dispatch checks that selected
controller’s availability without substituting another. adopt accepts a registered codespace_id with its observed generation, or an owned
provider_resource_name for initial admission. The controller uses trusted gh/SSH and the shipped
payload in place, preserving the disk and original operation journal. Ordinary file calls cannot
start or SSH into the environment. Local has no cloud aggregate quota; its current rights and
physical limits belong to the owner.
create, get, start, stop and delete address the selected provider. GitHub create/start may
return a pending resource; inspect its original receipt and current guest connection without replay. Ordinary workspace
dispatch requires a usable guest. Stop preserves repository data, and delete requires confirm_delete: true and
confirmed absence. Local agent deletion also requires its repository permission and current work
authority. The owner can instead confirm cleanup of that exact environment in Settings →
Development → Local computers, with paired local web control, without granting agent deletion
or renewing an expired work lease.
Unknown or foreign resources disclose no other owner’s data. Ordinary resource calls return
CODESPACE_NOT_FOUND; process authority refusal uses CODESPACE_AUTHORIZATION_REQUIRED.
An incomplete GitHub provider refresh reports a warning rather than erasing saved entries.
codespace({ action: "list", refresh: true }) requests a fresh approved repository/resource observation. Repository
identity follows the provider ID, so a rename or checked-out branch change does not replace the
environment. Creation still requires a valid branch or commit reference.
GitHub creation supports personal-account billing. Organization-billed creation is refused with
CODESPACE_BILLING_UNSUPPORTED. Settings shows current resources and separately available current-month GitHub billing. Local has no cloud billing limits;
its resource and policy observations come from the owner.
Billing may be unavailable without Plan: read or while its API is unavailable; that does not grant
or revoke resource access. Physical Local storage, CPU/RAM admission and finite work leases remain
effective.
GitHub idle preferences apply when Moira creates a new Codespace:
codespaces.auto_stop_enabled defaults to true and codespaces.idle_timeout_minutes defaults to
30 within GitHub’s 5–240-minute range. Disabling the preference requests 240 minutes, not unlimited
running. Existing environments retain their provider parameters. GitHub detects editor, browser and
terminal activity; a silent background command can be stopped by its native idle policy or lifetime
limit. Local environments follow their computer owner’s policy. Starting a stopped environment requires explicit start; stopping does not preserve a live process.
Commands, collection and sessions
Section titled “Commands, collection and sessions”Choose a fresh request_id in ws1-<lowercase UUID> form before exec, process start,
write, apply_patch or upload. Repository admission has its separate UUID identity.
Historical plain operation UUIDs are archival and cannot address new work; adding a prefix to an
old identifier does not recover its operation. Retain the actual identity you chose before submission.
exec accepts argv as arguments without shell interpolation, or script inside a named
session. It observes briefly and can return starting or running before completion. Collect a
lost reply with exec containing only codespace_id and the original request_id; do not start
a second command. A changed command or input under the same admitted identity is refused.
timeout_seconds sets an execution deadline only when explicitly supplied. Reply windows
max_stdout_bytes and max_stderr_bytes bound returned text; they neither stop the command nor
limit its retained output. Read later output with read, the original request_id, stream,
offset and length. Command observations retain their actual exitCode and stream sizes.
codespace_process exposes start/get/read/stop for a long-lived command. Start uses the same
command identity and fields; retain its process_id for collection and explicit cancellation.
A lost connection closes observation, not the admitted command. unknown means its effect is
unconfirmed, not that it never ran. not_started requires evidence that execution was prevented;
a cancellation request is not proof of completed cancellation. Inspect the same identity and
affected files before deciding what new work is needed.
Open a named session with session_start: true; subsequent commands use the same session.
The session carries its working directory and environment, including changes left by a shell
script. session_end: true closes it. Sessions have no inherited slot or context-size quota;
actual process/environment and storage failures remain observable. Session state is local to the
guest life, so reopen it after an environment restart. Retained terminal results can remain on the
persistent disk; a missing or uncertain result is never automatically replayed.
Supply at most one stdin form: stdin_text or a native stdin_file reference. Native bytes stream
to the service without base64 in the conversation or a cloud command-input spool. Current account,
repository, resource generation and Local device/work authority are checked independently of the
command journal. Independent commands and reads can proceed while another result is uncertain;
guarded mutations coordinate inside the guest.
Source preparation is distinct from execution: repository authority is checked before native acquisition, and the final locked session/repository gate can still refuse the prepared command. Collect its original result; prepared bytes alone do not prove execution or authorize a retry.
Reading, editing and publishing files
Section titled “Reading, editing and publishing files”Paths are repository-relative. stat returns file metadata and its version; it is useful when an
edit needs a size/hash precondition, and is not a required step before downloading.
search supports literal or regex search with caller-selected result windows
max_matches and max_bytes; those windows do not limit the total file bytes scanned.
read returns the requested UTF-8 range with offset and total_bytes, defaulting to a 64 KiB
window. Binary text ranges return CODESPACE_BINARY_READ_REQUIRES_DOWNLOAD.
write and apply_patch require a stable workspace request identity and expected existence,
with optional size_bytes and whole-file sha256. Patches use ordered byte-offset edits.
The service stages and commits guarded changes, refuses stale preconditions, traversal, unsafe
links and substituted ownership, and retains uncertainty rather than overwriting foreign data
during interrupted recovery. There is no inherited 4 MiB code-file ceiling.
upload streams a native attachment to its guarded repository target. download reads a complete
file by path and requires file_name and mime_type. It publishes an MCP resource_link plus
file.reference_id, size, digest and expiry. Optional max_bytes refuses an oversized complete
file with CODESPACE_DOWNLOAD_BOUND_EXCEEDED; it never publishes a prefix as the file.
A complete empty file is valid. Publication does not send a message: explicitly use
communication({ action: "deliver-file", request_id, referenceId, message, kind }) for an owned ready file.
Its immutable owner publication supports repeated reads until expiry; delivery does not renew it.
preview_image returns complete structurally checked PNG/JPEG content; optional max_bytes
sets the caller’s whole-image bound without generic byte or dimension ceilings.
Use complete download for the original binary. Workspace command/file streams have no inherited
aggregate transfer, output, session or implicit execution-duration quota. Physical storage,
filesystem confinement, scoped authority, provider policies and caller-selected observation bounds
still apply. The MCP HTTP JSON body guard is a separate metadata boundary; native binary streams
and the direct guest CLI do not encode their bytes in that JSON body.
Direct guest terminal access
Section titled “Direct guest terminal access”The installed CLI uses the same service and identities as remote calls:
moira-workspace exec --request-id ws1-11111111-1111-4111-8111-111111111111 -- npm testmoira-workspace status ws1-11111111-1111-4111-8111-111111111111moira-workspace output ws1-11111111-1111-4111-8111-111111111111 stdoutmoira-workspace upload --request-id ws1-22222222-2222-4222-8222-222222222222 assets/data.bin /tmp/data.binmoira-workspace download assets/data.bin > /tmp/data-copy.binChoose a fresh identity for each intended mutation; the literals above illustrate the format.
The command shortcuts generate and print one before accepting input or starting work when their
optional --request-id is omitted.
upload/ write default to an absent target unless an explicit expected JSON guard is supplied.
CLI download writes repository bytes to standard output; MCP download is the separate publication
step that supplies a private reference for communication. Use CLI status/output after a lost reply.
Use moira-workspace action request.json (or action - for JSON on stdin) for the full
workspace action contract, including scripts, sessions, cwd, environment, explicit timeouts,
native descriptors and observation windows. For example, request.json can contain:
{ "action": "exec", "request": { "request_id": "ws1-33333333-3333-4333-8333-333333333333", "session": "checks", "session_start": true, "cwd": ".", "env": { "CHECK_MODE": "local" }, "script": "printf '%s\\n' \"$CHECK_MODE\"", "timeout_seconds": 30 }}The JSON adapter preserves the supplied request_id or process_id; it does not generate one.
Collect with an exec action containing only the original request_id, or use status/output.
moira-workspace communication request.json (or communication -) submits the owner communication
JSON with its original camelCase requestId; status collects that original receipt without
another publication or send. Keep signed native descriptors in the JSON file or stdin, never argv.
Installation through the common image or Feature is described in
self-hosting.
Runtime help
Section titled “Runtime help”help discovers file-backed topics from the installed MCP help corpus and lists the direct tools topic alongside them. Call it without a topic to see the current topic names and aliases. Multiple requested topics are returned together with separators. The tools topic and its tool alias render the same typed catalog shown above directly from the registry.
Related
Section titled “Related”- MCP Agent Guide — How to use MCP tools
- Troubleshooting — Common issues