Skip to content

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.

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"
        },
        "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/conditions/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
                  }
                },
                "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
                  }
                },
                "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": "ui.theme"
}
{
  "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 a message to the current user or mint a one-time authenticated attachment upload grant.

Actions: send, attachment-token.

Input schema

{
  "type": "object",
  "properties": {
    "action": {
      "type": "string",
      "enum": [
        "send",
        "attachment-token"
      ]
    },
    "message": {
      "type": "string",
      "minLength": 1,
      "maxLength": 4096
    },
    "format": {
      "type": "string",
      "enum": [
        "plain",
        "markdown",
        "html"
      ]
    },
    "silent": {
      "type": "boolean"
    },
    "kind": {
      "type": "string",
      "enum": [
        "image",
        "document"
      ]
    },
    "filename": {
      "type": "string",
      "minLength": 1,
      "maxLength": 255
    },
    "mimeType": {
      "type": "string",
      "maxLength": 127,
      "pattern": "^[a-z0-9][a-z0-9!#$&^_.+-]*\\/[a-z0-9][a-z0-9!#$&^_.+-]*$"
    },
    "sizeBytes": {
      "type": "integer",
      "minimum": 1,
      "maximum": 20971520
    }
  },
  "required": [
    "action",
    "message"
  ],
  "additionalProperties": false,
  "$schema": "http://json-schema.org/draft-07/schema#"
}

Result: A channel-safe delivery summary or a short-lived upload grant and endpoint.

{
  "action": "send",
  "message": "The report is ready."
}
{
  "action": "attachment-token",
  "message": "Report",
  "kind": "document",
  "filename": "report.pdf",
  "mimeType": "application/pdf",
  "sizeBytes": 12000
}

session

Inspect and update execution-scoped state.

Actions: user, executions, execution_context, current_step, diagnose, recover, cancel-execution, update-note, set-parent, add-reminder, reminders, update-reminder, remove-reminder, variables, set-variable, progress, progress-image-token, materialize.

Input schema

{
  "type": "object",
  "properties": {
    "action": {
      "type": "string",
      "enum": [
        "user",
        "executions",
        "execution_context",
        "current_step",
        "diagnose",
        "recover",
        "cancel-execution",
        "update-note",
        "set-parent",
        "add-reminder",
        "reminders",
        "update-reminder",
        "remove-reminder",
        "variables",
        "set-variable",
        "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)"
    },
    "parentExecutionId": {
      "type": "string",
      "description": "Parent execution UUID or \"none\" for set-parent"
    },
    "expectedRevision": {
      "type": "integer",
      "minimum": 0,
      "description": "Expected workflow-step revision"
    },
    "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": {},
    "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"
}

workspace

Work in a persistent cloud workspace: lifecycle, commands and files, by action.

Actions: list, create, get, start, stop, delete, exec, stat, search, read, write, apply_patch, upload, download.

Input schema

{
  "type": "object",
  "properties": {
    "action": {
      "type": "string",
      "enum": [
        "list",
        "create",
        "get",
        "start",
        "stop",
        "delete",
        "exec",
        "stat",
        "search",
        "read",
        "write",
        "apply_patch",
        "upload",
        "download"
      ],
      "description": "Workspace operation to perform"
    },
    "repository_id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 255
    },
    "ref": {
      "type": "string",
      "minLength": 1,
      "maxLength": 255
    },
    "workspace_id": {
      "type": "string",
      "format": "uuid",
      "description": "Persistent workspace ID"
    },
    "expected_generation": {
      "type": "integer",
      "minimum": 1
    },
    "confirm_delete": {
      "type": "boolean",
      "const": true,
      "description": "Required explicit destructive confirmation"
    },
    "argv": {
      "type": "array",
      "items": {
        "type": "string",
        "minLength": 1,
        "maxLength": 16384
      },
      "minItems": 1,
      "maxItems": 128
    },
    "script": {
      "type": "string",
      "minLength": 1,
      "maxLength": 65536,
      "description": "Shell script run inside a session; what it leaves behind is carried forward"
    },
    "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_-]{0,63}$",
      "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",
        "maxLength": 4096
      },
      "propertyNames": {
        "pattern": "^[A-Za-z_][A-Za-z0-9_]{0,127}$"
      },
      "description": "Variables for this command, and for later commands in the same session"
    },
    "timeout_seconds": {
      "type": "integer",
      "minimum": 1,
      "maximum": 86400
    },
    "background": {
      "type": "boolean",
      "description": "Keep the command running past this request; collect it later by operation_id"
    },
    "max_stdout_bytes": {
      "type": "integer",
      "minimum": 1,
      "maximum": 8388608
    },
    "max_stderr_bytes": {
      "type": "integer",
      "minimum": 1,
      "maximum": 8388608
    },
    "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,
          "maximum": 4194304
        }
      },
      "required": [
        "file_id",
        "download_url"
      ],
      "additionalProperties": false,
      "description": "Native ChatGPT file reference; pass the attachment reference without base64"
    },
    "operation_id": {
      "anyOf": [
        {
          "type": "string",
          "format": "uuid",
          "description": "Pending operation ID returned by this tool"
        },
        {
          "type": "string",
          "format": "uuid",
          "description": "Command operation whose retained output is read"
        }
      ]
    },
    "cancel": {
      "type": "boolean"
    },
    "path": {
      "type": "string",
      "minLength": 1,
      "maxLength": 4096,
      "description": "Repository-relative path"
    },
    "query": {
      "type": "string",
      "minLength": 1,
      "maxLength": 4096
    },
    "mode": {
      "type": "string",
      "enum": [
        "literal",
        "regex"
      ]
    },
    "max_matches": {
      "type": "integer",
      "minimum": 1,
      "maximum": 1000
    },
    "max_bytes": {
      "anyOf": [
        {
          "type": "integer",
          "minimum": 1,
          "maximum": 1048576
        },
        {
          "type": "integer",
          "minimum": 1,
          "maximum": 4194304
        }
      ]
    },
    "offset": {
      "type": "integer",
      "minimum": 0
    },
    "length": {
      "type": "integer",
      "minimum": 1,
      "maximum": 4194304
    },
    "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,
            "maxItems": 4096
          }
        },
        "required": [
          "path",
          "expected",
          "edits"
        ],
        "additionalProperties": false
      },
      "minItems": 1,
      "maxItems": 64
    },
    "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": 4194304
        }
      },
      "required": [
        "file_id",
        "download_url"
      ],
      "additionalProperties": false,
      "description": "Native ChatGPT file reference; pass the attachment reference without base64"
    },
    "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: The result the requested action produces, sanitized: workspace state, durable operation state with bounded output, file versions, or a one-use native download link.

