OptionalarrayOptionalconvergeSTRUCTURE-ONLY: the downstream stage id this branch's convergence edge points to, overriding the default "converge at the next linear stage."
When a fork/selector/decider branch carries convergeAt, its visualized
next edge is fired to the named stage instead of to the shared
convergence node its siblings use. This expresses an unequal-depth merge
— e.g. a tools slot that bypasses the messageAPI assembly node and
pairs with its output at call-llm (so call-llm reads as a 2-parent
merge), faithful to the Anthropic wire protocol (system+messages = the
message payload; tools = a separate top-level field).
This affects the STRUCTURE/topology graph only — the runtime is unchanged (the branch's outputs ride shared scope; the named target reads them when it runs). It does NOT introduce a join barrier. The target is a FORWARD stage (added later in the chain), so it is not validated at branch-declaration time.
OptionalinputOptionaloutputMaps subflow output back into parent scope.
Array merge behavior is controlled by arrayMerge:
'concat' (default): [...existing, ...value] — return only delta items'replace': overwrites the parent value — return the full arrayScalar values are always replaced regardless of arrayMerge.
// Delta mode (default) — return only new items, concat appends
outputMapper: (sf) => ({ messages: sf.newMessages })
// Replace mode — return full array, parent value is overwritten
// Useful in Dynamic loops where the subflow recomputes the full value each iteration
outputMapper: (sf) => ({ toolDescriptions: sf.toolDescriptions }),
arrayMerge: ArrayMergeMode.Replace,
// Scalars are fine in both modes — always replaced
outputMapper: (sf) => ({ status: sf.result, count: sf.total })
OptionalpropagateWhen true, an inner scope.$break(reason) call inside this subflow
propagates up to the parent — i.e., the parent's breakFlag is set
after the subflow exits, terminating the parent's outer loop too.
Default: false (current behaviour — inner break stops only the
subflow; parent continues).
Set propagateBreak: true on subflow mounts that represent
terminal branches — "if this subflow fires, the outer loop is
done". Examples:
scope.$break(reason).$break behaviour).SubflowExecutor inspects the subflow's exit state. If
propagateBreak === true AND the inner break fired, it forwards
the break (and its reason) to the parent's breakFlag.shouldBreak on its next step and exits.FlowRecorder.onBreak event fires at the parent-mount level with
propagatedFromSubflow = the subflow's id and the inner reason.A fork child runs with its own break flag, and every fan-out call site
passes no parent break flag to ChildrenExecutor. So a
propagateBreak: true subflow mounted as a fork child stops its own
branch only; the parent fan-out never breaks, even when every child
broke.
The subflow's outputMapper (if supplied) ALWAYS runs before the
break propagates, so the subflow's partial state is still written to
the parent scope. This is intentional — the typical use case is an
"escalation" subflow whose output IS the final answer that needs to
land in the parent scope before the outer loop terminates. If you
want to suppress output mapping on break, check the break state
inside your outputMapper and return {} early.
OptionaltagsDeclared tags (9.21.1) for the MOUNT itself — the NAMES the author puts
on this mount at build time, landed by the same applyTags every other
options.tags site uses, with the same refusals (empty, non-string, the
reserved ~ marker, a duplicate, a second declaration).
A mount is a stage that commits: its first bundle in the PARENT log is a
stop in commitStops, so tagStops keeps it like any tagged stage and
carries these names as Stop.meta. Stamped on that first bundle only
(the mount's exit bundle carries none — the once-per-execution law).
The subflow's OWN log is untouched: its inner stages declare their own
tags, and drill(mount) reads those off the inner log.
This is the ONLY tag site for a fork-child mount (addSubFlowChart) or
a branch mount (addSubFlowChartBranch) — after those the cursor still
points at the parent, so .tag() refuses rather than mis-attribute. A
linear mount (addSubFlowChartNext) moves the cursor, so .tag() works
there too; declare in one place, not both.
Controls how array values from outputMapper are merged into parent scope. Applies only to top-level array keys. Nested arrays inside objects always use append (appendToArray) regardless of this setting.