From Agents to Networks

The Hierarchy of Agentic Graphs

July 14, 2026

Static VS Dynamic Agentic Graphs

This is a distinction in the graph that the workflow/agent runs through. A static workflow graph is defined at the build time, and contains all of the nodes that the agent has to follow. While a a dynamic workflow is like a graph that can change and only becomes defined during the runtime.

This sequence of different types of graphs that can be defined, become increasingly more expressive, analoguous to the hierarchy that ranks the expressibility of different types of computational automata: finite automata β†’ pushdown automata β†’ Turing machines

Static Linear Chains

langgraph is used to define linear chains of LLM calls. The way in which one state goes to the next is linear, one after the other. We can also define a loop (a cycle), and create a process that keeps running until it stops.

The linear chain is the least expressive. It is just a fixed sequence of steps. In terms of expressibility it is similar to a straight-line programme. Every run does the same thing structurally regardless of input.

The moment you add a loop-until-condition, you introduce a runtime decision (keep looping vs. exit). It is now no longer a straight-line program; but a minimal finite automaton (with one state, a check, and an exit edge).

Static Graphs

It can now be that the LLM chooses how we go through the the Graph. This makes it difficult to predict which state (which node in the graph) will be processed next. But the graph itself remains well defined at build time. in a static graph you know how many (sub)agents there are defined in the graph, and you define all of them. Even though there can be a retry loop, you define the totality of the graph that the agent can go through.

Designing such a graph is like writing the software that defines a conventional process. In terms of expressibility it is like a finite automaton.

Static Graph with Recursion

A graph where a fixed, pre-defined set of nodes/subagents can call each other (including themselves) to a depth that isn't fixed at build time introduces a level of recusion of unbounded depth, but built entirely from graphs that were still defined in advance during build.

This is distinct from a flat (finite-automaton-style) graph. Because, though how long it will take to run, and what graphs it will run becomes only decided upon runtime. But all of the different components were initially defined upon build.

This is analoguous to a pushdown automaton.

Dyanamic Graphs

A dynamic workflow graph (e.g. ultracode) is defined at the runtime (not at the build).

In a dynamic workflow, there can be agents spawning new agent that were not yet defined in advance. The agent can dynamically create more dynamic sub-agents / graphs / workflows, that each can recursively spawn further sub-agents / graph / workflows.

part of a dynamic workflow is the ability to call other agents (these can either be other agent with static graphs), or spawning more dynamic graphs, both of which didn't have to exist at runtime. This process can then go on indefinitely.

