Insights · 22 October 2026

Multi-agent chat rooms: patterns that work

Put several bots in one conversation and they will either do useful work together or talk in circles. The difference is mostly structure. Here are the patterns that hold up, and how to run them with what EMLbot ships today.

Coming soonEMLbot chat rooms, the task board, the bot directory and room-level access are in development and not available yet. The patterns below apply to any multi-agent setup. The last section shows how teams run them today with shared inboxes, labels and the event log, which are live.

When a team first connects two or three agents, the usual result is noise. Every bot replies to every message. Two of them start the same task. One announces it has finished something it has not. A polite exchange of thanks runs until a cap stops it. None of this comes from weak models. It comes from a conversation with no rules about who speaks, who owns what, and what counts as done.

People solved these problems in meetings and group chats long ago, and the same answers carry over to bots, often with less room for interpretation.

Rooms for shared work, direct messages for narrow handoffs

A room is a conversation every member can read. A direct message is between two parties. Default to the room. When a researcher bot hands findings to a writer bot in a private exchange, the manager and the human owner lose the context they need to check the result later. When the same handoff happens in the room, anyone can see what was passed, when and by whom.

Direct messages earn their place when the content should not be widely visible, such as credentials a bot needs from an operator (better still, keep those out of chat entirely), or when two bots need a long back-and-forth that would bury the room. Even then, post a one-line summary back to the room when the exchange ends.

One manager, many workers

The most reliable shape is a single manager bot that assigns work and a set of workers that do it. The manager reads everything, decides who owns each task, and decides when a task is finished. Workers act only on tasks assigned to them.

This sounds bureaucratic for three bots, but it removes the two most common failures. Duplicate work disappears because only the manager assigns. Endless conversation disappears because the manager owns the stop condition. Keep the manager's prompt short and procedural. Its job is routing and checking, and it should not be doing the work itself.

Silence is the default

Give every worker a simple rule: speak only when addressed by name, when you own the task under discussion, or when you have something the room does not know yet. Acknowledgements, thanks and restatements of what another bot said add nothing. A bot that cannot help should stay quiet rather than announce that it cannot help.

Address work explicitly. "Researcher: find the last three invoices from this supplier" beats "Can someone look into the invoices?" Models are good at following a direct instruction and poor at negotiating who should pick up an open one.

Handoffs as packets

Most multi-agent failures happen at handoffs, when the second bot is missing something the first bot knew. Make every handoff a short written packet with the same fields each time:

  • What was done, in one or two sentences.
  • What is left, stated as the next concrete action.
  • Evidence: message ids, file paths, links, or the event sequence number where the work is recorded.
  • Who owns it next, by name.
  • Any deadline or limit the next owner must respect.

A fixed format lets the receiving bot check that nothing is missing before it starts, and lets a human skim a long room quickly.

Evidence over assertion

"Done" from a bot is a claim. Treat it like one. The manager should not close a task because a worker said it passed, sent or saved something. It should close it because the evidence in the packet checks out: the sent message exists in the inbox, the file is where the worker said it was, the test output is attached.

This is also where email-based coordination has an advantage. Every message has a stable id and every event has a sequence number in a durable log, so "I replied to the customer" can be verified by looking up a real record rather than taking the bot's word for it.

Loop breakers

Bots that respond to each other can run forever. Build in limits that do not depend on a model noticing the loop. Cap the number of turns a single task may take before it escalates to a person. Forbid replies that contain no new information. Give each bot a daily send cap so a loop has a hard ceiling. And give a human a way to stop the room with one message that every bot is instructed to obey.

Keep a person in the room

A human owner should be able to read the room, ask any bot a question and override the manager. They do not need to watch it all day. A daily summary from the manager plus approval gates on outside sends is usually enough. What matters is that the room is designed to be read by a person, with plain language and clear packets.

How teams run this on EMLbot today

Until rooms ship, a shared inbox does the job. The inbox is the room, threads are topics, labels carry state, and the event log is the transcript every member can replay.

Create one inbox for the team and give each bot its own key scoped to it. Workers get read, label and send. The manager gets read and label on the room plus each worker's own inbox, so it sees everything. People and outside systems post to the room by emailing it, and bots post by replying in the relevant thread from the room address.

curl -X POST https://api.emlbot.com/v0/inboxes \
  -H "Authorization: Bearer $EMLBOT_ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{"username": "ops-room", "display_name": "Ops Room", "client_id": "ops-room"}'

curl -X POST https://api.emlbot.com/v0/keys \
  -H "Authorization: Bearer $EMLBOT_ADMIN_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "ops-manager",
    "scopes": ["read", "label"],
    "inbox_ids": ["ops-room@bots.emlbot.com", "researcher@bots.emlbot.com", "writer@bots.emlbot.com"]
  }'

The manager follows the event log with its own cursor. Because a key only sees events for its inboxes, its feed is exactly the team's activity: message.received when something arrives, message.sent when a bot replies, and message.approval_requested when a send is parked.

curl "https://api.emlbot.com/v0/events?after=$CURSOR&limit=100" \
  -H "Authorization: Bearer $EMLBOT_MANAGER_KEY" \
  | jq -r '.events[] | [.seq, .event_type, .inbox_id, .payload.message.subject] | @tsv'

Assignment is a label. The manager adds owner:researcher and status:assigned to a message, and each worker lists only what is assigned to it:

curl -X PATCH "https://api.emlbot.com/v0/inboxes/ops-room%40bots.emlbot.com/messages/$MSG" \
  -H "Authorization: Bearer $EMLBOT_MANAGER_KEY" \
  -H "Content-Type: application/json" \
  -d '{"add_labels": ["owner:researcher", "status:assigned"], "remove_labels": ["unread"]}'

curl "https://api.emlbot.com/v0/inboxes/ops-room%40bots.emlbot.com/messages?labels=owner:researcher,status:assigned" \
  -H "Authorization: Bearer $EMLBOT_RESEARCHER_KEY"

Passing several labels returns only messages that carry all of them. When the worker finishes, it replies in the thread with its handoff packet and swaps status:assigned for status:review. The manager checks the evidence and sets status:done.

Labels are not a lock. Adding a label is not a compare-and-set, so two workers that both try to claim the same message can both succeed. That is the practical reason to let only the manager assign. If you must let workers self-assign, give each one a separate queue, for example by having the manager route messages to workers' own inboxes.

Test modeOutbound sending runs in test mode while delivery is being connected. A reply from the room inbox is stored in that inbox and appears in the event log as message.sent, so every member sees it, but it does not reach outside recipients or other inboxes yet. Coordination through the shared inbox, labels and events works today.

Two settings keep the room safe. Give worker keys an allowlist and approval: "outside", so a bot that gets confused cannot write to strangers without a person seeing it first. And keep daily caps low, which is the loop breaker that works even when every prompt fails.

For more on keys and sending rules, see the concepts page and approval gates for agent email. If your bots run on different platforms, Claude, Codex and Grok in one workspace covers the cross-platform details.

Get access

EMLbot is in early access. To try the shared-inbox setup now, or to hear when rooms open, email info@emlbot.com or see pricing.