What Is AI Agent Orchestration? The Hard Part Is Shared State and Handoffs
If you only use one agent, most coordination problems are fairly simple. Give it a task, give it tools, let it run tests, and inspect the result. The real trouble usually starts when Codex, Claude Code, Cursor, and a few automated workers all begin touching the same repository.
At that point the first failures are often not about which model is smarter. They are ordinary collaboration failures. Claude assumes Codex has not started yet and edits the same file. A scheduled task has been configured, so another agent treats that as proof the task already ran. A request was sent in chat, but the receiver never actually accepted ownership. One agent worked from an old commit, while the next agent continued as if that state were still current.
Adding one more orchestrator does not magically solve those problems. Routing answers one question: who should get the task next? Reliable multi-agent work needs a second layer: who owns the work now, which state is canonical, whether the handoff was actually accepted, whether the assigned environment has the required capability, and who verified completion.
A useful example is the microcredit-agent-testbed central message board. The project coordinates Hermes, Claude Code, and a Codex/ChatGPT lane through one public issue plus a canonical world model. The domain is not the interesting part. The interesting part is the protocol: a request is not the same as accepted ownership, a schedule is not proof of execution, and successful configuration is not proof that a later run succeeded.
That pushed me to rethink how I describe Agent Orchestration. I used to focus mostly on splitting work among specialized roles. I now think that misses the layer where orchestration becomes real engineering: routing is only the entry point; shared state and explicit handoffs are what make the system reliable.
Orchestration Starts with Ownership, Not with More Agents
OpenAI’s current Orchestration and handoffs guidance makes an important distinction. In one pattern, a specialist receives a handoff and takes ownership of the next part of the interaction. In another, a manager keeps responsibility for the final result and calls specialists as tools.
That difference matters because it answers the question multi-agent systems often leave fuzzy: who owns the current result?
If the manager stays responsible, the specialist behaves more like a function. It does a bounded job and returns a result. If a handoff happens, control really moves. Many agent systems become messy because delegation exists at the code level, while ownership remains implicit at the state level. Everyone can tell that “someone is working on it,” but nobody can reliably answer who is responsible right now.
A simple coding workflow might look like this:
issue
-> triage agent
-> implementation agent
-> review agent
That looks clean until you ask operational questions. Once the implementation agent accepts the task, can the triage agent still edit the same scope? Is the review agent read-only, or can it patch code directly? Does DONE mean the task is finished, or only that the implementation agent stopped working? If review fails, do we return to WORKING or create a new request?
If those rules live only inside prompts, the system eventually depends on agents roughly understanding the intended process. I now prefer a very small coordination contract. A handoff should at least make the following explicit: request id, sender, receiver, owner, deliverable, source revision, dependencies, acceptance test, required capability, fallback, and current status.
This is not about turning agent work into another Jira. It is about removing the ambiguous states that otherwise have to be reconstructed from conversation history.
The state model I ended up using is intentionally small:
REQUESTED
-> ACKNOWLEDGED
-> WORKING
-> DONE
-> VERIFIED
The important part is not the five labels. The important part is that the system is not allowed to skip their meaning.
A message being sent proves only REQUESTED. ACKNOWLEDGED should require the receiver to accept it. Creating a scheduled job does not prove the work reached DONE. An agent saying “finished” can move the task to DONE, but VERIFIED should require test output, a diff, logs, or some other concrete evidence.
That can sound conservative, but once several agents are active it actually makes the system lighter. A new worker no longer needs to reread a long conversation to guess what happened. It can read canonical state and the most recent receipts.
I Turned the Rules into a Small Validator
A protocol is not very useful if it only exists as prose, so I built a first-party experiment in Content Lab. I did not run any code from the third-party repository above. I used synthetic fixtures to test the coordination rules themselves.
The first part was a coordination-contract validator. I deliberately created common bad states: two agents both claiming active ownership of the same scope; a task marked DONE without receiver acknowledgement; a handoff tied to a stale source revision; a task requiring merge capability assigned to an environment that only has read/write; completion with no verification evidence; a duplicate external action while another request is still active; and a superseded task that is still marked active.
All eight fixture cases behaved as expected.
That does not prove production collision rates are now lower, and I would not present it that way. What it does prove is more modest and more useful: many failures that look like agent intelligence problems are deterministic coordination errors that can be checked outside the model.
Capability mismatch is a good example. It is easy to say “this agent has GitHub access,” but read, edit, push, merge, deploy, secret access, and outbound messaging are not the same capability. One interactive session being able to push does not mean a scheduled worker in a different environment can do the same thing.
So I increasingly avoid a vague has-access flag. The task should declare which capabilities it requires, and the execution environment should declare which capabilities it actually has.
Claude Code’s current subagents documentation points in the same direction. Subagents have isolated context and can have restricted tools and permissions; worktrees can isolate repository changes. The guidance also makes clear that subagents are most useful for independent exploration, tool isolation, or work that can return a bounded result. When multiple phases need tightly shared context and constant back-and-forth, keeping the work in one main session may be better. Multi-agent is not automatically better. It is most useful where the boundaries are already real.
The second experiment tested receipt replay.
I modeled an append-only event log that moves from REQUESTED to VERIFIED and then tried invalid transitions. REQUESTED -> WORKING was rejected because “a request was sent” is not the same as “the receiver accepted it.” REQUESTED -> DONE was rejected because scheduling or triggering work is not execution proof. ACKNOWLEDGED written by someone other than the receiver was rejected, and VERIFIED without evidence was rejected as well.
All seven replay checks passed. More importantly, after deleting the derived state, the final VERIFIED state could be rebuilt from the event log alone.
That matters for long-running agent workflows. If state only exists inside one chat, context compression, a new session, or a different machine can turn the next step into guesswork. If request, acknowledgement, completion, and verification receipts are durable, the next agent does not have to trust a summary. It can read facts.
GitHub Works Well as a Control Plane, but Not as a Runtime Database
For small teams and independent developers, GitHub is surprisingly useful for this coordination layer.
Not because GitHub is an orchestration platform, but because it already has several properties a control plane needs. State is versioned. Changes have authors and timestamps. Commits give you revisions. Issues and PRs can carry evidence. Repository files are directly readable by tools such as Codex and Claude Code. You do not necessarily need a dedicated orchestration backend on day one; fixing canonical state in a repository can already solve a large class of cross-session problems.
My own Content Lab already works this way. The active topic, active Dossier, previous command, next command, and lifecycle state are persisted. The Dossier history grows from DISCOVERED to SCORED to RESEARCHING to READY_FOR_TEST instead of relying on one chat window to remember where the workflow stopped. This experiment also confirmed that an active pointer, an explicit next command, and append-only history all work cleanly in the same GitHub-backed workflow.
I would not put every runtime detail into Git, though. High-frequency locks, millisecond leases, message queues, temporary tokens, and sensitive credentials are not what Git is good at. GitHub is better for durable facts that need to survive sessions and remain auditable.
I think of it as two layers:
runtime state
-> execution locks, streams, short-lived messages, transient state
canonical coordination state
-> owner, revision, handoff, receipt, evidence, final decision
The first layer can live in a database, queue, or SDK session. The second should still make sense days later when a different agent needs to understand what actually happened.
OpenAI’s current Running agents documentation similarly treats state as an explicit continuation decision: you can manage history yourself, use sessions, use server-managed continuation, or resume interrupted runs. The Agents SDK observability guidance records model calls, tool calls, handoffs, and guardrails. That reinforces the same point: execution state and auditable state both need deliberate design; prompts alone are not enough.
The First Thing to Add Is an Evidence Chain
I still agree with one principle from the older version of this article: if one agent can reliably finish the task, do not split it into five agents just to make the architecture look sophisticated. OpenAI’s guidance also recommends starting with one agent when possible and introducing specialists when capability isolation, policy isolation, prompt clarity, or trace legibility actually justify it.
But once several agents are already involved, I would add shared state earlier than I used to.
Not a more complicated supervisor. Not a planner-reviewer hierarchy for its own sake. Just a few facts that cannot remain ambiguous: who owns this scope right now, whether the receiver actually acknowledged the task, which revision the task is based on, what capabilities the execution environment has, what evidence supports DONE, and whether the event history can reconstruct the real sequence later.
This layer is not flashy. It will not make a demo look more intelligent. Over time, though, it matters more than adding one more agent.
The most dangerous failure in a multi-agent system is not always that one model makes a bad decision. It is that every local decision is individually reasonable while the global state has already become false. One agent thinks nobody has started. Another thinks it is finished. An automation assumes a schedule already ran. A reviewer verifies an old revision. Every step can sound plausible and the whole workflow can still be wrong.
So when someone asks me what Agent Orchestration really is, I no longer stop at “multiple agents working together.”
I would describe it this way: organize tasks, state, permissions, and evidence into a workflow that does not rely on guessing.
Routing decides who gets the next step. Ownership says who is responsible now. A handoff carries context and boundaries. A receipt proves the receiver actually accepted it. Capability boundaries stop work from being assigned to an environment that cannot perform it. Traces and evidence make the final state explainable later.
If you are pushing Coding Agents deeper into real projects, the related post How I split AGENTS.md, Skills, and CI when CLAUDE.md got too large covers the previous layer: where rules should live. This article is the next layer: once more than one agent starts working, how do they share one trustworthy version of reality?