Skip to main content

Overview

Workflow nodes let you execute another SirenSpec workflow inline as part of a parent workflow — enabling sub-workflow composition, code reuse, and modular workflow design. Any node with type: workflow is a workflow node.
The sub-workflow runs blocking (not in parallel) inside the parent workflow. Its output dict is written into the parent context so downstream nodes can reference it.

When to Use Workflow Nodes

Use workflow nodes when:
  • You want to compose modular, reusable workflow templates
  • A sub-workflow is shared across multiple parent workflows
  • You need to organize complex workflows into logical stages (e.g., extraction → analysis → synthesis)
  • You want to keep workflow files small and maintainable
Do NOT use workflow nodes when:
  • You want to run tasks in parallel (use swrm or factory instead)
  • You are passing the entire workflow context to a sub-workflow (inputs isolate the sub-workflow’s context by design)

Node Fields


ref — Sub-Workflow Reference

The ref field accepts two forms:

File Path

Relative or absolute paths to YAML workflow files, resolved at execution time:

Named Registry Entry

If a WorkflowRegistry is passed to execute(), ref can be a string name:
The registry is passed programmatically:

inputs — Context Isolation

The sub-workflow’s context is initialized with only the keys declared in inputs. It does not inherit the parent’s full working context. This ensures clean separation of concerns: the sub-workflow only sees what the parent explicitly passes.
Before the sub-workflow starts, template expressions in inputs are resolved against the parent’s context:
  • {{ extract.output }} — reads from the parent’s working or output
  • {{ env.API_KEY }} — reads environment variables
  • {{ inputs.message }} — reads the parent’s initial input
After resolution, the sub-workflow receives a clean context dict containing only the values in inputs. Inside the sub-workflow, these become available under {{ inputs.* }}:

writes — Output Path

By default, sub-workflow output is written to output.<node_id>. You can customize this path:
Without writes, output is written to output.run_child:
With writes: output.analysis, output is written to output.analysis:
The sub-workflow’s output dict (keyed by sub-node ID) is stored at the specified path, so you can reference individual sub-nodes:

max_depth — Nesting Limit

Workflow nodes can nest arbitrarily deep, but to prevent infinite recursion cycles, each node has a nesting depth limit (default: 10).
If a sub-workflow node is executed at depth >= max_depth, execution raises ValidationError:

Output Shape

After a workflow node executes, its sub-workflow’s output dict is written to the parent context:

Accessing Sub-Node Outputs

Reference individual sub-node outputs via the output dict:

Complete Example

Parent workflow (parent.yaml):
Sub-workflow (analysis.yaml):
Run it:
The parent’s output will include:

Error Handling

ValidationError: Max workflow nesting depth exceeded

Raised when a workflow node is executed at a depth >= its max_depth. Increase max_depth or simplify your workflow nesting:

FileNotFoundError

Raised when ref points to a non-existent file:
Check the file path relative to the parent workflow file location.

KeyError

Raised when ref is a named string and the registry does not contain that workflow:
Register the workflow before execution:

Template Interpolation

In inputs values, you can use all standard SirenSpec template syntax:

JSON Schema

The sirenspec.schema.json artifact validates workflow nodes inline with other node types. IDEs that support JSON Schema (VS Code, JetBrains) will autocomplete type: workflow, ref, and all fields automatically.