JH← Back to blog

A Plan → Execute → Synthesize Pattern for Multi-Agent Orchestration

How I structured agentix around three phases — planning, execution, and synthesis — with a pluggable agent registry and a live network graph for observability, and why single-prompt agents fall over.


Single-prompt agents fail in predictable ways: they conflate planning with execution, lose track of state across tool calls, and produce output you can't inspect until the very end. Breaking the loop into three explicit phases — Plan, Execute, Synthesize — fixes each of those. This is the design behind agentix.

Why single-prompt agents fall over

The "one big loop" agent — give a model some tools and let it reason, act, and decide all in one context — works in demos and degrades in production:

  • Context pressure. Planning, intermediate results, and tool output all pile into one window. As the task grows, the model loses the thread — the "lost in the middle" problem, where information in the centre of a long context gets ignored.
  • Hallucinated tool calls. When planning and execution are mixed, the model invents steps mid-flight that don't fit the actual plan.
  • No checkpoints. You can't inspect or correct anything until the whole thing finishes — so a wrong turn early wastes the entire run.

Separating concerns into phases gives you checkpoints, smaller per-step contexts, and a structure you can actually observe.

The three phases and what each owns

  • Planner — takes the goal and produces a structured task graph: discrete steps, their dependencies, and which agent each needs. Its only job is to decide what to do, not to do it. Output is data, not prose.
  • Executor — runs the steps. Each executor agent is single-responsibility and, where the graph allows, steps run in parallel. An executor doesn't re-plan; it does its one job and returns a result.
  • Synthesizer — assembles the executor results into the final answer, and crucially handles partial failure — composing what succeeded into a useful response rather than failing the whole run because one branch errored.

The discipline is that each phase has a narrow contract, so each can be tested, swapped, and reasoned about independently.

The pluggable agent registry design

New capabilities shouldn't require touching orchestration logic. agentix uses a registry where each agent declares a name, an input schema, an output schema, and an executor function. The orchestrator dispatches dynamically against the registry — the Planner can reference any registered agent by name, and the Executor looks it up and runs it.

Adding a new capability is therefore additive: register an agent that satisfies the interface, and the planner can immediately use it. The orchestration core never changes. This is the same separation that makes the provider-abstraction pattern work in other systems — the core speaks one contract, and capabilities plug in behind it.

Passing state between phases

State is the spine that connects the phases, so its shape matters. The Planner emits a task graph; that graph becomes the Executor's work queue; the Synthesizer receives the collected results keyed back to the plan. Keeping state explicit and treating each phase's output as an immutable hand-off (rather than a shared mutable blob everyone scribbles on) is what keeps the system debuggable — at any point you can see exactly what was planned, what ran, and what came back.

Observing it — the live network graph

Observability was a first-class requirement, not an afterthought. A log stream tells you what happened in sequence; it does not show you the structure of a multi-agent run — which steps depend on which, what's running in parallel, where a branch stalled. agentix renders the run as a live network graph: nodes are agents/steps, edges are dependencies, and state updates in real time as the run progresses. You can see a bottleneck or a failed branch at a glance, which is the kind of insight a flat log buries.

What I'd change

  • Retry semantics — the current design handles failure at the Synthesizer; smarter per-step retry with backoff before synthesis would recover more runs automatically.
  • Cost accounting per agent — attributing token/cost to each executor would make expensive branches visible and prunable.
  • Replanning — a controlled path for the Planner to revise the graph when an executor returns something that invalidates the original plan, without collapsing back into a single-loop agent.

FAQ

Why split an agent into separate planning and execution phases? To get checkpoints, smaller per-step contexts, and inspectability. Mixing them causes context pressure and hallucinated steps.

How do you add a new agent capability? Register an agent with its name, input/output schemas, and executor function. The orchestrator dispatches dynamically — no changes to the core.

What does the network graph show that logs don't? Structure: dependencies, parallelism, and where a run stalled — visible at a glance rather than reconstructed from a sequential log.