Rensei docs
Nodes

Parallel Nodes

fanout / fanin parallel execution nodes.

Partially implemented. Concurrent branch execution, the canvas group editor, branch ordering, and scope isolation are shipped. Fan-in output aggregation is not: parallel.fanin is a graph-shape marker that completes with an empty output - it does not collect branch results into a results array. Downstream steps cannot yet consume a merged per-branch output. Aggregation is tracked as a known gap on the roadmap.

Parallel nodes let a workflow execute multiple branches concurrently and then converge on a single continuation point. They appear as a matched pair: parallel.fanout starts the concurrent branches and parallel.fanin waits for all of them to complete before the workflow continues.

The pair forms a parallel group on the canvas - a visual container with a fan-out entry node, one or more branch subgraphs inside the container, and a fan-in exit node. The workflow definition serializes this as a parallel-group step type.

parallel.fanout

Starts concurrent execution of all branches defined in the parallel group. The executor fires all branches simultaneously at the same DAG tier.

Canvas behavior: Dropping parallel.fanout onto the canvas creates an empty parallel group container. Use the Parallel branches editor in the config panel to add, rename, and reorder branches. Each branch is an independent sub-graph within the container scope.

Port behavior: parallel.fanout has no typed input ports in isolation - upstream nodes wire to the parallel group boundary ports (the entry points of each branch). The fanout node itself acts as the scope entry signal.

Bespoke config panel: parallel.fanout uses an auto-discovered bespoke config panel that renders the branch definition editor. From the panel you can:

  • Add new branches with a label
  • Rename existing branches
  • Reorder branches
  • Remove branches (edges from removed branches are deleted)

parallel.fanin

Waits for all branches in the parallel group to complete before routing execution out of the container. The workflow instance remains in running status while branches execute concurrently. Once all branches complete, execution continues past the fan-in.

Merge behavior (not yet implemented): parallel.fanin does not aggregate branch outputs today. The executor treats the fan-in as a passthrough that completes with an empty output ({}) - fan-out/fan-in semantics live entirely in graph topology, with branches fired at the same DAG tier via Promise.allSettled. To consume a branch's result downstream, reference the branch step directly with a template expression - {{ steps.<stepId>.output.<field> }} - rather than the fan-in's output; a merged results array on the fan-in port is a known gap.

Port behavior: parallel.fanin exposes a single output port for downstream wiring, but its runtime value is an empty object until output aggregation ships.

Error handling: If a branch step fails (after retries), execution stops after the current DAG tier completes - steps already in flight in that tier run to completion (they are not cancelled), and no later tier (including steps past the fan-in) executes.

Parallel group anatomy

[upstream node]


parallel.fanout
  ┌────┴────────────────────┐
  │ Branch A                │  Branch B                │
  │ [node A1] → [node A2]   │  [node B1]               │
  └────────────────────────┘  └────────────────────────┘
       │                              │
       └──────────┬───────────────────┘

           parallel.fanin


           [downstream node]

YAML representation

The workflow definition serializes a parallel group as a single parallel-group step containing an ordered branches array. The executor uses Kahn-BFS tier computation to fire all branches at the same tier.

steps:
  - id: parallel_research
    type: parallel-group
    branches:
      - id: branch_linear
        steps:
          - id: read_linear
            type: action
            nodeId: linear.issue.read
            config:
              issueId: "{{ $trigger.data.issueId }}"

      - id: branch_github
        steps:
          - id: read_pr
            type: action
            nodeId: github.file.read
            config:
              owner: "{{ $trigger.data.repository.owner }}"
              repo: "{{ $trigger.data.repository.name }}"
              path: CONTRIBUTING.md

  - id: continue_after_parallel
    type: action
    nodeId: linear.comment.create
    config:
      issueId: "{{ $trigger.data.issueId }}"
      body: "Research complete. Linear issue and PR context loaded."

Usage patterns

Multi-tracker research: Fan out to read an issue from both Linear and GitHub Issues simultaneously, then fan in before dispatching the agent with both contexts.

Concurrent agent dispatch: Dispatch multiple agents in parallel - for example, a security scanner and a code reviewer - and wait for both before advancing the SDLC stage.

Multi-repo operations: Apply the same operation (create a branch, post a comment) to multiple repositories concurrently.

Independent setup steps: Provision multiple resources in parallel (create a branch, add a label, acknowledge the session) before the main agent dispatch.

Scope isolation

Steps inside a parallel group branch can only wire to other steps in the same branch or to the parallel group boundary ports. Cross-branch wiring is not allowed - this is enforced at canvas validation time. Because fan-in output aggregation has not shipped, data cannot flow between branches or out through the fan-in port; downstream steps that need a branch's data must reference the branch step's output directly via {{ steps.<stepId>.output }} template expressions.

On this page