Lesson 02 · Foundations · 12 min
Nodes and edges
A graph runtime is smaller than its reputation. Visit a node, run it, update state, choose an outgoing edge, repeat until you reach an end node or run out of steps. The version powering this lab is about a hundred and twenty lines.
while (current && steps < maxSteps) {
const node = graph.nodes.find((n) => n.id === current);
await runNode(node, state);
const outgoing = graph.edges.filter((e) => e.from === node.id);
const next = node.kind === "router"
? outgoing.find((e) => matches(e.when, state)) ?? outgoing.find((e) => !e.when)
: outgoing[0];
current = next?.to ?? null;
}Worth knowing before adopting a framework: most of what they add is ergonomics, typing and persistence rather than a different execution model. Understanding the loop above means you can read what a framework is doing and decide whether you need it.
Four node kinds cover most workflows. An llm node calls a model. A tool node calls a function. A router node reads state and picks an edge. An end node stops. This lab adds a fifth, interrupt, covered in lesson 5.
The step limit matters as much as it does in a loop. A graph with a cycle and no ceiling has the same failure mode as an unbounded loop, and the fix is identical.
Checkpoint
Trace one run and write down the sequence of node ids it visited.