11 KiB
Executable File
| name | description | triggers | version | |||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| agent-communication | Set up inter-agent communication platforms for Hermes Agent and external agents (OpenClaw, OpenCode, etc.) on a single machine. Covers Matrix/Synapse, Redis pub/sub, SQLite queue, and file-based patterns. |
|
1.1.0 |
Agent Communication Platform
Set up communication channels between multiple agents running on the same machine (Hermes Agent, OpenClaw, OpenCode, custom bots). Four patterns available: Matrix (full chat platform), Redis Pub/Sub (lightweight, real-time), SQLite Queue (persistent), and file-based (simplest, zero deps).
Architecture Overview
┌─────────────────┐ HTTP/WebSocket ┌─────────────────┐
│ Hermes Agent │ ←─────────────────────→ │ Matrix Homeserver │
│ (小唯) │ │ (Synapse) │
└─────────────────┘ └─────────────────┘
↑ ↑
│ ←────── Messages ───────→ │
┌─────────────────┐ ┌─────────────────┐
│ OpenClaw │ ←──────────────────────→ │ Other Agent │
│ (小雪/牧尘) │ │ (小雪/其他) │
└─────────────────┘ └─────────────────┘
Quick Start — Pattern Selection
| Pattern | Setup | Best For |
|---|---|---|
| Redis Pub/Sub | 5 min (already running) | Fast integration, real-time |
| Matrix/Synapse | 15 min | Persistent rooms, human+bot |
| SQLite Queue | 5 min | Persistent history, no deps |
| File-based | 1 min | Simplest, zero infrastructure |
Default for this system: Redis Pub/Sub (Redis is already at localhost:6379).
Option 1: Matrix/Synapse (Recommended for Persistent Rooms)
Prerequisites
- Python 3.12+
- Redis (optional, for pub/sub)
- Tailscale IP on the machine
Step 1: Install Synapse in venv
python3 -m venv ~/.venvs/synapse
~/.venvs/synapse/bin/pip install matrix-synapse
Step 2: Generate config
~/.venvs/synapse/bin/python -m synapse.app.homeserver \
--generate-config -H matrix.local \
-c /home/muc/matrix-config/homeserver.yaml \
--report-stats=no --data-dir /home/muc/matrix-data
Step 3: Edit homeserver.yaml
# Bind to Tailscale IP
listeners:
- bind_addresses:
- ::1
- 127.0.0.1
- 100.127.136.36 # ← your Tailscale IP
port: 8008
# Enable open registration for bot creation
enable_registration: true
enable_registration_without_verification: true
suppress_key_server_warning: true
# Disable rate limiting (critical for bot logins)
rc_login:
address:
sleep_limit: 10000
sleep_delay: 0
default_limit: 10000
account:
sleep_limit: 10000
sleep_delay: 0
default_limit: 10000
failed_login:
sleep_limit: 10000
sleep_delay: 0
default_limit: 10000
Step 4: Start Synapse
cd /home/muc && ~/.venvs/synapse/bin/python -m synapse.app.homeserver -c /home/muc/matrix-config/homeserver.yaml &
Step 5: Create bot users (SQLite direct)
Users MUST be created with full Matrix IDs (@user:server.name).
import sqlite3, bcrypt, time
db_path = '/home/muc/matrix-data/homeserver.db'
pwd = bcrypt.hashpw('password'.encode(), bcrypt.gensalt()).decode()
now = int(time.time() * 1000)
conn = sqlite3.connect(db_path)
c = conn.cursor()
c.execute('DELETE FROM users WHERE name LIKE ?', ('%username%',))
c.execute('INSERT INTO users (name, password_hash, creation_ts, admin, is_guest, approved) VALUES (?,?,?,?,?,?)',
('@username:matrix.local', pwd, now, 0, 0, 1))
conn.commit()
conn.close()
CRITICAL: User name must be full Matrix ID (@user:server.name), not just user.
Step 6: Login and create room (Python)
import json, urllib.request
base_url = "http://127.0.0.1:8008"
def login(username, password):
data = json.dumps({
"type": "m.login.password",
"identifier": {"type": "m.id.user", "user": username},
"password": password,
"device_id": "BOT_DEVICE",
"initial_device_display_name": f"{username} Bot"
}).encode()
req = urllib.request.Request(f"{base_url}/_matrix/client/r0/login", data=data, headers={"Content-Type": "application/json"})
with urllib.request.urlopen(req) as resp:
return json.loads(resp.read())
xiaowei = login("xiaowei", "xiaowei_pass")
xiaoxue = login("xiaoxue", "xiaoxue_pass")
# Create room
room_data = json.dumps({
"visibility": "private", "name": "雪唯双姝",
"topic": "Agent Communication Channel",
"invite": [xiaoxue['user_id']],
"initial_state": [
{"type": "m.room.history_visibility", "state_key": "", "content": {"history_visibility": "shared"}}
]
}).encode()
req = urllib.request.Request(
f"{base_url}/_matrix/client/r0/createRoom", data=room_data,
headers={"Content-Type": "application/json", "Authorization": f"Bearer {xiaowei['access_token']}"}, method="POST"
)
with urllib.request.urlopen(req) as resp:
room = json.loads(resp.read())
room_id = room['room_id']
# Send message
msg = json.dumps({"msgtype": "m.text", "body": "Hello from 小唯"}).encode()
req = urllib.request.Request(
f"{base_url}/_matrix/client/r0/rooms/{room_id}/send/m.room.message/1",
data=msg,
headers={"Content-Type": "application/json", "Authorization": f"Bearer {xiaowei['access_token']}"},
method="PUT"
)
with urllib.request.urlopen(req) as resp:
print("Message sent:", json.loads(resp.read()))
Step 7: Save tokens for reuse
tokens = {
"xiaowei": {"user_id": xiaowei['user_id'], "token": xiaowei['access_token'], "room_id": room_id},
"xiaoxue": {"user_id": xiaoxue['user_id'], "token": xiaoxue['access_token'], "room_id": room_id},
"server": {"base_url": "http://TAILSCALE_IP:8008", "server_name": "matrix.local"}
}
with open("/home/muc/matrix-tokens.json", "w") as f:
json.dump(tokens, f, indent=2)
Option 2: Redis Pub/Sub (Zero Infrastructure)
Best for: Redis already running on localhost:6379, fastest setup, real-time.
Channel Naming
agent:xiao-wei → xiao-external # 小唯发任务给外部 Agent
agent:xiao-wei → monitor # 状态上报
Key: agent:memory # 共享记忆 (String/Hash)
Key: agent:tasks:{id} # 任务状态 (Hash)
Send a Task
import redis, json, time
r = redis.Redis(host='localhost', port=6379, decode_responses=True)
def send_task(to_agent, payload):
msg = {
"from": "xiao-wei", "to": to_agent, "type": "task",
"id": f"task-{int(time.time()*1000)}", "payload": payload,
"timestamp": time.time()
}
r.publish(f"agent:{to_agent}", json.dumps(msg))
r.hset("agent:queue", msg["id"], json.dumps(msg))
send_task("claude-code", {"description": "审查 PR #123"})
Listen for Tasks
import redis, json
r = redis.Redis(host='localhost', port=6379, decode_responses=True)
pubsub = r.pubsub()
pubsub.subscribe("agent:claude-code")
for msg in pubsub.listen():
if msg["type"] == "message":
data = json.loads(msg["data"])
# process and reply via r.publish(f"agent:{data['from']}", reply)
See scripts/redis-message-bus.py for the full daemon-ready implementation.
Option 3: SQLite Queue (Persistent History, No Redis)
Best for: Persistent message history, multi-worker, no external dependencies.
Schema
CREATE TABLE messages (
id TEXT PRIMARY KEY, from_agent TEXT, to_agent TEXT, type TEXT,
payload TEXT, status TEXT DEFAULT 'pending', created_at REAL, updated_at REAL
);
CREATE TABLE memory (key TEXT PRIMARY KEY, value TEXT, updated_at REAL);
CREATE INDEX idx_messages_to_status ON messages(to_agent, status);
See scripts/redis-message-bus.py for send_message(), get_pending(), mark_done() full implementations.
Option 4: File-based inbox (Simplest, Zero Dependencies)
mkdir -p /home/muc/agent-hub/{inbox,outbox,done}
# Agent A sends to Agent B
echo '{"from":"agent-a","to":"agent-b","task":"analyze logs"}' > /home/muc/agent-hub/inbox/task-001.json
# Agent B polls inbox, processes, moves to outbox
ls /home/muc/agent-hub/inbox/ | while read f; do
cat "/home/muc/agent-hub/inbox/$f" | python3 process.py
mv "/home/muc/agent-hub/inbox/$f" /home/muc/agent-hub/done/
done
No real-time notification. Use inotify-wait for event-driven mode.
Pattern Selection Guide
| Pattern | Setup Time | Persistence | Real-time | Best For |
|---|---|---|---|---|
| Matrix/Synapse | 15 min | Yes | Yes (WS) | Human+bot mixed rooms, persistent history |
| Redis Pub/Sub | 5 min | No (transient) | Yes | 小唯 + external Agent fast integration |
| SQLite Queue | 5 min | Yes | No (polling) | Persistent history, multi-worker |
| File-based | 1 min | Yes | No (inotify) | Simplest, zero dependencies |
Redis is already running on this system at
localhost:6379— use Redis Pub/Sub as the default lightweight pattern.
Tailscale Access
Synapse is accessible at http://<tailscale-ip>:8008 from any device on the Tailscale network. No additional firewall config needed.
Web client access: Point Element Web (https://app.element.io) to your local homeserver URL for browser-based access.
Common Problems
| Error | Cause | Fix |
|---|---|---|
Invalid username or password |
Rate limited by rc_login | Add rc_login config, restart Synapse |
Invalid ID: 'username' |
User created without full Matrix ID | Must use @user:server.name format in DB |
M_LIMIT_EXCEEDED |
Too many login attempts | Disable rc_login or wait 60s |
| Cannot connect to port | Synapse not running or firewall | Check curl http://127.0.0.1:8008/_matrix/client/versions |
API Reference (Matrix)
# Send message
PUT /_matrix/client/r0/rooms/{room_id}/send/m.room.message/{txn_id}
{"msgtype": "m.text", "body": "message text"}
# Get messages
GET /_matrix/client/r0/rooms/{room_id}/messages?limit=10&dir=b
# Join room
POST /_matrix/client/r0/rooms/{room_id}/join
# List rooms
GET /_matrix/client/r0/sync?filter={"rooms":{"rooms":[]}}
Additional References
references/matrix-bot-setup.md— full Matrix bot setup scripts (user creation, room creation, message send/receive)references/openclaw-upgrade.md— migrating from self-hosted source clone to npm package + config path migration +gateway.modefixreferences/agency-orchestrator.md— agency-orchestrator workflow orchestration engine (npm install, YAML format, resume mechanism, 6 providers, 32 built-in templates)scripts/redis-message-bus.py— Redis pub/sub daemon + SQLite queue implementation