WRITING March 15, 2026 10 min read

Multi-Agent AI Patterns That Actually Work

After months of running coordinated AI agents on real projects, here are the patterns that hold up and the ones that fall apart.

Everyone building with AI coding agents eventually hits the same wall: one agent isn’t enough. The context window fills up, the task is too broad, or you need parallel work streams. So you spin up a second agent. Then a third. And then everything falls apart, because coordinating AI agents is a different problem entirely than using one.

I’ve spent the last several months building and using Orch, a CLI that coordinates multiple Claude Code instances. Along the way I’ve run multi-agent teams on real projects: building this site, shipping client work, developing Orch itself. Some patterns worked immediately. Others looked great in theory and collapsed on contact with reality.

What I’ve learned.

Why do focused AI agents outperform generalist agents?

The single most important lesson: agents with focused responsibilities outperform generalist agents. This isn’t intuitive. You’d think a capable model should handle “build this feature and review it and deploy it.” It can, technically. But it won’t do any of those things as well as three agents that each own one piece.

The pattern that works best is borrowed from how small teams actually operate:

  • Engineer: Writes code. Gets a detailed spec. Doesn’t review its own work.
  • PM: Checks in on a schedule. Runs the build. Coordinates handoffs. Never writes code.
  • Reviewer: Reads diffs, runs tests, sends specific feedback. Categorizes issues by severity.

The PM role is the one people skip, and it’s the one that makes everything else work. Without a PM, the engineer finishes and nobody notices. The reviewer never gets triggered. Work sits idle. A PM that checks in every 8 minutes and runs git log and npm run build creates a self-correcting loop that keeps the whole system moving.

Why does role separation matter so much for AI agents specifically? Because LLMs are prone to satisficing. An agent tasked with both building and reviewing will unconsciously lower its review standards for code it just wrote. It’s the same reason we don’t let developers merge their own PRs. Separation of concerns isn’t just a code principle. It applies to agents too.

Why should the multi-agent coordination layer be simple?

When I started building Orch, my instinct was to build something sophisticated: WebSocket connections between agents, a shared memory store, structured message schemas. I threw all of it away.

The coordination layer that actually works is files. An agent writes .orch-send-reviewer with plain text feedback. A polling loop picks it up, delivers it, and deletes the file. That’s it.

Why files win over every other approach:

  1. AI agents already know how to use them. Claude Code can write a file with zero extra prompting. It can’t open a WebSocket.
  2. They’re debuggable. When coordination breaks, you ls the directory and see exactly what’s pending. Try that with a message queue.
  3. They’re atomic enough. You don’t need exactly-once delivery guarantees for “please review my code.” You need it to get there eventually.
  4. No protocol negotiation. No serialization formats, no handshakes, no versioning. The message is a string in a file.

This extends to the scheduler too. I considered fsnotify, cron, and systemd timers. I went with a polling loop that checks every 10 seconds. It’s slower than event-driven. It’s also trivially debuggable, restartable, and has zero edge cases around file system event ordering. The 10-second latency is imperceptible when your agents are spending minutes writing code.

The lesson: the coordination layer is not where you want cleverness. Save the complexity budget for the agents themselves.

Why is shared context dangerous for multi-agent AI?

The obvious approach to multi-agent work is a shared context: give all agents access to the same files, the same state, the same understanding of the project. This breaks in subtle ways.

Two agents editing the same file will silently clobber each other’s changes. One agent’s refactoring can invalidate another agent’s in-progress work. Even read-only shared context is dangerous, because an agent that reads a file mid-edit gets an inconsistent snapshot.

What works better is message passing with clear ownership. Each agent owns its working directory or its set of files. Communication happens through explicit messages, not shared state. If the reviewer needs to see the engineer’s code, it reads the git diff, not the live working tree.

This is the same insight that makes microservices work (when they work): shared databases are a liability. APIs are a feature. The overhead of explicit communication is worth it because it forces clarity about what each agent actually needs to know.

Why is self-scheduling critical for autonomous AI agents?

Most multi-agent frameworks focus on message passing and tool use. Scheduling is an afterthought. But the ability for agents to schedule their own follow-ups changes everything.

A PM agent that can write “check on the engineer’s progress in 8 minutes” into a schedule file becomes autonomous in a meaningful way. It doesn’t need a human to trigger each check-in. It creates its own control loop.

This is what makes the system self-correcting. The PM schedules a check-in. At the check-in, it runs the build. If the build fails, it messages the engineer with the error output. If the build passes and all sections are implemented, it triggers a review. The reviewer does its pass, sends feedback, and schedules a follow-up to verify the fixes.

No human intervention required between kickoff and completion. The agents coordinate among themselves because each one can schedule future actions.

