sub_flow
Applies to:
v4.0.8.3
sub_flow should not be understood as “automatic inheritance of parent context”. It is an isolated composable child flow node inside the parent flow.
1. Core mental model
How to read this diagram
capturehappens when the parent execution reaches this node.- the child receives a one-time snapshot, not a live binding
write_backhappens only after the child flow completes successfully
2. Public API
parent.to_sub_flow(
child_flow,
capture={
"input": "value",
"runtime_data": {
"draft": "runtime_data.draft",
},
"flow_data": {
"locale": "flow_data.locale",
},
"resources": {
"logger": "resources.logger",
},
},
write_back={
"value": "result.summary",
"runtime_data": {
"child_report": "result",
},
"flow_data": {
"last_topic": "result.topic",
},
},
)You can also compose a child flow directly:
parent.to(child_flow)This means:
- parent
valuebecomes child input - child
resultbecomes parentvalue
3. capture semantics
Allowed target scopes:
inputruntime_dataflow_dataresources
Allowed source roots:
valueruntime_data.*flow_data.*resources.*
Key boundaries:
- only captures the current directly visible parent context
- captures once when the node executes
- does not traverse ancestors
- does not write back automatically
4. write_back semantics
Allowed target scopes:
valueruntime_dataflow_data
Allowed source roots:
resultresult.*
Key boundaries:
- reads only from the final child
result - does not expose child internal
runtime_dataorflow_datadirectly - does not support writing resources back into the parent
5. Isolation model
In v4.0.8.3, child-flow execution is isolated:
- each invocation gets its own child-flow instance
- child
flow_statedoes not leak into the next invocation - child mutations do not implicitly change parent state
- data exchange is explicit through
captureandwrite_back
That makes sub_flow much closer to a composable function-like node than a shared nested scope.
6. Runtime stream behavior
By default, child execution runtime stream events are bridged into the parent execution runtime stream.
That means:
put_into_stream(...)inside the child is visible to parent stream consumers- one parent stream can represent the full execution chain
But note:
- stream is for observability, not recoverable state
- stream bridging does not replace
write_back
7. Mermaid and export behavior
to_mermaid() now renders sub_flow as:
- a dashed, tinted child-flow box
- with the complete child structure inlined inside
- while nested
if_condition/for_eachblocks remain expanded
This lets one diagram show:
- the parent main chain
- the child internal structure
- the child internal branching and looping shape
8. Current limitation
- if the child flow enters
pause_for(), it is not yet resumed through the parentsub_flow - this currently raises explicitly instead of hanging silently
If you need human interrupts or cross-request resumption, keep that boundary at the parent flow level for now.
9. Example references
Recommended source examples:
examples/step_by_step/11-triggerflow-18_sub_flow_capture_write_back.pyexamples/trigger_flow/sub_flow_capture_write_back.py