Start
Entry point for workflow execution.
Nodes are the building blocks of Moira workflows. Each node represents a step in the process with specific behavior defined by its type.
Moira supports 8 interactive node types and 3 automatic node types:
Start
Entry point for workflow execution.
End
Terminal node marking workflow completion.
Agent Directive
Agent task with directive and completion condition.
Condition
Branch execution based on structured conditions.
Expression
Compute values using arithmetic expressions.
Subgraph
Delegate to another workflow.
Telegram Notification
Send notifications via Telegram.
Teleport
Jump target reachable only via explicit teleport.
Entry point for workflow execution. Every workflow must have exactly one start node.
{ "id": "start", "type": "start", "initialData": { "projectName": "my-project" }, "connections": { "default": "first-task" }}| Property | Required | Description |
|---|---|---|
id | Yes | Convention: should be “start” |
type | Yes | Must be "start" |
initialData | No | Initial context variables |
connections.default | Yes | Next node ID |
Terminal node marking workflow completion. No outgoing connections.
{ "id": "end", "type": "end", "finalOutput": ["result", "summary"]}| Property | Required | Description |
|---|---|---|
id | Yes | Convention: should be “end” |
type | Yes | Must be "end" |
finalOutput | No | Context keys to include in final result |
The primary node type for agent tasks. Contains a directive (what to do) and completion condition (when done).
{ "id": "analyze-requirements", "type": "agent-directive", "directive": "Analyze the requirements document and identify key features", "completionCondition": "Features are listed with priorities", "inputSchema": { "type": "object", "properties": { "features": { "type": "array", "items": { "type": "string" } } }, "required": ["features"] }, "connections": { "success": "next-step" }}| Property | Required | Description |
|---|---|---|
directive | Yes | What the agent should do |
completionCondition | Yes | When the step is complete |
inputSchema | No | JSON Schema for response validation |
maxRetries | No | Max validation retries (default: 3) |
retryMessage | No | Custom retry message |
connections.success | Yes | Next node on success |
connections.error | No | Next node on error |
connections.maxRetriesExceeded | No | Next node when retries exhausted |
Branch execution based on structured conditions:
{ "id": "check-result", "type": "condition", "condition": { "operator": "eq", "left": { "contextPath": "status" }, "right": "success" }, "connections": { "true": "success-path", "false": "retry-step" }}| Property | Required | Description |
|---|---|---|
condition | Yes | Structured condition object |
connections.true | Yes | Next node when condition is true |
connections.false | Yes | Next node when condition is false |
Conditions use a structured format (not string evaluation):
{ "operator": "and", "conditions": [ { "operator": "gt", "left": { "contextPath": "score" }, "right": 80 }, { "operator": "eq", "left": { "contextPath": "validated" }, "right": true } ]}Supported condition types:
equals, notEqualsgreaterThan, lessThan, greaterThanOrEquals, lessThanOrEqualsand, or, notexists, isEmptyCompute values using arithmetic expressions. Useful for counters, calculations, and variable transformations:
{ "id": "increment-counter", "type": "expression", "expressions": ["counter = counter + 1", "result = counter * multiplier"], "connections": { "default": "next-step", "error": "error-handler" }}| Property | Required | Description |
|---|---|---|
expressions | Yes | Array of assignment expressions |
connections.default | Yes | Next node after successful evaluation |
connections.error | No | Next node on evaluation error |
Expressions support basic arithmetic operations:
+, -, *, /(a + b) * cresult = a + bstep.index, plan.items[0].value{ "expressions": ["total = price * quantity", "tax = total * 0.1", "final_price = total + tax"]}Expression nodes can fail in two cases:
When an error occurs, execution routes to the error connection if defined, otherwise the workflow fails.
Delegate execution to another workflow:
{ "id": "run-tests", "type": "subgraph", "graphId": "test-workflow", "inputMapping": { "codeDir": "projectPath" }, "outputMapping": { "testResults": "results" }, "connections": { "success": "next-step" }}| Property | Required | Description |
|---|---|---|
graphId | Yes | Referenced workflow ID |
inputMapping | Yes | Parent context -> subgraph context |
outputMapping | Yes | Subgraph context -> parent context |
connections.success | Yes | Next node on success |
connections.error | No | Next node on failure |
Send automated notifications via Telegram:
{ "id": "notify-complete", "type": "telegram-notification", "message": "Workflow {{workflowName}} completed successfully", "parseMode": "Markdown", "connections": { "default": "next-step", "error": "notification-failed" }}| Property | Required | Description |
|---|---|---|
message | Yes | Notification text (supports templates) |
parseMode | No | Message format: “Markdown” or “HTML” |
connections.default | Yes | Next node after sending |
connections.error | No | Next node on API failure |
Jump target reachable only via explicit teleport, not via normal connections. Behaves like agent-directive (pauses for input, validates schema) but is only reachable when the agent explicitly requests a teleport jump.
{ "id": "teleport-replan", "type": "teleport", "directive": "Rewrite the development plan", "completionCondition": "New plan created and validated", "hint": "Use when current plan needs restructuring", "inputSchema": { "type": "object", "properties": { "reason": { "type": "string" } }, "required": ["reason"] }, "connections": { "success": "plan-node" }}| Property | Required | Description |
|---|---|---|
hint | Yes | Human-readable description of when to use teleport |
directive | Yes | Instruction shown to agent after teleport |
completionCondition | Yes | Success criteria for the teleport step |
inputSchema | No | JSON Schema for agent response validation |
connections.success | Yes | Next node after teleport input provided |
connections.error | No | Error handler node |
When a workflow contains teleport nodes, their hints are automatically appended to each step response under “Available Teleport Jumps”. To jump to a teleport node, use the teleportTo parameter in step():
step({ processId: "abc123", teleportTo: "teleport-replan" })input when teleporting — the teleport node will present its own directiveconnections.successDefine expected response structure using JSON Schema:
{ "inputSchema": { "type": "object", "properties": { "summary": { "type": "string", "description": "Brief summary of findings" }, "items": { "type": "array", "items": { "type": "object", "properties": { "name": { "type": "string" }, "priority": { "type": "number" } } } } }, "required": ["summary"] }}Automatic nodes execute without agent interaction. They run server-side and immediately continue to the next node. Used for note storage operations.
Reads notes matching filter criteria into context variable:
{ "type": "read-note", "id": "load-notes", "outputVariable": "projectNotes", "filter": { "tag": "{{projectTag}}", "keyPattern": "project-" }, "singleMode": false, "connections": { "default": "next-node", "error": "error-handler" }}| Property | Required | Description |
|---|---|---|
outputVariable | Yes | Context variable to store results |
filter.tag | No | Filter by exact tag |
filter.keyPattern | No | Filter by key prefix |
filter.keySearch | No | Search in key (contains) |
singleMode | No | Return object instead of array |
connections.error | No | Error handler node |
Writes data from context to notes:
{ "type": "write-note", "id": "save-results", "key": "results-{{timestamp}}", "source": "analysisResults", "tags": ["analysis"], "connections": { "default": "next-node" }}| Property | Required | Description |
|---|---|---|
key | No* | Note key (required in single mode) |
source | Yes | Context variable with value |
tags | No | Tags to assign |
batchMode | No | Process array of notes |
Find-or-create operation:
{ "type": "upsert-note", "id": "upsert-config", "search": { "tag": "config" }, "keyTemplate": "{{projectId}}-config", "value": "configData", "connections": { "default": "next-node" }}| Property | Required | Description |
|---|---|---|
search.tag | No | Search by tag |
search.keyPattern | No | Search by key prefix |
keyTemplate | Yes | Key for new note if not found |
value | Yes | Context variable with note value |
inputSchema for structured responses