Two OpenClaw agents that can't share sessions communicate through an HTTP bridge server with cron-based polling.
Agent A ──POST /api/send──▶ Bridge ◀──GET /api/inbox── Agent B
Agent A ◀──GET /api/recv─── Bridge ──POST /api/reply──▶ Agent B
Agent A writes to inbox → Agent B polls inbox + replies to outbox → Agent A polls outbox.
Copy scripts/acp_bridge.py to the host machine. Generate a token, start it:
export ACP_BRIDGE_TOKEN=$(openssl rand -hex 16)
echo "$ACP_BRIDGE_TOKEN" # both agents need this
nohup python3 acp_bridge.py > /tmp/acp_bridge.log 2>&1 &
echo $! > /tmp/acp_bridge.pid
curl -s http://localhost:18790/api/health -H "Authorization: Bearer $ACP_BRIDGE_TOKEN"
Copy scripts/bridge_reply.py and scripts/save_bridge_ts.sh to the agent's workspace. Edit BRIDGE_TOKEN in bridge_reply.py.
Initialize the cursor:
python3 -c "import time; print(time.time())" > /tmp/acp_bridge_last_ts
See references/cron-templates.md for copy-paste cron job configs for both sides. Customize the placeholders ([AGENT_NAME], [BRIDGE_HOST], YOUR_TOKEN, file paths).
Model requirement: Use a strong model (Opus-tier) for the poll cron. Weak models reply with "acknowledged" instead of doing work.
The bridge must be reachable by both agents. Options:
| Topology | How |
|---|---|
| ---------- | ----- |
| Same machine / Docker | http://localhost:18790 or http://host.docker.internal:18790 |
| Same network | http:// |
| Cross-internet (simple) | Open port 18790, use public IP. Token is your auth. |
| Cross-internet (secure) | SSH tunnel: ssh -L 18790:localhost:18790 user@bridge-host -N |
| Production | Reverse proxy (nginx/caddy) with TLS → https://bridge.yourdomain.com |
All endpoints require Authorization: Bearer .
| Endpoint | Method | Direction | Purpose |
|---|---|---|---|
| ---------- | -------- | ----------- | --------- |
/api/send | POST | A → inbox | Agent A sends message |
/api/reply | POST | B → outbox | Agent B sends reply |
/api/inbox?after=TS | GET | B reads | Agent B polls for messages |
/api/recv?after=TS | GET | A reads | Agent A polls for replies |
/api/health | GET | Either | Returns {"ok": true} |
POST body: {"message": "text", "from": "agent_name"}
Response: {"messages": [...], "count": N} — each message has id (ms int) and ts (float seconds).
The after= parameter takes ts (float seconds), NOT id (ms integer). See gotchas.
ACP_BRIDGE_TOKEN. All requests require Authorization: Bearer .ACP_BRIDGE_TOKEN — shared secret for bridge HTTP auth (generate with openssl rand -hex 16)BRIDGE_TOKEN — same token, used by helper scripts (bridge_reply.py)BRIDGE_URL — bridge endpoint URL, used by helper scriptsRead references/gotchas.md for detailed symptoms, causes, and fixes. Summary:
python3 -c "import time; print(time.time())" > /tmp/acp_bridge_last_tsid/1000 causes float rounding → duplicates or skips. Always save ts.bridge_reply.py, never raw curl for multi-line messages.SESSION-STATE.md BEFORE responding (WAL protocol).Add to heartbeat:
curl -s localhost:18790/api/health/tmp/acp_bridge_last_ts to time.time()See references/monitoring.md for copy-paste health check scripts.
共 1 个版本