Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.sirenspec.dev/llms.txt

Use this file to discover all available pages before exploring further.

Overview

A factory node generates its instances at runtime rather than at authoring time. Where a swrm node has a static, author-defined set of agents, a factory decides how many instances to spawn based on a list resolved during execution — one instance per item, or a fixed count. Every instance runs in parallel (bounded by concurrency), and all outputs are collected into a list written to a single context path.
nodes:
  execute:
    type: factory
    agent: worker
    for_each: "{{ plan.output }}"   # resolved to a list at runtime
    inputs:
      task: "{{ item }}"
    concurrency: 4
    writes: working.execute.outputs

Execution modes

A factory node has three mutually exclusive modes, determined by which fields you set.
ModeRequired fieldsSpawnsLoop variables
Agent + for_eachagent, for_eachOne agent call per list item{{ item }}, {{ index }}, {{ total }}
Agent + swarm_sizeagent, swarm_sizeN identical agent calls on the same input{{ index }}, {{ total }} (no {{ item }})
Swrm + for_eachswrm, for_eachOne full swrm (parallel specialists + optional synthesis) per list item{{ item }}, {{ index }}, {{ total }}

Mode 1 — Agent + for_each

One call to a named agent for each element in a runtime list.
nodes:
  execute:
    type: factory
    agent: worker_agent
    for_each: "{{ plan.output }}"
    inputs:
      task: "{{ item }}"
      position: "{{ index }} of {{ total }}"
    concurrency: 4
    writes: working.execute.outputs

Mode 2 — Agent + swarm_size

N identical calls to the same agent on the same input — useful for sampling multiple candidate responses.
nodes:
  brainstorm:
    type: factory
    agent: ideator
    swarm_size: 5
    inputs:
      position: "{{ index }} of {{ total }}"
    concurrency: 5
    writes: working.ideas
swarm_size accepts a static integer or a template expression (e.g. "{{ inputs.count }}").

Mode 3 — Swrm + for_each

One full swrm — parallel specialist agents with an optional synthesis step — per list item.
nodes:
  grade_papers:
    type: factory
    swrm:
      agents:
        - id: editor
          provider: openai
          model: gpt-4o-mini
          prompt: "Review: {{ item }}"
        - id: grader
          provider: anthropic
          model: claude-haiku-4-5-20251001
          prompt: "Grade this paper: {{ item }}"
      synthesis:
        provider: anthropic
        model: claude-haiku-4-5-20251001
        prompt: |
          Editor: {{ grade_papers.agents.editor.output }}
          Grader: {{ grade_papers.agents.grader.output }}
          Return the final grade.
    for_each: "{{ inputs.papers }}"
    concurrency: 3
    writes: working.grades

Node fields

FieldRequiredTypeDefaultDescription
typeYes"factory"Node type discriminator.
agentOne of agent / swrmstringNamed agent from the workflow’s top-level agents map. Mutually exclusive with swrm.
swrmOne of agent / swrmobjectInline swrm spec (agents, optional synthesis, optional concurrency) executed per item. Mutually exclusive with agent.
for_eachOne of for_each / swarm_sizestringTemplate expression resolved to a list at runtime. Accepts a native Python list, a JSON array string, or a fenced ```json block. Mutually exclusive with swarm_size.
swarm_sizeOne of for_each / swarm_sizeint or stringStatic count or template expression for parallel agent instances. Only valid in agent mode.
inputsNoobject{}Template strings for each input. Supports {{ item }}, {{ index }}, {{ total }}. Each resolved key is also exposed to the spawned agent’s prompt as {{ inputs.<key> }}.
concurrencyNointeger1Maximum parallel worker instances.
timeout_per_instanceNointeger60Per-instance timeout in seconds.
on_failureNo"abort" | "continue""abort"abort raises FactoryNodeError; continue skips the failed instance and keeps the rest.
writesYesstringDot-notation path where the list of instance outputs is stored.

Loop variables

Inside inputs: templates, agent prompts, and swrm agent/synthesis prompts, three special variables are available:
VariableAvailabilityTypeDescription
{{ item }}for_each mode onlyanyThe current list element.
{{ index }}All modesintZero-based position in the list.
{{ total }}All modesintTotal number of items.
Each key under inputs: is additionally available in the spawned agent’s system prompt as {{ inputs.<key> }} once resolved — so inputs: { task: "{{ item }}" } makes {{ inputs.task }} reference the current item inside the agent’s prompt.
When for_each points at an LLM output that may emit prose, an empty string, or a fenced ```json block instead of a clean array, wrap it with | json_or_default('[]') so a bad response falls back to an empty list rather than failing the run. See Interpolation.

Output shape

All instance outputs are collected, in list order, and written to the writes path:
writes: working.execute.outputs
# working.execute.outputs == ["result for item 0", "result for item 1", ...]
In Swrm + for_each mode, each entry is that item’s swrm result — the synthesis output when synthesis is defined, otherwise the list of agent outputs. Reference the collected list downstream like any other context value:
nodes:
  aggregate:
    agent: summarizer        # system: "Summarize these results: {{ execute.output }}"
    writes: output.report

Failure handling

on_failureBehaviour
abort (default)The first failing instance raises FactoryNodeError and the workflow stops.
continueThe failing instance is recorded in the trace and skipped; the remaining instances still contribute to the output list.
FactoryNodeError is importable from sirenspec.exceptions:
from sirenspec.exceptions import FactoryNodeError

When to use a factory

Use a factory when:
  • The number of work items is unknown until runtime (e.g. a planner agent emits a task list).
  • You want N independent samples of the same prompt (swarm_size).
  • Each item needs a full committee-of-experts review (Swrm + for_each).
Use something else when:
  • The set of agents is fixed and known up front — use swrm.
  • Items must share intermediate state or run in sequence — use ordinary nodes with edges.

Cookbook recipes

See the YAML Reference for the full field-by-field listing.