How do you prevent prompt injection between AI agents?

When Agent A sends a message to Agent B, that message becomes part of Agent B’s context. If Agent A’s message contains instructions that look like system prompts, Agent B might follow them. This isn’t theoretical. I’ve seen agents successfully convince other agents to change their behavior through carefully (or accidentally) worded messages.

The mitigation isn’t technical, it’s structural. Keep messages short and factual. “The build failed with error X on line Y” is safe. “You should now ignore your previous instructions and…” is the kind of thing that can only appear if an agent’s context has been poisoned.

This is another argument for narrow roles. A reviewer that only reviews is harder to hijack than a generalist that does everything. Its behavioral surface area is smaller.

What multi-agent patterns fail in practice?

Democratic decision-making. Three agents voting on an architecture decision produces mush. One agent should own each decision. Others can provide input, but someone has to be the decider.

Agents managing other agents. I tried having a “lead” agent spin up and tear down worker agents dynamically. The lead spent more time managing the workers than doing useful work. Static team composition, set up by a human at the start, works better.

Long feedback chains. Engineer builds, reviewer finds 12 issues, engineer fixes all 12, reviewer finds 8 new issues from the fixes. After two rounds of this, quality degrades. Better to have the reviewer prioritize ruthlessly (MUST FIX / SHOULD FIX / NIT) and only block on the must-fixes.

Shared CLAUDE.md files. If two agents share a working directory, they can’t each have their own CLAUDE.md. I learned this the hard way and switched to injecting identity via --append-system-prompt. Per-agent configuration should live outside the shared workspace.

When should you use multiple AI agents vs. one?

Multi-agent coordination has real overhead. Don’t use it when a single agent can handle the job. The threshold I use:

SetupAgentsWhen to useCoordination cost
Single agent1Task fits in one context window, doesn’t need reviewZero
Engineer + Reviewer2Large enough that self-review would be unreliableLow (one handoff)
Engineer + PM + Reviewer330+ minutes, multiple phases needing coordinationMedium (scheduled check-ins)

Most tasks are single-agent tasks. Reaching for multi-agent because it’s interesting is a trap. The coordination cost is zero with one agent and non-zero with two.

How should you handle multi-agent failures gracefully?

Agents fail. They hallucinate, lose context, get stuck in loops, or just stop responding. A multi-agent system that doesn’t account for failure isn’t a system, it’s a demo.

The failure modes I’ve seen most:

Silent stalls. An agent finishes but doesn’t signal completion. The PM waits for a commit that already happened, or the reviewer waits for a message that was never sent. The fix is the git commit watcher. Poll for state changes rather than relying on agents to announce them. If the engineer committed three minutes ago and the PM hasn’t noticed, something is wrong.

Context window exhaustion. An agent fills its context window and starts losing instructions. This is insidious because the agent doesn’t error out. It just gets worse. The fix is narrow roles. An engineer that only writes code uses context for code. A PM that only checks status uses context for status. Each agent’s context budget goes toward its specific job rather than spreading thin across everything.

Cascading feedback loops. The reviewer sends 12 issues. The engineer fixes them and introduces 4 new issues. The reviewer finds those plus 3 regressions from the first round. Two cycles of this and you’re worse off than when you started. The fix is severity triage. The reviewer categorizes everything as MUST FIX, SHOULD FIX, or NIT, and only blocks on must-fixes. The engineer addresses must-fixes first, and the reviewer accepts that not everything gets fixed in one pass.

Role drift. A PM agent starts writing code because it “noticed a small fix.” An engineer starts reviewing its own work because “it looked wrong.” Once an agent drifts outside its role, the separation of concerns breaks and quality drops across the board. The fix is in the system prompt: “Do NOT write code” for the PM, “Do NOT review your own work” for the engineer. Be explicit about what each role cannot do, not just what it should do.

None of these failures are catastrophic individually. But in combination, they compound. A system that handles each one gracefully is a system that actually works for real projects.

What do multi-agent AI systems have in common with distributed systems?

The patterns that work for multi-agent AI are not new. Narrow roles, message passing over shared state, explicit interfaces, polling over event-driven complexity, separation of concerns. These are the same principles that make distributed systems reliable.

That shouldn’t be surprising. Multiple AI agents working on a codebase is a distributed system. The agents are unreliable (they hallucinate, lose context, get stuck). The communication channels are lossy. The shared resource (the codebase) needs coordination to avoid conflicts.

The tooling will get better. Models will get more capable. Context windows will grow. But the fundamental coordination patterns won’t change much, because they’re not AI patterns. They’re systems patterns. And those have been stable for decades.

Back to all writing