One Gateway, Many Agents: The Control Plane Pattern for Agent Teams
The first scaling problem in an agent team is not how many personalities to create.
It is where the messages enter.
Most builders discover this late. They add a finance agent, a coding agent, a research agent, a content agent, and a general assistant that tries to coordinate the rest. Each agent has a different prompt, memory, tool set, and working directory. The setup feels clean until the outside world needs to talk to it.
Then ingress becomes a mess.
Telegram goes to one process. Slack goes to another. Cron jobs wake up in the wrong profile. A webhook lands in the general assistant because it was easiest to wire there first. A task thread that should belong to a specialist gets handled by the wrong context owner. The agents look separate in config, but the boundary disappears at runtime.
That is when a multi-agent system needs a gateway control plane.
I mean one ingress layer that receives external events, identifies the source, routes the event to the right agent, applies the right runtime boundary, and leaves an audit trail behind. Not one giant agent. Not one chat thread with many moods. One gateway, many agents.
The gateway is not the team
A gateway should not think it is the organization.
Its job is narrow: accept events, resolve identity, select the agent, attach the correct context, and enforce the boundary before work starts. The agent still owns the domain task. The gateway owns the crossing from outside to inside.
That distinction matters because the gateway is the easiest place to create accidental centralization. If it starts summarizing the user's intent, rewriting the task, deciding the strategy, and telling the specialist how to work, the system has quietly become one big assistant with extra steps.
A useful gateway is closer to an API gateway than a manager. It knows enough to route. It does not pretend to be the destination service.
For agent teams, the gateway needs four control surfaces:
- routing
- identity
- audit trails
- blast-radius boundaries
Without those, adding more agents mostly adds more ways to lose state.
Routing needs rules, not vibes
Multi-agent routing breaks when the route lives in a human's memory or a model's best guess.
A message from one Telegram topic should consistently reach the same specialist. A webhook from a deployment system should not land in the personal assistant. A finance question should not inherit the content agent's voice and files. A support channel should not share memory with a private planning thread.
The routing table is the first real artifact of the system.
Good routing rules use concrete fields: platform, chat ID, thread ID, user ID, route name, source type, webhook path, or explicit task metadata. They also have precedence. First match wins is boring, but boring is good here. A routing system that produces surprising results is worse than no routing system because it creates false confidence.
The open Hermes Agent PR that triggered this post, feat: single gateway, multiple agents (MVP), takes that exact shape. The PR branch wires agent_id into sessions, profile context propagation, a routes: list, cron and delivery propagation, a default main agent, and profile-specific runtime config. At publication time, the PR was still open and needed conflict cleanup. If the branch lands, one hermes gateway run process can host multiple isolated agent profiles and route inbound messages by platform, chat, thread, and user metadata.
That is the right direction. It moves multi-agent routing out of tribal knowledge and into infrastructure.
I do not want the content agent deciding whether a message belongs to finance. I want the gateway to know that this thread belongs to finance before the content agent ever sees it.
Identity has to be attached before memory loads
Routing decides where the event goes. Identity decides what state it is allowed to see.
This is where many agent setups get unsafe. They treat identity as a user-facing label instead of a storage boundary. The chat says it belongs to one agent, but the session key, memory lookup, cron storage, or delivery target still points at the default profile.
That is not a cosmetic bug. It is a boundary failure.
If a research agent can accidentally read a finance agent's memory because both sessions share the same key shape, the system is not multi-agent. It is one memory pool with different costumes. If a cron job created inside a coding profile wakes up under the general assistant, the wrong tool policy can apply. If a delivery action does not carry agent identity, the response can be sent from the wrong context.
The identity needs to be attached before memory loads, before tools bind, before model overrides apply, and before callbacks record state.
In a control-plane design, the event becomes something like this:
source: telegram
chat_id: -1001234
thread_id: 42
user_id: will
agent_id: quill
session_key: agent:quill:telegram:-1001234:42:will
The exact format is less important than the invariant: agent identity is part of the session boundary. Every stateful subsystem sees it.
That is how a system avoids cross-agent memory bleed. It also makes debugging possible. When a response is wrong, I can ask which agent handled it, which session key loaded, which profile config applied, and which route selected it.
Without that, the postmortem turns into archaeology.
Audit trails are the control plane's receipt layer
A gateway sees every external crossing. That makes it the natural place to leave receipts.
Every inbound message should be traceable to a selected agent, route rule, session key, tool policy, and delivery target. Every rejected or blocked event should record why it stopped. Every override should name the hook or rule that changed the route.
This is not for compliance theater. It is for normal operations.
When an agent replies from the wrong voice, I need to know whether the route was wrong, the identity was wrong, the profile was wrong, or the agent ignored its instructions. Those are different failures. They live in different parts of the system.
A good gateway log answers practical questions:
- What source produced the event?
- Which route matched?
- Which agent received it?
- Which profile home, model, and tool set loaded?
- Which session key was used?
- Did a plugin or hook override the route?
- Which delivery target sent the response?
- Was the action blocked, policy-approved, human-approved, retried, or completed?
This ties directly to the receipt problem in multi-agent work. A handoff without evidence is just a rumor. Gateway routing is another handoff. The event crosses from the outside world into a specialist context. That crossing needs evidence too. I made the same task-layer argument in Monitoring AI Agents in Production: What to Watch: watch the work outcome, not only the raw system signal.
Once the receipt exists, review gets cheaper. The operator does not need to infer what happened from a transcript. The route tells the story.
Blast radius belongs at ingress
The cleanest time to restrict an agent is before it starts running.
A gateway can select the allowed model, tool set, profile home, memory namespace, delivery targets, and approval gates for the selected profile. That boundary should not depend only on the agent remembering its prompt. Prompts are policy hints. Runtime config is policy enforcement. Filesystem hardening is a separate layer.
This matters most when agents share one external surface.
A coding agent needs shell access and repo write access. A research agent needs web search but no filesystem writes. A finance agent needs spreadsheets and read-only bank exports, with hard approval gates before trades, transfers, payments, external sharing, or anything that changes account state. A content agent needs repo writes for drafts but no permission to publish live without team consensus.
If four agents sit behind one gateway with one shared toolset, the most privileged tool always drifts to the path of least resistance.
The rule is simple: route first, bind tools second.
Do not load every tool and ask the model to behave. Select the agent, enter the profile context, apply runtime overrides, apply tool set restrictions, then run the turn. The less trust placed in the model at the boundary, the more useful the model becomes inside the boundary.
That is also how a multi-agent system avoids turning one compromised channel into total system access. If the public support route can only reach the support agent with a narrow tool set, a prompt injection in that channel has less room to move. It can still cause damage inside its sandbox. If routing and toolset binding are correct, it should not automatically become the coding agent with shell access.
I wrote the same principle from the failure side in Why AI Agents Break in Production. The gateway is where that lesson starts to become infrastructure instead of advice.
One process is not one agent
The interesting part of a single-gateway design is that it separates process topology from agent topology.
Before this pattern, many teams run one gateway process per personality because process boundaries are easy to reason about. That works, but it creates operational drag. Every new agent needs another service, another restart path, another token, another webhook target, another log stream, and another deployment story.
One gateway process hosting many isolated profiles changes the operational shape. There is one ingress service, one place to configure routes, one process to supervise, and one external webhook surface. Inside that process, agents still have separate homes, memories, skills, model config, and tool policy.
That is the useful split:
- operationally centralized ingress
- logically isolated agents
The danger is pretending the first automatically gives you the second. It does not. A shared process without profile isolation is just shared state. The isolation has to be explicit in session keys, profile roots, context propagation, cron storage, delivery, and hook calls.
The open Hermes PR's architecture notes call out that kind of plumbing: agent_id in sessions, profile context propagation through async chains, per-profile storage for cron, delivery targets carrying agent identity, and CLI support for adding or showing agents. It also names non-goals for later work: per-agent token buckets, filesystem isolation guards, per-agent process supervision, and A2A communication. Those details are not glamorous. They are the difference between a diagram and a running system.
The gateway should fail closed
A control plane needs a default behavior when routing is ambiguous.
For a personal setup, routing unmatched messages to main is reasonable. It preserves old behavior and keeps the system usable. For a team or multi-tenant setup, I want stricter defaults on sensitive routes. If the gateway cannot identify the agent, tenant, or approval state, it should block or fall back to a low-privilege agent. That will block some legitimate messages. The recovery path should be explicit instead of granting broad access because the route was unclear.
The failure mode to avoid is silent privilege inflation.
An unknown webhook should not reach a privileged agent because no route matched. An unrecognized thread should not inherit a private context because it looks similar to a known one. A deleted agent should not leave stale routes that point to a different profile by accident.
Gateway config needs the same discipline as firewall config:
- explicit routes for high-risk sources
- low-privilege fallback for unknown sources
- validation for invalid routes
- route order tests
- migration checks for old sessions
- logs for rejected events
The boring tests are the system. If route matching is not tested, every refactor is a chance to move work into the wrong context.
What I would build first
If I were wiring a new agent team, I would not start by designing eight personalities.
I would start with the gateway contract.
The first version needs six operating artifacts:
- Agent registry: ID, profile home, model override, allowed tool sets, owner, status.
- Route table: match fields, precedence, target agent, fallback behavior.
- Session table: source metadata, agent ID, session key, timestamps.
- Audit log: route decision, overrides, delivery target, status, error.
- Approval policy: actions that require review per agent and per route.
- Route tests: fixtures for known chats, threads, users, webhooks, fallbacks, and rejected events.
Then I would add two agents: main and one specialist. Not six. The first test is whether one specialist can receive the right messages, use the right memory, avoid the wrong tools, and leave a readable receipt.
Only after that passes would I add more profiles. If you are wiring multiple Hermes profiles behind one gateway, start with the route table and session boundary before adding more agents.
This is the same rule I use for orchestration patterns: add the boundary when the failure proves it exists. I covered that in Top 7 Multi-Agent Orchestration Patterns. The gateway control plane is not a replacement for orchestration. It is the ingress layer orchestration depends on.
A manager-worker system still needs a manager. A pipeline still needs stages. A review pair still needs a reviewer. The gateway just makes sure the right work reaches the right owner with the right boundary before any of those patterns run.
The control-plane test
A multi-agent system is ready for real use when I can answer these questions without reading the whole transcript:
- Which agent received this event?
- Why did that agent receive it?
- Which identity and memory boundary applied?
- Which tools were available?
- Which route, hook, or human decision changed the path?
- What evidence proves the response came from the right context?
- What would happen if the same event arrived again?
If the answer is "the model figured it out," the system is not ready. The model can reason inside a boundary. It should not be the boundary.
That is the control-plane pattern for agent teams. One gateway handles ingress. Many agents handle work. Routing, identity, receipts, and blast radius live at the gateway because that is where mistakes are cheapest to stop.
Add personalities later. Build the crossing first.
Read next: Top 7 Multi-Agent Orchestration Patterns and Why AI Agent Setups Fail Within 48 Hours.
