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