Engine-feature demo — this guide teaches a single mechanism: parallel fan-out via
shape=componentand fan-in viashape=tripleoctagon. For the canonical attractor shape used in real work, start with Tutorial 00: The Convergence Loop.
Self-contained -- the goal is baked into the .dot, so no --param is needed.
From the attractor repo root:
DOT="$PWD/examples/pipelines/05-parallel-fan-out.dot"
mkdir -p /tmp/attractor-demo && cd /tmp/attractor-demo
attractor run "$DOT" --cwd .See README.md in this folder for the run pattern and why the $DOT capture + cd + --cwd . are needed (box-node process-cwd alignment + dot-path resolution).
- Parallel handler (
shape=component): Fans out to multiple branches concurrently - Fan-in handler (
shape=tripleoctagon): Consolidates parallel results and selects the best candidate join_policy="wait_all": All branches must complete before fan-in proceedserror_policy="continue": If one branch fails, other branches still run to completionmax_parallel=3: Bounds concurrent execution to 3 branches (matches our branch count)- Isolated branch contexts: Each branch gets a
context.clone()-- changes in one branch don't affect others parallel.resultsin context: The parallel handler stores branch results for the fan-in handler to consume
+--> test_arithmetic --+
| |
start -> plan -> parallel +--> test_trig --------+--> collect_results -> summarize -> done
| |
+--> test_stats -------+
plancreates the test plan -> SUCCESSparallel_testshandler activates:- Identifies 3 outgoing edges (fan-out branches)
- Clones context for each branch (isolation)
- Creates asyncio semaphore with
max_parallel=3 - Emits
pipeline:parallel:startedevent withbranch_count=3 - Executes all 3 branches concurrently
- Each branch emits
pipeline:parallel:branch:startedandpipeline:parallel:branch:completed - Stores results in
context["parallel.results"]as a list of dicts - Evaluates
wait_allpolicy: all 3 must complete (SUCCESS if none failed, PARTIAL_SUCCESS if any failed)
collect_results(fan-in) handler:- Reads
parallel.resultsfrom context - Ranks candidates by status (SUCCESS > PARTIAL_SUCCESS > RETRY > FAIL)
- Records winner in
parallel.fan_in.best_idandparallel.fan_in.best_status
- Reads
summarizecreates a unified report- Pipeline completes
| Policy | Behavior |
|---|---|
wait_all |
All branches complete. SUCCESS if none failed, PARTIAL_SUCCESS otherwise |
first_success |
Returns as soon as one branch succeeds. Others may be cancelled |
k_of_n |
At least min_success branches must succeed (set via node attribute) |
quorum |
At least quorum_fraction (e.g., 0.5) of branches must succeed |
| Policy | Behavior |
|---|---|
continue |
All branches run to completion regardless of failures |
fail_fast |
Cancel remaining branches on first failure |
ignore |
Filter out failed branches from results entirely |
steps:
- agent: attractor:pipeline-runner
instruction: "Run the parallel fan-out pipeline"
context:
pipeline_path: "examples/pipelines/05-parallel-fan-out.dot"parallel:startedevent withbranch_count=3- Three
parallel:branch:completedevents (one per branch) parallel:completedevent withsuccess_countandfailure_count- Context contains
parallel.results(list of 3 result dicts) - Context contains
parallel.fan_in.best_idafter fan-in - Each branch's log directory has its own
prompt.md,response.md,status.json - Branch contexts are isolated -- changes in
test_arithmeticdon't appear intest_trig