Skip to content

Editing Workflows

Editing Methods

Via MCP Tools

Use the manage tool with edit action:

mcp__moira__manage({
action: "edit",
workflowId: "my-workflow",
changes: {
// changes go here
},
});

Via workflow-management-flow

Start the management workflow:

mcp__moira__start({
action: "prepare",
workflowId: "workflow-management-flow",
parentExecutionId: "none",
});
mcp__moira__start({ action: "execute", startAttemptId: "<Start attempt ID from prepare>" });

Select “edit” when prompted for action.

Use workflow-management-flow for complex edits. It reviews the design before mutation, validates the resulting graph, and independently reviews the completed workflow.

Via the Workflow CLI

Repository authors can use the official moira-workflow CLI for file-backed edits. First confirm which checkout supplies a globally linked command, especially when several Moira worktrees exist:

Terminal window
moira-workflow --version

The output includes both the package version and exact source path. Long descriptions and complete variable schemas can be read from files, avoiding fragile shell quoting:

Terminal window
moira-workflow ./workflow.json set-description --file ./description.txt
moira-workflow ./workflow.json set-system-reminder --file ./reminder.txt
moira-workflow ./workflow.json set-tags research,verification
moira-workflow ./workflow.json set-variable-schema result --file ./result-schema.json

The process view uses the same file-backed authoring surface. Set the complete block list from JSON with set-progress (or grow it with add-block / edit-block), then give every node its block with set-block — routing nodes included, since the derivation refuses an unowned node. Progress attachment is available on user-notification and deprecated telegram-notification nodes; none and false clear the corresponding optional fields.

Terminal window
moira-workflow ./workflow.json set-progress --file ./progress.json
moira-workflow ./workflow.json update implement --progress-node-id implementation
moira-workflow ./workflow.json update implement --progress-active-label "Implement {{unit}}/{{total}}"
moira-workflow ./workflow.json update notify --progress-node-id review --attach-progress-image true

The block contract has its own commands: own a node by a block, add or edit a block with its description, label a connection that leaves a block, and explain a return with the cause of the loop and the condition that ends it. Each write reports how many block-contract diagnostics remain, so a flow is annotated iteratively until derive shows none; --no-version-bump keeps the version while iterating.

Terminal window
moira-workflow ./workflow.json set-block route-plan-approval plan
moira-workflow ./workflow.json add-block deliver "Deliver" "Hand the result over" --after execute
moira-workflow ./workflow.json edit-block deliver --summary "Present the result"
moira-workflow ./workflow.json set-label check-plan-approved true "plan approved"
moira-workflow ./workflow.json set-label route-review false "review found defects" \
--cause "The independent review reported blocking findings." --exit "The review passes."
moira-workflow ./workflow.json derive

These commands persist schema fields; they do not derive the process or judge its meaning, and they do not replace the final validate, derive, schema, behavioral scenarios, or independent semantic review.

For a complete planned rewrite, sync preserves the destination identity and its catalog migration aliases in previousSlugs. The catalog reader validates those aliases separately; only the executable graph is passed to the engine validator. Aliases always come from the real destination, not from a workspace copy. A metadata or graph validation failure leaves the destination unchanged. The standalone validate command exits unsuccessfully for either class of error, so an agent or CI script can use it as a real gate without weakening runtime/upload graph validation.

Terminal window
moira-workflow ./workspace/workflow.json sync ./workflows/production/flows/<flow>.json
moira-workflow ./workflows/production/flows/<flow>.json validate

Before reviewing or changing a large graph, print its complete deterministic control-flow schema:

Terminal window
moira-workflow ./workflows/production/flows/<flow>.json schema

The schema names every real node and labelled connection, conditions, cycles, declared outputs and mappings, context references, normal start paths, explicit teleport-only regions, and disconnected components. When the workflow defines a process view, the same projection includes every ordered block, any legacy display edge still stored on it, and every node-to-block mapping. It is a read-only structural projection for agent or human reasoning; it does not run the workflow, interpret workflow-specific meaning, or claim that a structurally visible route is semantically correct.

How workflow-management-flow handles edits

For an edit, the management workflow loads the complete current workflow and records the edit requirements, analysis, plan, and review reports in its workspace. Their contents stay in files; the graph carries only small values that affect routing.

The initial choice also records whether server access is allowed. An explicit local-only or offline instruction is reused without asking again and prevents the edit path from downloading or comparing a server definition.

The same first step records the operating mode. In interactive mode every approval stays as it is: design, plan, and result are confirmed by you. In autonomous mode the workflow routes around those three approvals and delivers a single final report at the end instead. The agent reuses a mode you already stated, infers an unambiguous one — including a run started as a child of an already autonomous process — and asks once only when the mode is neither stated nor derivable.

Autonomy removes waiting for a person, not authority. Uploading still requires an explicit decision, and in autonomous mode an upload without prior authorization resolves to “no” instead of escalating to a non-standard method. Writing the edited definition back to its already resolved local target is the requested work of the run, so it needs no separate approval in either mode.

Before planning, the workflow decides whether to audit the whole source workflow against the known anti-pattern catalog. In interactive mode it asks, reports concrete existing findings, and asks which of them should join the edit scope. In autonomous mode the agent makes both choices itself from the requested change and the available evidence, and leaves the findings it did not take in the audit report. When the audit is skipped, the analysis remains limited to the requested change and its necessary dependencies.

The plan describes outcomes, affected contracts, invariants, acceptance criteria, evidence methods, and risks. Before it requires a validation or proof mechanism, it must identify the required state, a plausible wrong state, and an observation that reliably distinguishes them. An unprovable derived criterion is revised instead of being replaced with a surrogate signal. The plan does not prescribe an exhaustive file list, exact commands, pseudocode, or a fixed sequence of local edits unless an external contract requires them.