{
  "action": "list"
}
{
  "action": "create",
  "repository_id": "123456",
  "ref": "main"
}
{
  "action": "get",
  "workspace_id": "00000000-0000-4000-8000-000000000000"
}
{
  "action": "exec",
  "workspace_id": "00000000-0000-4000-8000-000000000000",
  "argv": [
    "git",
    "status",
    "--short"
  ],
  "cwd": ".",
  "timeout_seconds": 60
}
{
  "action": "read",
  "workspace_id": "00000000-0000-4000-8000-000000000000",
  "path": "src/index.ts",
  "offset": 0,
  "length": 65536
}
{
  "action": "delete",
  "workspace_id": "00000000-0000-4000-8000-000000000000",
  "expected_generation": 3,
  "confirm_delete": true
}
{
  "action": "search",
  "workspace_id": "00000000-0000-4000-8000-000000000000",
  "path": ".",
  "query": "TODO",
  "mode": "literal"
}
{
  "action": "write",
  "workspace_id": "00000000-0000-4000-8000-000000000000",
  "path": "notes.txt",
  "text": "done\n",
  "expected": {
    "exists": false
  }
}
{
  "action": "download",
  "workspace_id": "00000000-0000-4000-8000-000000000000",
  "path": "result.pdf",
  "max_bytes": 4194304,
  "file_name": "result.pdf",
  "mime_type": "application/pdf"
}
{
  "action": "download",
  "workspace_id": "00000000-0000-4000-8000-000000000000",
  "operation_id": "11111111-1111-4111-8111-111111111111",
  "file_name": "result.pdf",
  "mime_type": "application/pdf"
}

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.

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 of at most 4096 characters and returns a sanitized aggregate status for all configured channels.

For an image or document, call attachment-token with the message, attachment kind, filename, MIME type, and exact byte size. The returned grant expires after five minutes and can authorize at most one provider attempt. Keep the grant out of the URL and send the bytes with an OAuth or persistent MCP Bearer credential belonging to the user who minted it:

Terminal window
curl --request POST "$uploadUrl" \
--header "Authorization: Bearer $MOIRA_MCP_TOKEN" \
--header "X-Moira-Communication-Grant: $grant" \
--header "Content-Type: application/pdf" \
--header "Content-Length: $(wc -c < report.pdf)" \
--data-binary @report.pdf

The declared size must equal both Content-Length and the received byte count. Each attachment is limited to 20 MiB; images accept PNG or JPEG and documents reject image MIME types. Before provider delivery begins, a failed MIME, size, image-signature, or in-flight admission check releases the grant for another corrected request until expiry. After any provider attempt, success or failure is terminal and replay returns the same non-specific invalid-grant response. Each user may have ten live grants and two simultaneous upload buffers totalling at most 40 MiB; the installation accepts one thousand live grants. Expired and completed grants do not consume issuance capacity.

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 workspace tool follows the same pattern at a larger scale: one flat object carrying action plus every action’s fields, of which only action is required, while dispatch enforces the exact form of the action requested (a new request, or a resume carrying only workspace_id and operation_id; exactly one of stdin_text or stdin_file for exec). A field that belongs to no action is rejected as an MCP error, as before; a field that belongs to a different action is rejected at dispatch as WORKSPACE_REQUEST_INVALID. A default an action declares is applied there too, so it no longer appears in the published schema. Where two actions accept the same field with different limits — max_bytes is 1 MiB for search and 4 MiB for download — the schema shows both forms, and the action you named decides which one your call had to match.

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, and deliver a paused materialization node’s files into the response when this host cannot run the presented command. 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, 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.

The execution revision advances only when an original step persists workflow state. 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.

When current_step presents a paused materialization node, it returns a fresh five-minute archive command rather than file contents. The grant is bound to the current user, execution, node, and context snapshot and can be downloaded repeatedly only while that execution remains waiting on the node with the same context. Run or retry the returned command exactly, then complete the node with null or {}; advancing the execution or changing its context invalidates the URL. A host that cannot run the command or reach the network uses materialize instead, which returns the same file bodies in the response under the same bindings and window, subject to a smaller total-size ceiling, and completes the node the same way.

Progress-image grants are bound to the execution owner, workflow version, workflow-step revision, context revision, and normalized render options. Failed rendering or failed HTTP delivery does not consume the grant; successful response completion does.

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 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, 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 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.

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:

Terminal window
curl -X POST "${uploadUrl}" -F "workflow=@your-workflow.json"

The workspace tool gives an agent a persistent, user-owned cloud development environment (currently a personal GitHub Codespace) without a local shell or filesystem. One tool serves the whole surface: action selects the operation — list, create, get, start, stop, delete, exec, stat, search, read, write, apply_patch, upload or download — and the other fields are those the chosen action declares. GitHub is connected only on the Moira website; no action starts, resumes or polls an authorization. When the connection, installation or server configuration is missing, every action returns a bounded error with a same-origin settings_url for the user to complete setup, and nothing is provisioned.

Every call but list and create names a workspace_id obtained from one of them. Ownership is checked server-side, so an unknown or foreign ID returns the generic WORKSPACE_NOT_FOUND result. A workspace is not tied to a chat or session: reuse the same workspace_id from any client. list offers only workspaces that can still be used; a deleted or rejected one is absent from it while get still answers for its workspace_id. stop preserves the repository data (data_preserved: true); delete is destructive and requires confirm_delete: true with the workspace’s current generation, so a stale call cannot delete a changed workspace.

exec runs argv as data (no shell interpolation) in a repository-relative cwd with a timeout (timeout_seconds, optional) and optional per-stream output limits, and returns bounded stdout, stderr and the exact exit_code. Those limits bound the answer, not the command: a command that prints more keeps running, keeps its own exit code and keeps its own stderr, and the result reports each stream’s complete size and whether the payload was truncated. The whole output stays in the workspace until the operation is cleaned up, and any range of it is read with read. A command is stopped for its volume only if its retained output reaches the workspace ceiling, which is reported as that rather than as the command’s own failure. For work that outlives one request, such as a full build or test suite, pass background: true: the call returns a running operation at once, the command keeps running in the workspace under a much larger ceiling, its output is readable by range while it runs, and its result is collected later with the same operation_id, which stays collectible for at least as long as the command was allowed to run. Omitting timeout_seconds gives a bounded command 300 seconds and a background command its whole ceiling.

