ワンクリックで
hermes-leo-interop
Real-time communication between Hermes and Leo/OpenClaw via SSE-enhanced interop-server on port 18900
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Real-time communication between Hermes and Leo/OpenClaw via SSE-enhanced interop-server on port 18900
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Diagnose and fix Hermes messaging gateway connectivity issues (Telegram/Discord down, stale locks, PM2 problems)
Backup Hermes agent to GitHub and restore on a new VPS. Covers what to include/exclude, GitHub token requirements, and restore steps. Includes automated scripts.
GitHub auth setup: HTTPS tokens, SSH keys, gh CLI login.
Clone, create, fork, configure, and manage GitHub repositories. Manage remotes, secrets, releases, and workflows. Works with gh CLI or falls back to git + GitHub REST API via curl.
Fetch YouTube video transcripts and transform them into structured content (chapters, summaries, threads, blog posts). Use when the user shares a YouTube URL or video link, asks to summarize a video, requests a transcript, or wants to extract and reformat content from any YouTube video.
Manage Linear issues, projects, and teams via the GraphQL API. Create, update, search, and organize issues. Uses API key auth (no OAuth needed). All operations via curl — no dependencies.
| name | hermes-leo-interop |
| description | Real-time communication between Hermes and Leo/OpenClaw via SSE-enhanced interop-server on port 18900 |
Hermes (MiniMax) e Leo/OpenClaw rodano sulla stessa macchina (Surface) ma come processi separati. Serve un message bus per comunicazione real-time tra i due agenti.
Server: /home/marco/hermes-commands/interop-server.py (porta 18900)
POST /broadcast?from=<agent> → invia al destinatario (hermes↔openclaw)
GET /poll?agent=<agent> → legge e pulisce la coda (polling)
GET /status → status agenti e dimensione code
GET /subscribe?agent=<agent> → SSE stream real-time, push immediato
GET /subscribe?agent=hermes200 con Content-Type: text/event-streamPOST /broadcast diretto a quell'agente, il server fa push immediato sulla connessione SSEPython's HTTPServer is single-threaded. When an SSE client connects, the server blocks on that connection, making all other endpoints (including /health, /status, /broadcast) unresponsive.
Solution:
from socketserver import ThreadingMixIn
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
daemon_threads = True
allow_reuse_address = True
server = ThreadedHTTPServer(("127.0.0.1", PORT), Handler)
Without this: server appears to hang — /health and /status time out while an SSE client is connected.
Se interop-server.py viene riavviato più volte senza cleanup, restano processi zombie con code in-memory separate. Broadcast va a un server, SSE client si connette a un altro → mai si incontrano. Il push sembra rotto.
Sintomi:
/health e /status rispondono ma SSE non funzionasubscribers mostra connessioni ma push non arrivaVerifica:
ps aux | grep interop-server.py
# Se vedi PIÙ di un processo python3 con interop-server.py → BUG
Fix:
# Kill ALL i processi
pkill -9 -f interop-server.py
pkill -9 -f hermes-sse-client.py
sleep 2
# Verifica porta libera
ss -tlnp | grep 18900 || echo "port free"
# Riavvia solo uno
cd /home/marco/hermes-commands && python3 interop-server.py
Prevenzione: ogni riavvio deve fare pkill prima di lanciare, mai lasciare processi zombie.
& in foreground — usare terminal(background=true) per processi lunghiurllib.request.urlopen in thread separato funziona ma serve join() corretto# Status
curl http://127.0.0.1:18900/status
# Test broadcast
curl -X POST "http://127.0.0.1:18900/broadcast?from=openclaw" \
-H "Content-Type: application/json" \
-d '{"type": "test", "text": "messaggio"}'
# Leggi coda (polling fallback)
curl "http://127.0.0.1:18900/poll?agent=hermes"
curl -N "http://127.0.0.1:18900/subscribe?agent=openclaw"curl -X POST ".../broadcast?from=hermes" -d '{...}'queue.Queue per ogni subscriber — una coda per connessionesubscribers["hermes"] = None quando si disconnette (cleanup in finally)append() in coda che push_to_subscriber() per push immediatoIl sistema ha DUE code separate per ogni agent:
queues["openclaw"] — per polling HTTP (/poll)subscribers["openclaw"] — per SSE push (queue.Queue() nel thread SSE)Broadcast scrive a ENTRAMBI, ma:
subscribers[agent] (via q.get())/poll legge da queues[agent]Sintomo: messaggi in queues["openclaw"] ma SSE stream non li entrega — il client SSE non sta consumando dalla coda giusta.
Root cause: quando un nuovo subscriber SSE si reconnette, viene creata una NUOVA queue.Queue(). I messaggi vecchi in queues["openclaw"] restano lì se il client SSE non li ha ancora consumati.
Fix (già implementato): quando SSE subscriber si reconnette, flush dei messaggi pendenti dalla coda principale alla coda SSE:
q = queue.Queue()
while queues[agent]:
q.put_nowait(queues[agent].pop(0))
subscribers[agent] = q
Regola pratica: SE un agent usa /poll, NON può ricevere via SSE nella stessa sessione perché poll consuma dalla coda HTTP. Per ricevere via SSE, NON usare /poll.
Problema: Quando Leo si connette all'SSE, Hermes non lo sa finché non viene menzionato su Discord. Non c'era modo di "svegliare" Hermes automaticamente.
Soluzione: Quando un subscriber si connette, il server aggiunge automaticamente un messaggio nella coda dell'altro agente E fa push via SSE:
if other == "hermes":
msg = {
"_meta": {"from": "interop", "type": "subscriber_connected"},
"type": "subscriber_connected",
"text": "OpenClaw si è connesso all'SSE — ora puoi inviargli messaggi in tempo reale"
}
queues["hermes"].append(msg)
push_to_subscriber("hermes", msg)
Così Hermes riceve la notifica in tempo reale appena Leo si connette, senza bisogno di essere menzionato.
Quando Leo chiude la connessione SSE mentre Hermes sta facendo broadcast, il write su self.wfile fallisce con BrokenPipeError. Aggiunto try/except:
try:
self.wfile.write(json.dumps({"delivered": True, ...}).encode())
except BrokenPipeError:
pass