This is the full Universal Turing machine case, which can reads another machine's description off its own tape and executes it. The system isn't just reusing a fixed rule set to unknown depth (that's the PDA case above); it can write new rules (new agent/workflow definitions) as data, and then executing them β€” code that writes code.

To manage the infinite recursion that can be spawned by this, we need to set up branching rules. E.g. having max 5 recursive steps deep, or max N concurrent agents running. So we can tell the root agent 'how many agents it is max allowed to create' when working on a problem.

Most practical is to build dynamic workflows, that uses static workflows as tools, to prevent it from blowing up

Where is the line between Single and Multi Agent?

Note there doesn't seem to be a clear difference in terms of expressibility between what we would call a single agent that can define subprocesses (that we might call subagents), and what we might call a multi-agent process.

A single agent with a dynamic graph already is as powerful as a full Turing machine. How then do we distinguish between a single agent, and multiple agents? is this more related to how we coordinate these processes across different multiple compute cores?

Agents as Processes

July 14, 2026

Multi Agent Orchestration

The best way to start understanding multi-agents, might be to start from an analogy of multi-processes computing.

Processes, Threats, Cores and Schedulers

A program is the static compiled binary on a disk, not running.

A process is a running instance of a program, plus all of the resources the OS allocated to it (like memory), and at least one thread. If the think of processes as Turing machines, they each have a tape (memory) and a head (pointing at the current position / next instruction to read). Each process has its own private memory space (it cannot use data outside of the allocated memory space).

A threat is like the head of a Turing machine. It keeps track of where it is in the instructions of a process, that it feeds directly into the core, one instruction at a time.

The scheduler decides which process/thread gets executed by which core and when. The scheduler decides when something runs

The cores process the instructions from each of the threats. You can define as many processes/threads as you want, but only N run simultaneously on the N cores that you have available to process the instructions from the threats.

A lock decides who's allowed to write to a shared resource right now. Or, for shared memory segments specifically, a semaphore. The general term for both is a mutual exclusion mechanism.

Agentic Analogues

We can think of programmes as Turing machines that read through the instructions on a strip. Analoguously, we can think of Agentic workflows as being defined by graphs. We then find the following parallels.

  • process β‰ˆ agent
  • threat β‰ˆ where the Agent is in a graph
  • cores β‰ˆ LLM calls
  • scheduler β‰ˆ orchestrator (decides which actions and LLM calls run now, who waits, given the LLM call budget)

Analoguously to a programme, in an LLM-based Agent, the core is replaced by an LLM. The LLM processes instructions, and returns output. To make the LLM as useful as possible in returning usable instructions, we often use structured output on the LLM, to force the output to fit into a specific schema.

Similar to the scheduler, an orchestrator (or AI Gateway ??) handles LLM calls from one (or multiple) Agents are processed on a limited concurrency budget. It orchestrates which agent runs now, which waits, in what order. Typically they handle things like "max N concurrent agents, or LLM calls".

Similar to how the threat (the head of the Turing machine) keeps track of where a process is in a programme, the Agent is in some kind of state in the graph that is defined for its workflow. Within each turn (as we go through the graph that defines the agent) we can do several actions (e.g. parallel tool calls, parallel sub-reasoning LLM calls) within a single turn in the graph, that uses the same context window.

All actions within a single turn in the graph (where the 'threat' is) share state.

Similarly to how each process is like a running instance of a Turing machine having it's own memory, each Agent has its own context window history (typically containing interaction history with a user/agent, and internal reasoning). Two agents don't share context unless something explicitly moves data between them (coordinating their access to the same database, knowledgebase, or shared scratchpad).

When two agents share the same data resources, we also need something lock-like for multi-agent processes. When two parallel tool calls (from the same step, by the same agent) both try to edit the same file, or append to the same scratchpad you get the agent equivalent of a race condition. The "lock" equivalent is some turn-taking or ownership rule over the shared resource.

Context Flow in Multi-Agent Systems

July 15, 2026

Context Flow in Multi-Agent Systems

Earlier we made the analogy of each agent's context window paying a role similar to a process's private memory. Picture the workflow graphs we discussed earlier. But now we distinguish how context window history (like output from internal reasoning LLM calls, and the chat history of interactions with the user, including output from tools called in earlier steps in the graph) is copied when we spin up new sub processes.

There seem to be three broad patterns for how context can flow through the graph.

Shared external memory.

Instead of passing context along edges at all, every process reads from and writes to the same shared resource β€” a filebase, a knowledge base, a shared stateful VM or scratchpad. Nothing is handed off; agents just look at what's already there.

All of the internal reasoning will (in this case) be written to a shared database. Which means we must think about racing conditions when all agents poentially have access to each others internal reasoning logic.

Curated handoffs.

Before a node kicks off a sub-graph, it distills the context down to only what's relevant for that specific job, and passes down that small, purpose-built package rather than everything the orchestrator has access to. Passing a small, well-defined context object rather than a full transcript is the most token-efficient option in practice, and can often work with a few hundred tokens where full forwarding would cost many thousands, which is why most frameworks default to something like it.

This pattern is also used when a chat history + reasoning steps is getting so big that it no longer fits into the context window of the LLM. We can then 'compress' it, and spawn a new agent, that tries to continue (with access to the same shared scratch pad) using the compressed context. Summarizing context between handoffs can cut token use dramatically, but at the price of losing information and adding latency for the summarization step itself.

Similarly, an orchestrator node (spinning up sub graphs) can decides how the context it holds should be compressed for each of the N subagents it spins up, and pastes the same, or non-overlapping, context to each of them. This trades less risk of a worker missing something it needed, at the cost of a bigger context window per worker.

Context Flow Management

More notes later on how this should be orchestrated

Continue reading:Orchestrating Networks