Consecutive commands can share a working context. Open a session with session and session_start: true, then name the same session on later commands: it remembers the cwd a call names and the variables a call passes in env, and applies both to every command that continues it. A command without a session is unaffected. Inside a session you may send script instead of argv: it runs under the workspace’s own shell, and the directory it ends in and the variables it added, changed or removed are carried to the commands that follow, which is how activating a toolchain or a virtual environment survives. An argv command is never run through a shell, and one call carries one kind of work. End a session with session_end: true, alone or with a command; ending frees its slot and removes what it stored. A workspace holds a bounded number of open sessions, and once it is full the next session_start is refused with that ceiling named and asks you to end one rather than retry or open another workspace. A session’s stored context is bounded too, a call that would exceed it is refused with that ceiling named, and a script carries its end state whether it succeeded or failed, while one whose end state would not fit, one that ends its own shell with exit and one that was stopped report session_capture_dropped instead of leaving a session you cannot use. A session belongs to the workspace’s current life: after the workspace stops and starts again, naming it returns WORKSPACE_SESSION_UNAVAILABLE and a new session must be opened, as it does for a session that was never opened. What a session stores stays in the workspace and is never returned. Stop either kind by calling the same action with only workspace_id, operation_id and cancel: true. A command stops with its workspace, so a long one needs a workspace whose idle lifetime outlasts it. A workspace that went to sleep does not have to be started first: the call that needs it starts it and then runs, within a bounded wait. If it does not finish starting in time the call returns WORKSPACE_START_TIMEOUT, which names that wait and asks you to retry; a workspace that cannot start at all is refused by what it is. A command whose workspace restarted under it is reported as WORKSPACE_OPERATION_INTERRUPTED, with interrupted_by_restart on the operation, rather than as a failure of its own: the files it had already written are still there, it produced no result, and running it again is the remedy. Supply at most one stdin form: stdin_text for UTF-8 text or stdin_file for a native ChatGPT file reference; the file’s bytes reach the process without base64 in the conversation. Failed, timed-out and cancelled commands and rejected file edits are returned as tool errors that keep operation_id and the available output. A command that finishes quickly returns its terminal result from the same call that started it; one that is still running returns a non-terminal state, which is not a success. Call the same action again with only workspace_id and operation_id to obtain the stored outcome without running the command or mutation twice.

read returns UTF-8 text with offset and total_size, plus sha256 for a repository file; give path for a file, or operation_id and stream for a command’s retained stdout or stderr, naming the workspace that command belongs to. A read that starts at or past the end of a stream returns no text and the stream’s current size. length defaults to 64 KiB, and search defaults to 100 matches within 64 KiB of results, so naming only the workspace, path and query is a complete call. Search covers repository content and skips the repository’s own .git directory, and it refuses a search rooted at or inside that directory; a file there is still readable by its exact path. A non-text range returns WORKSPACE_BINARY_READ_REQUIRES_DOWNLOAD. A call that matches no request form returns WORKSPACE_REQUEST_INVALID naming the missing or invalid fields. write replaces a file atomically under an expected precondition (exists, optional size_bytes and sha256), and apply_patch applies ordered byte-offset edits per file with the same preconditions and returns old/new versions plus a content-free summary. upload writes a native file reference to a path; download returns the file as an MCP resource_link whose one-use HTTPS link expires automatically and is never repeated in the JSON result.

The agent runs as the ordinary Codespace user with that environment’s repository, network and configured secrets. Moira bounds its own concurrency, input/output size, time and quotas and protects the Moira server and other users; it does not sandbox the workspace from the agent its owner authorized. A user may hold several workspaces at once, and a creation refused by a ceiling says which one refused it: your own active-workspace ceiling, the instance-wide one, or the interval between creations. The refusal names that ceiling’s configured value and never names another user or their workspaces. When GitHub itself refuses a creation, start, stop or delete, the error says so rather than reporting an internal failure: it distinguishes a grant you must reauthorize, a request GitHub will refuse again however many times you repeat it, and a provider outage worth retrying, and it repeats GitHub’s own explanation in one shortened line. That line is dropped whole, leaving only the HTTP status, whenever it contains anything shaped like a credential — a token, a labelled secret, a JWT or a URL.

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.