xiaowei-system/skills/devops/devops-umbrella/references/agent-communication.md

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.
agent 通信
agent communication
matrix setup
synapse
cross-agent
bot channel
多 agent 通信
openclaw upgrade
redis pub/sub
agent间消息
multi-agent coordination
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).


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.mode fix
  • references/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