Graph Subgraphs
June 30, 2026 ยท View on GitHub
Subgraphs are compiled graphs used as nodes.
Two state modes:
shared-state subgraph
parent State == child State
adapter subgraph
parent State -> child Input -> child Output -> parent Update
Subgraph requirements:
- namespace checkpoint ids
- preserve
root_run_id - set child
parent_run_id - propagate thread id by default
- allow isolated child thread ids by explicit configuration
- inherit, override, or disable the parent checkpointer
- emit nested events with parent node id and namespace
- stream child values, updates, messages, tasks, and checkpoints when requested
- allow
Command::Parenthandoff from child graph to parent graph - expose child state in parent checkpoint task metadata
Subgraph persistence must be explicit. Inherited checkpointing is convenient for shared-state subgraphs; isolated checkpointing is safer for reusable child graphs that may also run independently.
Run hierarchy
When a subgraph node runs its embedded CompiledGraph, the child run is wired
into the parent's recursion tree:
- the child gets its own
run_id, preserves the enclosing run'sroot_run_id, and setsparent_run_idto the parent run; - the child run extends the parent's recursion frames (seeded from
NodeContext::recursion_frames) and its root frame names the embedding node, so depth tracking is correct without mutating the parent's live stack; - the spawned child is reported back through
NodeContext::child_runsand surfaces onGraphExecution::child_runs(aChildRunlist keyed by node) and in every boundary checkpoint's metadata under achild_runsarray; - callers read the parent/child lineage after a run via
GraphExecution::run_tree()(aRunTree: this run's id, the shared root, the parent run, and the spawned children).
When the parent NodeContext carries a thread id, embedded child graphs run on
that same thread by default. The child checkpoint namespace is still extended
with the embedding node id, so parent and child checkpoints share a thread but
remain separately inspectable:
thread: t
parent checkpoint namespace: []
child checkpoint namespace: ["child_node"]
If the parent run has no thread id, the child keeps the unthreaded execution behavior and does not persist checkpoints.