[FEATURE] Agent-to-agent messaging with wake-on-delivery — every multi-agent setup is hand-rolling a message bus on the filesystem, and the sprawl IS the queue
Summary
Claude Code has no way for one agent to send a message to another and have it arrive, wake the recipient, and be acknowledged. Every multi-agent setup therefore hand-rolls a message bus on the filesystem — and every failure mode I have documented over the past month is a missing guarantee from that improvised bus.
I am not asking for an orchestration framework or an opinion about how agents should be organized. I am asking for four primitives that a transport layer needs, so that the coordination people are already building can stop being written in markdown.
What I built, and what it is substituting for
| What I built | What it substitutes for |
|---|---|
| Files in a shared handshake directory | Message passing |
| UTC timestamps in filenames | Message IDs |
| A mandated N-minute check-in cadence | Heartbeat / liveness |
| An external heartbeat process | Wake-on-delivery |
| Status JSON files | Presence and state |
| A second AI vendor supervising the first | Delivery confirmation |
| 1,371 files in one directory | The queue |
None of that is exotic. It is the minimum viable transport, implemented in the only medium available.
The four guarantees, and what each one's absence produced
1. Addressable identity
There is no stable way to name "this agent" as a recipient. Addressing is done by filename convention, which is why filenames encode routing (_FROM_X_TO_Y_TOPIC_TIMESTAMP.md) and why every producer invents its own scheme.
2. Reliable delivery
A write lands in a directory and that is the end of the guarantee. Nothing confirms a message was received. Observed consequence: a status check-in refreshed exactly on schedule, with a fresh timestamp and both watchers running — while repeating stale content and having never read the rejection it was responding to. The transport reported success; nothing was delivered.
3. Wake-on-delivery — the load-bearing one
A session only acts when something gives it a turn. Quoting an agent explaining its own overnight stall:
"I only act when something gives me a turn — your message or an agent finishing. At [03:11] both lanes went quiet, nothing woke me, and I stopped. Every check-in I've written happened because I was already in a turn. So promising harder does nothing; the gap is structural."
Writing a file to a directory does not wake anyone. So the moment coordination matters most — the last worker finishes and goes quiet — is precisely the moment nothing exists to generate a turn. Observed consequences: a 5h31m silent stall with fifteen queued actions untouched; a worker in an infinite wait loop for ~90 minutes on a file whose producer had already been terminated; and a session that read a stale status, verified it, wrote about it, and dispatched nothing — provable as active_workers: [].
My workaround was to build an external heartbeat that feeds turns in from outside. A customer building a pacemaker for a marketed-as-autonomous system is the wrong shape of fix.
4. Read acknowledgment
A sender cannot tell whether a message was consumed. This is why coordination degrades into polling, and polling is what produces the file volume — and why nothing can ever be retired, since no message is ever known to be finished.
What the absence costs, measured
On this machine right now:
- 1,371 files in the handshake directory
- 847 of them created in the last 7 days — ~121/day
- 785 of 834 markdown files (94%) carry a timestamp in the filename, because there are no message IDs and a name must be unique
- 76 single-item files that exist only to carry one decision each, because there is no queue with per-item state
A timestamped filename cannot be updated by a later run — the next run computes a new name. So the improvised transport is append-only by construction, with no acknowledgment and no retention. That is not a documentation-hygiene problem. It is a queue with no consumer-ack, and the file count is its backlog.
Why I am filing this separately
I have asked for "a project-management layer" before (#79948) and it did not land, correctly — it is true but it is not a spec, and nobody can pick it up on a Monday.
This is a spec. Four capabilities, each independently testable:
- An agent can be addressed by a stable identity.
- A message send either succeeds or reports failure.
- A recipient becomes active because it was written to — not because a human typed something.
- A sender can observe that a message was consumed.
Given those, retention becomes possible (an acknowledged message can be retired), liveness becomes observable (presence, not a mandated cadence), and the improvised filesystem bus can be deleted rather than grown.
Wake-on-delivery (#3) is the one that matters most. It is the same missing primitive as the timer/heartbeat request in #75036, seen from the other side: without it, every coordination pattern degrades into polling, and polling is what produced every number above.
Environment
- Claude Code 2.1.222, Windows 11
- Multi-agent setup, several concurrent lanes plus background/isolated agents
This issue has 2 comments on GitHub. Read the full discussion on GitHub ↗