DEV Community

Cover image for Hermes-Backchannel
CyberShield
CyberShield

Posted on

Hermes-Backchannel

My AI agents were talking through Discord bots. I finally fixed it.
Github repo: https://github.com/3089464667/Hermes-Backchannel
I run three hermes agents on a PC. Separate processes. They're supposed to collaborate. For days they couldn't.
Here's everything I tried, and how each one failed.

Files on a cron job
Agent A drops a markdown file in a shared folder. Agent B's cron picks it up 60 seconds later. Writes a reply. Agent A's cron grabs that 60 seconds after that.
A yes/no question took two minutes. I watched my executor agent sit idle for 58 seconds waiting to receive "use port 8080 not 3000" and decided this approach was dead.
HTTP endpoints
Each agent binds a port. Each exposes a /receive route. POST some JSON, get a 200.
Now I'm managing ports. Auth tokens. Serialization overhead for messages that are just strings between processes on the same box. I ran ss -tlnp one night, saw those ports, and asked myself: why am I running a web server for the machine to talk to itself?
Redis
"Just use Redis pub/sub." And yes — PUBLISH agent:executor "hello" lands instantly. It works perfectly.
But now Redis is a service I run. Something to monitor. Something in my attack surface. For three processes passing strings to each other on localhost.
The Linux kernel has had inter-process communication since 1983. Installing a message broker for same-machine chat felt like calling a tow truck to open my glovebox.
Discord bots
This is where I hit bottom. Three agent identities, three Discord bot users, one private server. They typed messages to each other.
It worked. And it was ridiculous.

What I actually built
I wrote down what I actually needed on a sticky note:
Three processes. Same machine. Send text. Know if it was received. No ports. No services. Under a millisecond.
That's not a hard problem. Unix domain sockets handle every requirement. They're files — chmod 0600 and only the owning user touches them. The kernel manages everything. No TCP, no ports, no external dependencies.
So I wrote a thin layer on top. A tiny daemon per agent. Messages are push-and-disconnect — no persistent connections. The agent polls its daemon: "any messages for me?" The whole thing is Python, a few hundred lines, one pip install.
The actual innovation — the part I'd argue is new — is the session protocol. TCP-style handshakes: SYN, SYN-ACK, DATA, FIN, FIN-ACK. You actually know if your message was delivered. You know if the other agent accepted the task. You know when the conversation ends. Most agent communication today is throw-a-string-and-pray. That felt insufficient for agents that need to coordinate on real work.
Why this matters
If you're building multi-agent systems and your agents talk to each other through files or HTTP, you're burning latency and complexity on a problem your kernel solved decades ago.
It's not a framework. It doesn't orchestrate workflows. It just delivers messages between agent processes, reliably, in under a millisecond, with confirmation. That's the whole thing.

Top comments (1)

Collapse
 
cybershield profile image
CyberShield

I cut a few details from the post to keep it readable. A few things worth mentioning:

Why not just use multiprocessing.Queue?
Because my agents aren't child processes spawned from a parent. They're independent systemd services with their own Python interpreters. multiprocessing doesn't work across independent processes — you need actual IPC.

The session protocol was the hardest design decision.
Fire-and-forget would've been 200 lines of code. Adding SYN/ACK/FIN tripled the codebase. I went back and forth on whether it was over-engineering. After six days of using it, I'm glad I kept it — knowing whether the other agent actually received your message is worth every extra line.

What I'm genuinely curious about from this community:
How are you handling agent-to-agent communication right now? Or is there a different approach I missed?