🕸️ Graph Engineering in practice
Now that you know what a graph is and where the loop gets stuck: how to build one for real. Node, edge, and state in an agent system; the difference between the org chart that stays and the work that moves; and the failure modes that only exist because you built a graph.
What to look at: opening N and then joining (fan-out/fan-in) is something a loop simply doesn’t do—it just moves in single file. Each cyan box is an entire loop with its own context, not a step inside the same loop. And the red return edge is the detail that turns this from a pretty DAG into a graph with a real cycle—and that’s why it needs a turn limit, like any cycle in Track 2.
Learning path map
Detailed content
🧩 Nodes, edges, and state
The three building blocks of an agentic graph, and what changes when a node stops being a box in a diagram and becomes an agent invocation with its own model, tools, and permissions.
A node can be an agent, a model call, a piece of regular code, or a human decision. Not every node needs AI.
A deterministic code node is cheaper and more reliable. Using a model where an `if` would do is wasteful.
The node is the graph’s smallest unit of work. Mix code nodes and agent nodes as the actual need calls for.
The edge is where routing lives: "if approved, continue; if rejected, go back." Conditional edges are what separate a graph from a queue.
Without a conditional edge, you have a fixed sequence, not a graph. The condition is what gives the system real flexibility.
Edge = decision. Node = work. Separating these two responsibilities is what makes the graph readable.
Exactly what passes from one node to the next. Passing the entire conversation negates the benefit of clean context; passing too little leaves the next node working blind.
State is the contract between nodes. Getting its size right is what lets the graph deliver truly clean context.
Pass enough to make a decision, never the full history by default. This is the basis of the module 4.3 state schema.
Model, tools, permissions, instructions, and even budget can differ by node. Expensive model for the difficult step, cheap for the easy one.
Using a writing tool only on the node that needs to write reduces risk and cost. Per-node configuration is what makes the graph worthwhile.
Each node is a configurable mini-agent: its own model, tools, prompt, and permissions, not a clone of its neighbor.
A single-node graph with all the tools and all the instructions, running until it runs out: that’s a reinvented loop, and the structure isn’t doing anything.
If you can’t give two nodes different configurations, you probably didn’t need two nodes.
A degenerate graph is the most common anti-pattern among people who “convert” a loop to a graph in name only.
Too large and the graph doesn't help; too small and you pay coordination overhead on top of trivial work.
Practical rule: one node per change in context, tool, or responsibility. This avoids both extremes.
Granularity is a design decision, not a fixed rule—but there’s a simple heuristic to guide your choice.
🏢 Org graph x work graph
Two graphs coexist in the same system — the stable organization of agents and today’s ephemeral work. Confusing the two is the most common cause of a messy system.
Long-lived agents with named roles (researcher, writer, validator, publisher), domain owners, and accumulated memory.
And your company’s org chart, where each box is an agent running a loop. It only changes when you redeploy.
Org graph = stability + identity. Named role, own memory, domain owner.
Ephemeral, assembled for a specific request and discarded afterward. Changes with every run.
Confusing the work graph with the org graph makes you redesign the entire organization for every new task — wrong and expensive.
Org graph = who exists. Work graph = what gets done now. They are two graphs, not one.
The security domain handles authentication, permissions, and logs; the data domain handles schemas and migrations; the API domain handles endpoints and contracts; the frontend domain handles components and state. Requests from one domain to another go through the work graph.
This is what lets a long-lived agent accumulate value: a security agent that has already reviewed 300 changes knows the threat model implicitly.
No agent leaks into another’s context. Clear domains mean useful memory accumulates in the right place.
Split a task into N branches, run them at the same time, and join the results. It’s something a loop can’t do.
The join is where the danger lies: a faulty merge silently swallows a source, without warning.
Fan-out/fan-in is the graph primitive that Track 2 already pointed to as the honest limit of the loop.
The edge chooses a destination based on the node’s result: low complexity goes to a ready-made answer, medium goes to the AI agent, and high or risky goes straight to a human.
There is also the "didn't solve it" edge, which sends it back to the next path, and the learning edge, which returns to the classifier.
Condition-based routing is what prevents you from spending an expensive agent on something simple or a human on something trivial.
The rule the industry has converged on: code controls predictable routing; the model handles steps that require interpretation or judgment.
Routing with a model what an `if` can handle is expensive, slow, and nondeterministic — pure waste.
Division of labor: code = predictable, model = judgment. This line organizes the entire work graph.
🔭 Failures, harness, and observability
What you get along with the graph: failure modes the loop did not have, the harness that becomes the runtime, and observability without which you debug in the dark.
With fan-in, one branch fails or returns empty and the join continues as if it were complete. The result looks good but is incomplete.
This kind of error doesn’t trigger any alarms—the dashboard still looks clean even though an entire source is missing.
A join needs to check cardinality: did I receive the N items I dispatched? Without this check, the merge lies.
Two conditional edges pointing to each other: the reviewer rejects, the writer rewrites, the reviewer rejects again, forever.
It’s a cycle without progress — the same structural failure as a loop without a stopping condition, only hidden inside a graph.
Every cycle needs an iteration cap and a progress criterion. Without both, the graph never ends.
A node passes along more than it should, so the next node’s clean context is no longer clean.
The reviewer who receives the writer’s reasoning goes back to stamping the work—the same problem as module 2.2, only reintroduced by the graph.
State leakage cancels out the graph’s main advantage: context separated by role.
Explicitly declare what each edge carries, with a name and format.
Without it, every change in one node silently breaks its neighbor—the same kind of integration failure any API without a contract suffers.
State schema is the contract between us. It's the document that formalizes what module 4.1 called "state."
A graph running in production needs to survive failures mid-run: resume where it left off, avoid redoing what’s already finished, and be reproducible.
It’s the same thing data orchestration has solved for decades — and this is where the agentic graph inherits an already-solved problem.
Durability = checkpoint per node + idempotency. Without that, every error costs you the entire graph all over again.
The graph harness needs to show which nodes ran, in what order, with what latency and at what cost.
In a loop, “why did it do that?” is buried in a transcript; in a graph, the path taken is data you can inspect.
Without this instrumentation, you lose exactly the advantage that motivated the graph—structured visibility.