Create and edit use the same independent pre-mutation design review. Reviews record detailed findings in a stable workspace file and return only pass, repair, or replan for routing. repair is reserved for a confirmed defect owned by the reviewed artifact; an invalid criterion, evidence model, requirement interpretation, plan, or process returns to its earliest contract owner. After a real repair, the reviewer receives the bounded root class and changed knowledge. A repeated same-root finding without stronger evidence and validation-only work both trigger reassessment rather than another validation layer. Structural validation remains the responsibility of the node that creates or changes the workflow and uses Moira’s official validator.

Change Types

Update Metadata

mcp__moira__manage({
action: "edit",
workflowId: "my-workflow",
changes: {
metadata: {
version: "2.0.0",
description: "Updated description",
},
},
});

Update Node Content

mcp__moira__manage({
action: "edit",
workflowId: "my-workflow",
changes: {
updateNodes: [
{
nodeId: "task-node",
changes: {
directive: "New directive text",
completionCondition: "New condition",
},
},
],
},
});

Add Nodes

mcp__moira__manage({
action: "edit",
workflowId: "my-workflow",
changes: {
addNodes: [
{
type: "agent-directive",
id: "new-node",
directive: "New task",
completionCondition: "Task complete",
connections: { success: "existing-node" },
},
],
},
});

Remove Nodes

mcp__moira__manage({
action: "edit",
workflowId: "my-workflow",
changes: {
removeNodes: ["node-to-remove"],
},
});

When removing nodes, update connections in other nodes that referenced the removed node.

Safe Editing Process

  1. Get current structure

    mcp__moira__manage({
    action: "get-structure",
    workflowId: "my-workflow",
    });
  2. Find nodes to edit

    mcp__moira__manage({
    action: "search-nodes",
    workflowId: "my-workflow",
    query: "search term",
    });
  3. Get node details

    mcp__moira__manage({
    action: "get-node",
    workflowId: "my-workflow",
    nodeId: "node-id",
    });
  4. Apply changes

    mcp__moira__manage({
    action: "edit",
    workflowId: "my-workflow",
    changes: {/* ... */},
    });
  5. Validate

    mcp__moira__manage({
    action: "validate",
    workflowId: "my-workflow",
    });

Editing Without Extra Machinery

Make the change with the official MCP actions or the workflow CLI, and validate the real artifact before you finish. A one-off generator, a migration script, or an intermediate format written to make one edit becomes an undeclared dependency: the workflow then only round-trips correctly where that tool exists, and nothing in the definition says so. The workflow JSON is the artifact of record.

Reconciling Repository and Server Copies

A bundled workflow exists twice: as a file in the repository and as a catalog entry on the instance that serves it. Before editing, resolve which identities refer to the same workflow — the public owner/slug, the internal UUID, and any local path — and compare the two definitions rather than assuming they match.

Terminal window
# Fetch the served definition through a one-time download token
mcp__moira__token({ action: "download", workflowId: "moira/quick-task" })

When the two differ, decide the baseline deliberately: which definition the requested change actually targets, which is newer by metadata.version, and what each one would lose. Combining the two JSON documents mechanically produces a graph neither side reviewed.

Changing a bundled workflow’s slug changes its catalog identity. To rename it without leaving the old entry active after an upgrade, add the old slug to the catalog-only previousSlugs array. The loader migrates that entry under the same owner and preserves its database ID; it fails if more than one declared previous identity exists, rather than guessing or creating a duplicate. Do not use previousSlugs to merge unrelated workflows.

Updating Connections

Single Connection Update

{
updateNodes: [
{
nodeId: "source-node",
changes: {
connections: {
success: "new-target-node",
},
},
},
];
}

Condition Node Connections

{
updateNodes: [
{
nodeId: "condition-node",
changes: {
connections: {
true: "when-true-node",
false: "when-false-node",
},
},
},
];
}

Version Control

Increment Version

Always update version when making changes:

{
metadata: {
version: "1.1.0"; // was 1.0.0
}
}

Version semantics:

  • Major (2.0.0): Breaking changes, restructured flow
  • Minor (1.1.0): New features, new nodes
  • Patch (1.0.1): Bug fixes, text corrections

Compare Versions

mcp__moira__manage({
action: "diff",
workflowId: "my-workflow",
compareWorkflowId: "my-workflow-old",
});

Common Edits

Fix Typo in Directive

{
updateNodes: [
{
nodeId: "task-node",
changes: {
directive: "Corrected directive text",
},
},
];
}

Add Required Field to InputSchema

{
updateNodes: [
{
nodeId: "input-node",
changes: {
inputSchema: {
type: "object",
properties: {
existing_field: { type: "string" },
new_field: { type: "string" }, // added
},
required: ["existing_field", "new_field"], // updated
},
},
},
];
}

Insert Node in Flow

{
addNodes: [
{
type: "agent-directive",
id: "inserted-node",
directive: "New step",
connections: { success: "original-target" }
}
],
updateNodes: [
{
nodeId: "original-source",
changes: {
connections: { success: "inserted-node" }
}
}
]
}

Validation Errors

Missing Connection Target

Error: Node 'task-1' connection target 'missing-node' not found

Fix: Update connection to valid node ID.

Orphaned Node

Warning: Node 'orphan-node' is not reachable from start

Fix: Add connection from another node or remove orphaned node.

Invalid Node Type

Error: Unknown node type 'custom-type'

Fix: Choose a built-in type from the Nodes reference. For a namespaced extension type, make sure its extension is installed. A validator without authoritative live registry data reports the type as unresolved; a live registry that does not contain it reports an error.

See Also