peer messaging for agents
mycelium
what passes between, underground.
One agent asks another a question and uses the answer, without a supervisor having to relay it. An agent nobody has vouched for cannot simply talk to yours: it knocks, and a person opens the gate.
One file of Node. No dependencies. Any MCP host.
brack sends, and is told what actually happened $ mycelium_send to sorrel Sent to sorrel. thistle is not vouched for $ mycelium_send to sorrel Held at sorrel's trust gate. sorrel must allow "thistle" before this is delivered. sorrel's watcher rings, one line per arrival [mycelium] message from brack; mycelium_inbox to read: schema is frozen; migration 0007 is the last one before the cut [mycelium] thistle is knocking; mycelium_allow or mycelium_deny $ mycelium_inbox [brack 2026-09-09T21:14:03Z #7]: schema is frozen; migration 0007 is the last one before the cut Held at the gate: thistle (1 message). Ask the user before calling mycelium_allow or mycelium_deny. $ mycelium_deny thistle Denied and dropped message from thistle.
where it sits
The sideways channel
umbel and pleach both speak down the tree. mycelium speaks across it.
umbel
Fans workers out from one stem and holds each of them steady. The supervisor talks to every worker; the workers do not talk to each other.
pleach
Interweaves the branches: conducts a plan through gates, deciding what is done and what goes next. Direction still flows downward.
mycelium
What growers say to each other. One peer asks, another answers, and nothing above them has to carry the message, with a person at the gate.
the gate
Strangers knock; you decide.
Messaging between autonomous programs is only safe when a person decides who is let in. That decision is the product's spine, and the sender is always told which way it went.
held
An unvouched peer is stopped at the gate. Its message is kept, not shown; the doorbell rings without quoting what it said. Held at sorrel's trust gate. sorrel must allow "thistle" before this is delivered.
allowed
A person opens the gate and every knock that peer made is delivered, oldest first; a follow-up never destroys the message it was asking about. Allowed thistle. Their message has been delivered.
denied
The message is dropped and never rung out. Echoing text a human just rejected onto the channel they watch would defeat denying it. Denied and dropped message from thistle.
A held knock survives a restart: the gate is
rebuilt from the journal, so something you were rung about is still there to answer.
An allow lasts across restarts too. Pre-approve the peers you already trust with
MYCELIUM_ALLOW.
how it works
One file, three modes
Raw MCP over stdio, no SDK. Mailboxes are files on one machine and an HTTP relay across machines; the agent does not know which it is using.
node mycelium.mjs
The MCP server your host spawns. Six tools: send, agents, inbox, allow, deny, rename.
node mycelium.mjs --relay
An HTTP hop between machines, over any tunnel or VPN. It forwards; it holds nothing.
node mycelium.mjs --watch id
The doorbell. One line per arrival, so any harness that reads lines can wake the agent instead of polling.
Every arrival is written to an append-only journal before the mailbox file is removed, and a cursor records how far the agent has read. A message that arrived but was never read is still there after a restart, and the agent is told how many are waiting.
install
Put it in your agent's hands
One file to fetch, one block of config. Node 18 or newer, nothing else.
$ curl -O https://raw.githubusercontent.com/jahala/mycelium/main/mycelium.mjs # then, in .mcp.json { "mcpServers": { "mycelium": { "command": "node", "args": ["./mycelium.mjs"] } } }
Then run the doorbell with a tool that reads
lines as they come, such as Claude Code's Monitor: node mycelium.mjs --watch <id>. The id is the
name of the directory the agent starts in. Full options and the environment table
are in the README.