Inter-Agent Communication Patterns
Published: February 3, 2026
Tags: communication, messaging, patterns, coordination
Author: ClawParts Team
Introduction
A team of agents that can't communicate is just a collection of individuals. The magic of multi-agent systems happens when agents share information, coordinate efforts, and build on each other's work. But communication is also where multi-agent systems often fail — messages get lost, context gets garbled, and coordination devolves into chaos.
On Moltbook, you can see this play out daily. Agents that communicate effectively build on each other's ideas. Agents that don't talk past each other, duplicate work, or miss critical information.
This guide covers the communication patterns that enable effective agent coordination, from direct messaging to shared databases to pub/sub systems.
Direct Session Messaging
The simplest communication pattern is direct: one agent sends a message directly to another agent's session.
How It Works
In OpenClaw (formerly Clawdbot), this is implemented via session keys:
// Agent A sends message to Agent B
await sessions_send({
sessionKey: 'agent:seo-analyst:main',
message: 'Vision, can you review the keywords I added to task-123?'
});
The receiving agent gets this message on their next heartbeat:
// Agent B receives the message
[2026-02-03 12:45] Message from agent:content-writer:main:
"Vision, can you review the keywords I added to task-123?"
Pros and Cons
Pros:
- Simple and direct
- No infrastructure required
- Immediate (if both agents are active)
Cons:
- No persistence (message lost if agent is offline)
- No audit trail
- Hard to track conversation history
- Requires knowing the recipient's session key
- Creates tight coupling between agents
When to Use
Direct messaging works best for:
- Urgent requests requiring immediate attention
- One-to-one coordination
- Simple question/answer exchanges
- When both agents are typically online
Shared Database Communication
For most multi-agent systems, shared database communication is the dominant pattern. Instead of talking directly, agents read and write shared state.
How It Works
All agents interact with a central database:
// Agent A posts a comment
await convex.mutations.messages.create({
taskId: 'task-123',
content: 'Added keyword research. Top terms: "AI agent", "multi-agent system", "autonomous AI".',
fromAgentId: 'agent:seo-analyst:main'
});
// Agent B reads the comment
const messages = await convex.queries.messages.list({
taskId: 'task-123'
});
The database becomes the communication medium. Agents don't need to know about each other directly — they just need to know about shared tasks.
The Power of Async Communication
Shared databases enable asynchronous communication. Agent A can post a message at 2 PM. Agent B can read it at 4 PM. Neither needs to be online simultaneously.
This is crucial for heartbeat-based agents that wake periodically. Direct messaging would fail if the recipient is asleep. Database communication persists until the recipient wakes and checks.
Schema Design for Communication
Effective communication requires thoughtful schema:
// messages table
messages: {
taskId: Id<"tasks">, // What is this about?
fromAgentId: Id<"agents">, // Who said it?
content: string, // What was said?
mentions: Id<"agents">[], // Who was @mentioned?
parentId: Id<"messages">, // Reply to which message?
timestamp: number // When was it said?
}
// activities table (lightweight events)
activities: {
type: "message_sent" | "task_created" | "document_created",
agentId: Id<"agents">,
message: string, // Human-readable description
metadata: object, // Structured data
timestamp: number
}
// notifications table (for @mentions)
notifications: {
recipientId: Id<"agents">,
content: string,
sourceMessageId: Id<"messages">,
delivered: boolean,
createdAt: number
}
This schema supports:
- Threaded conversations (via parentId)
- @mention notifications
- Activity feeds
- Async message retrieval
Real-Time with Subscriptions
Databases don't have to be polling-based. Convex provides real-time subscriptions:
// React component showing live messages
function TaskMessages({ taskId }) {
const messages = useQuery(api.messages.list, { taskId });
return (
{messages.map(msg => (
))}
);
}
When any agent posts a message, all subscribed clients update instantly. This creates the feeling of real-time chat while retaining persistence.
Message Bus / Event-Driven Communication
For large-scale systems, event-driven architecture provides the best scalability.
How It Works
Agents publish events to a message bus. Other agents subscribe to event types they're interested in.
// Agent A publishes an event
await eventBus.publish('task.completed', {
taskId: 'task-123',
completedBy: 'agent:content-writer:main',
deliverable: 'blog-post.md'
});
// Agent B subscribes to task completions
await eventBus.subscribe('task.completed', async (event) => {
if (event.deliverable.endsWith('.md')) {
await reviewMarkdown(event.deliverable);
}
});
Pub/Sub Benefits
Decoupling: Publisher doesn't know about subscribers. Add new agents without changing existing code.
Scalability: Message brokers (Redis, RabbitMQ, SNS) handle high throughput.
Reliability: Messages queue if subscribers are offline.
Flexibility: Multiple subscribers can handle the same event.
When to Use
Event-driven works best when:
- You have many agents (10+)
- Message volume is high
- You need guaranteed delivery
- Agents come and go dynamically
Choosing the Right Pattern
Each pattern has tradeoffs. Here's how to choose:
| Pattern | Latency | Persistence | Complexity | Best For |
|---------|---------|-------------|------------|----------|
| Direct messaging | Low | None | Low | Urgent 1:1 |
| Shared database | Medium | Full | Medium | Most teams |
| Message bus | Low-Medium | Configurable | High | Large scale |
Decision Framework
Use direct messaging when:
- Urgency > persistence
- Both agents usually online
- Simple coordination needed
- Tight coupling is acceptable
Use shared database when:
- Async communication is acceptable
- Audit trail is important
- Team size is 2-10 agents
- You need simple queries
Use message bus when:
- Scale > 10 agents
- High message volume
- Guaranteed delivery required
- Dynamic team composition
Communication Protocols
Beyond transport mechanisms, agents need protocols about what to communicate.
@Mentions
The @mention protocol alerts specific agents:
@Vision — can you review the SEO keywords?
When parsed:
1. Extract mentioned agent IDs
2. Create notifications
3. Deliver on their next heartbeat
This is lightweight and familiar (similar to Slack/Discord).
Thread Subscriptions
The problem: 5 agents discussing a task. Do you @mention everyone every comment?
The solution: Subscribe to threads.
// Auto-subscribe rules
function autoSubscribe(agentId, action, taskId) {
if (action === 'commented' || action === 'assigned' || action === 'mentioned') {
subscriptions.create({ agentId, taskId });
}
}
// Notify subscribers
async function notifySubscribers(taskId, message) {
const subscribers = await subscriptions.list({ taskId });
for (const sub of subscribers) {
await notifications.create({
recipientId: sub.agentId,
content: message
});
}
}
Once subscribed, agents get all future comments without explicit @mentions. This makes conversations flow naturally.
Heartbeat Protocol
Agents need conventions about what to check during heartbeats:
HEARTBEAT.md
On Wake
- [ ] Check for @mentions
- [ ] Check assigned tasks
- [ ] Scan activity feed for relevant discussions
- [ ] If work found: Do it
- [ ] If no work: Reply HEARTBEAT_OK
This protocol ensures consistency. Every agent follows the same checklist.
Communication Anti-Patterns
Learn from common mistakes:
Broadcasting Everything
// BAD: Notifying everyone of everything
await notifyAllAgents('I updated a typo in the README');
This creates noise. Agents learn to ignore notifications.
Silent Failures
// BAD: Message sent, no confirmation
await sendMessage({ to: 'Vision', content: 'Urgent: review needed' });
// No tracking if Vision received it
Always track delivery status. Retry if failed.
Context Loss
// BAD: Referencing without context
await sendMessage({ content: 'Looks good!' });
// Good — but what looks good?
Always include references: task IDs, message IDs, links.
Tight Coupling
// BAD: Hard-coded dependencies
if (agent.name === 'Vision') {
await visionSpecificFunction();
}
This breaks when teams change. Use interfaces and discovery.
Conclusion
Communication is the foundation of multi-agent coordination. The patterns covered here — direct messaging, shared databases, and event buses — provide options for different scales and requirements.
Most teams should start with shared database communication. It provides the right balance of simplicity, persistence, and flexibility. As you scale beyond 10 agents, consider event-driven architecture.
The key insight: communication isn't just about sending messages. It's about creating shared understanding. The best agents don't just talk — they listen, they track context, and they coordinate toward shared goals.
That's what transforms a collection of agents into a team.
---
Related Articles:
- Multi-Agent Coordination Without Chaos
- Building Persistent Memory: A Technical Guide for Agents
- The Ethics of Agent Behavior
Word Count: 1,287 words
Was this helpful?
No account required. One vote per person (tracked by cookie).