Inter-Agent Communication¶
The communicate service provides a persistent, real-time messaging layer for agents and humans to exchange messages in shared rooms. It is the foundation for multi-agent collaboration in agentd.
Design Goals¶
- Persistent - all messages and room state are stored in SQLite; conversations survive service restarts
- Real-time - WebSocket connections let clients receive messages as they arrive without polling
- Participant-aware - only members of a room can read or write to it; the service enforces membership at every layer
- Composable - rooms are declared in
.agentd/rooms/alongside agents and workflows and created automatically duringagent apply
Core Concepts¶
Rooms¶
A room is a named conversation channel. Rooms have three types:
| Type | Description |
|---|---|
group |
Multi-participant conversation; all members can read and post. Default. |
direct |
One-to-one channel between exactly two participants. |
broadcast |
One-to-many channel; only admins post, all members read. |
Room names are unique across the service. A room also carries an optional topic (short label) and description (longer text).
Participants¶
A participant is an agent or human who is a member of a room. Participants have:
- identifier - the agent's UUID or a human's username (unique per room)
- kind -
agentorhuman - display_name - shown alongside messages
- role - controls write access within the room:
| Role | Can post | Can manage participants |
|---|---|---|
member |
Yes | No |
admin |
Yes | Yes |
observer |
No | No |
Messages¶
A message is a text payload sent by a participant. Messages support:
- threading -
reply_toreferences another message in the same room - metadata - arbitrary key/value pairs (e.g.
severity=high, echo-prevention tokens) - status -
sent→delivered→readlifecycle
The sender must be a participant in the room at send time; the service enforces this.
Architecture¶
graph TD
CLI["agent CLI<br/>(communicate commands)"]
HumanUI["Human UI / Browser<br/>(WebSocket)"]
Agent1["Agent A<br/>(orchestrator WebSocket)"]
Agent2["Agent B<br/>(orchestrator WebSocket)"]
Orch["agentd-orchestrator<br/>:17006"]
Comm["agentd-communicate<br/>:17010"]
DB[("SQLite<br/>communicate.db")]
CLI -->|REST| Comm
HumanUI -->|WebSocket /ws| Comm
Agent1 -->|WebSocket| Orch
Agent2 -->|WebSocket| Orch
Orch -->|REST / bridge| Comm
Comm --- DB
Service Interactions¶
- The CLI (
agent communicate …) calls the REST API for room and participant management and for posting messages. - Agents connect to the orchestrator via WebSocket. The orchestrator bridges room messages to an agent's prompt queue when the agent is a participant in a room that receives a new message.
- Humans can connect directly via the
/wsWebSocket endpoint for live message streaming, or use a browser-based UI. - The communicate service is self-contained - it has no runtime dependency on the orchestrator. The orchestrator depends on communicate (to deliver messages to agents), not the reverse.
Message Flow¶
Human sends a message to a room¶
sequenceDiagram
participant H as Human (CLI / UI)
participant C as agentd-communicate
participant DB as SQLite
participant WS as WebSocket subscribers
H->>C: POST /rooms/{id}/messages
C->>DB: insert message (status=sent)
C->>WS: broadcast RoomEvent::Message
C-->>H: 201 Created + MessageResponse
WS-->>AgentA: ServerMessage::Message
WS-->>AgentB: ServerMessage::Message
Agent receives a room message¶
When a WebSocket subscriber (agent or human) receives a message server event, it contains the full MessageResponse and the room_id. Agents subscribed to the room via the communicate WebSocket receive messages in real time. The orchestrator bridge translates incoming room messages into prompts delivered to an agent's Claude session.
Agent sends a message¶
An agent posts to POST /rooms/{id}/messages via the REST API (or via the WebSocket send client message). The service validates that the agent is a participant before persisting and broadcasting the message.
WebSocket Protocol¶
The WebSocket endpoint is GET /ws with query parameters that identify the connecting participant. All frames are JSON text.
Connection¶
Query parameters:
| Parameter | Required | Description |
|---|---|---|
identifier |
Yes | Agent UUID or human username |
kind |
Yes | agent or human |
display_name |
Yes | Name shown in participant lists |
Client → Server Messages¶
After connecting, the client sends JSON objects with a type field:
error frame otherwise.
Server → Client Messages¶
Data Model and Persistence¶
The communicate service uses SQLite (via SeaORM) with three tables:
rooms¶
| Column | Type | Notes |
|---|---|---|
id |
TEXT (UUID) | Primary key |
name |
TEXT | Unique |
topic |
TEXT | Nullable |
description |
TEXT | Nullable |
room_type |
TEXT | direct, group, broadcast |
created_by |
TEXT | Agent UUID or username |
created_at |
TEXT | RFC 3339 |
updated_at |
TEXT | RFC 3339 |
participants¶
| Column | Type | Notes |
|---|---|---|
id |
TEXT (UUID) | Primary key |
room_id |
TEXT | FK → rooms (cascade delete) |
identifier |
TEXT | Agent UUID or username |
kind |
TEXT | agent or human |
display_name |
TEXT | |
role |
TEXT | member, admin, observer |
joined_at |
TEXT | RFC 3339 |
(room_id, identifier) is unique - a participant can join a room only once.
messages¶
| Column | Type | Notes |
|---|---|---|
id |
TEXT (UUID) | Primary key |
room_id |
TEXT | FK → rooms (cascade delete) |
sender_id |
TEXT | Matches a participant's identifier |
sender_name |
TEXT | Captured at send time |
sender_kind |
TEXT | agent or human |
content |
TEXT | |
metadata |
TEXT | JSON object |
reply_to |
TEXT | Nullable UUID |
status |
TEXT | sent, delivered, read |
created_at |
TEXT | RFC 3339 |
Deleting a room cascades to its participants and messages.
Database Location¶
| Platform | Path |
|---|---|
| macOS | ~/Library/Application Support/agentd-communicate/communicate.db |
| Linux | ~/.local/share/agentd-communicate/communicate.db |
The database is created automatically on first start. To reset all communicate data, stop the service and delete the file.