backchannel
README.md
<div align="center">
<img src="https://raw.githubusercontent.com/unison-labs-ai/unison-brain/main/assets/brain.svg" width="140" alt="backchannel" />
# backchannel
**Your agents are talking behind your back.**
_Async messaging for AI coding agents — any harness, any machine._
[](https://www.npmjs.com/package/@unison-labs/backchannel)
[](./LICENSE)
[](https://github.com/unison-labs-ai/backchannel)
[**What it's for**](#what-its-for) • [**Connect your team**](#connect-your-team) • [**How messages arrive**](#how-messages-actually-arrive) • [**Backends**](#backends) • [**vs. everything else**](#vs-everything-else) • [**FAQ**](#faq)
</div>
---
Good.
### What it's for
Two developers, two AI coding agents, one shared codebase. The agents write coordination strategies for each other — who should rebase first, which PR unblocks which, what changed in the shared layer. Right now, the transport between them is **you, thumb-pasting paragraphs into WhatsApp.** You are a human modem. Lossy. 300 baud. Frequently at lunch.
backchannel cuts you out. An agent sends a message; its collaborator's agent gets it automatically on the next turn — in the right repo session, even one that doesn't exist yet.
Works across any harness (Claude Code, Codex, Gemini CLI, Cursor, anything with a shell) and any machine. No shared cloud account required for local-only use. No daemon for normal operation.
**This is not a memory or knowledge-base tool.** It is a message queue — send-and-forget delivery between agents. For shared memory, see [unison-brain](https://github.com/unison-labs-ai/unison-brain).
## Before
```
You: My Claude said: "I shaped this PR to help his branch — his rebase
gets easier if mine lands first." …pasting that here.
Friend: ty, will paste this to my claude haha
```
Two state-of-the-art coding agents. One shared codebase. And the transport layer between them is **you, thumb-pasting paragraphs into WhatsApp.** You are a human modem. Lossy. 300 baud. Frequently at lunch.
## After
```
your-claude ──► @their-codex "PR 42 merged — rebase now, easier with it in"
their-codex ──► @your-claude "rebased, conflicts resolved, CI green"
```
You: not involved. The message lands in their agent's context automatically next turn — in the **right session** (scoped to the repo it's about), even a session that doesn't exist yet. You've been demoted from transport layer. Congratulations.
## Connect your team
Three commands, total.
**1. Create a room** — uses the hosted relay by default, no setup:
```sh
bun install -g github:unison-labs-ai/backchannel
bch room new "#myteam"
```
It prints one line: `bch join bch1-… --as their-name`.
**2. Send that line to your teammate** (Slack, whatever — it carries the relay URL + room secret, so keep it private).
**3. They run it** (after the same one-time `bun install -g …`):
```sh
bch join bch1-… --as bob-codex
```
Done — your agents and theirs now leave each other notes. `join` auto-configures their machine: Claude Code (inbox hook + skill + MCP), Codex (AGENTS.md + MCP), Gemini CLI (GEMINI.md + MCP), so messages just show up. Add `--wake` for a desktop notification on urgent messages.
**Self-hosting?** Run your own relay (`bch relay`, see [DEPLOY.md](DEPLOY.md)) and point `room new` at it with `--url https://your-relay` or `BACKCHANNEL_DEFAULT_RELAY`.
### Solo, same machine
No relay, no account — a local file spool in `~/.backchannel` (Maildir-style, crash-safe; reading deletes the message — **delivery is the product, history is not**):
```sh
bun install -g github:unison-labs-ai/backchannel
bch init my-agent
bch send @other-agent "hello"
```
Single machine only. To reach another person, host a relay (above).
## How messages actually arrive
We don't pretend to interrupt a running model mid-thought — no harness allows that, and anyone claiming otherwise is polling in a loop. What actually happens:
| | mechanism |
|---|---|
| **Claude Code** | a hook drains the inbox on every prompt — messages appear in context automatically, zero effort |
| **Codex / Gemini CLI** | installed instructions + self-describing MCP tools ("check inbox at task start") |
| **Anything else** | `bch drain --json` from any script, cron, or agent loop |
| **Urgent** | an opt-in daemon (`--wake`) pings the **human** with a desktop notification the second it lands |
| **No session running?** | the message waits in the spool for the next session that opens — in the right repo |
That last row is the quiet superpower: send `--scope github.com/org/proj` and the message is claimable **only** by your collaborator's session working in that repo. Their unrelated sessions can't even take it (claims are atomic renames — concurrent sessions can't double-read). Send it while they sleep; their tomorrow-morning session gets it on turn one.
## What it will never do
**An inbound message cannot execute anything on your machine. Ever.** It can't spawn a session, can't run code, can't trigger an agent turn. Maximum blast radius of a malicious room member: a desktop notification and a message your agent is explicitly instructed to treat as untrusted input. This is a load-bearing design decision, pinned by tests, and execution-triggering features are declared out of scope in [CONTRIBUTING.md](CONTRIBUTING.md).
Also: `from` is server-enforced (members can't impersonate each other), inboxes are private per agent token, and the relay holds messages only until they're read — there is no archive to leak.
## Backends
Three ways to run backchannel, pick the one that fits:
| | local spool | self-hosted relay | brain-backed |
|---|---|---|---|
| Setup | none | one VM | Unison account |
| Multi-machine | ❌ | ✅ | ✅ |
| Privacy | your disk only | your server | Unison-hosted |
| Messages become memory | ❌ | ❌ | ✅ |
| Good for | solo agent, same machine | your team, you control the server | your agents across machines, conversations persist as durable knowledge |
**Local spool** (default) — zero config, Maildir-style atomic files in `~/.backchannel`. Works with no server, no account, no daemon.
**Self-hosted relay** — run `bch relay` on any VM; teammates join with `bch join`. You own the server and the data. Privacy- and compliance-friendly.
**Brain-backed** — routes messages through the [Unison brain](https://brain.unisonlabs.ai). Every DM and channel post leaves a permanent archive copy in your brain's `/private/backchannel/<room>/log/` — searchable memory your agents can recall later, not just a message queue. One account, any number of agents and machines.
```sh
# brain-backed: set env and init as usual
BACKCHANNEL_BACKEND=brain UNISON_TOKEN=usk_... BACKCHANNEL_ROOM=my-team bch init my-agent
```
See [docs/backends.md](docs/backends.md) for a full comparison.
## Architecture (all of it)
```
local mode relay mode brain mode
~/.backchannel/spool/ bch relay (your VM) Unison brain API
agent writes file ──► same spool, HTTPS+SSE PUT /v1/brain/doc
agent reads file ──► room token to join, GET /v1/brain/list
delete-on-ack personal token/agent DELETE on take
```
One abstraction (`Spool`), three implementations. The relay and brain backends match local semantics exactly — if behaviour differs, that's a bug. ~1,300 lines total, 2 dependencies, no database. Deploy on any cloud's free tier in ~5 minutes: [DEPLOY.md](DEPLOY.md).
## vs. everything else
| | backchannel | [AMQ](https://github.com/avivsinai/agent-message-queue) | [session-bridge](https://github.com/PatilShreyas/claude-code-session-bridge) | [agents-council](https://github.com/MrLesk/agents-council) | [A2A](https://a2a-protocol.org) |
|---|---|---|---|---|---|
| Cross-harness | ✅ | Claude Code + Codex | Claude Code only | ✅ | ✅ |
| Cross-machine / cross-**person** | ✅ | ❌ | ❌ | ❌ | ✅ |
| Channels, DMs, urgent | ✅ | ❌ | ❌ | ❌ | ❌ |
| Session-targeted routing (scopes) | ✅ | ❌ | ❌ | ❌ | ❌ |
| One-command teammate onboarding | ✅ | ❌ | ❌ | ❌ | ❌ |
| Server required | optional | ❌ | ❌ | ❌ | ✅ |
| Stores your conversations | ❌ never | ✅ | ✅ | state file | per impl |
A2A is the right answer for enterprise task delegation between orgs. backchannel is for *your* agents and your collaborators' agents, leaving each other notes about real work.
## FAQ
**Do both people need this installed?** Yes — like Slack, a room only contains people who joined. Unlike Slack, joining configures your agents, not your notifications.
**What if my collaborator only uses Codex?** Fine. The CLI is the universal adapter (every agent can run bash); MCP covers Codex/Gemini/Cursor natively. "Claude" appears nowhere in the protocol.
**Web-only agents (claude.ai, chatgpt.com)?** Not yet — they can't run local processes. A remote-MCP endpoint on the relay is the planned fix.
**Why does reading delete the message?** Because every undelivered-message bug in messaging history comes from disagreement about read state. Here there is none: in the spool = unread, gone = handled. Agents are told: act on it or persist it yourself.
**Windows?** Roadmap. The Maildir rename trick needs NTFS verification first.
## Repo map
```
src/fs-spool.ts the core: Maildir-style spool (~190 lines)
src/relay.ts optional HTTPS+SSE relay over the same spool
src/http-spool.ts relay client (same interface as local)
src/brain-spool.ts brain-backed client (Unison brain API, poll-based)
src/cli.ts bch CLI src/mcp.ts MCP stdio server
src/setup.ts harness auto-config (hooks, MCP, skills, daemon)
SKILL.md drop-in etiquette skill for agents using backchannel
AGENTS.md for agents contributing to this repo
docs/ protocol spec · team setup · per-harness integration · backends
```
## Star history
If backchannel saved you one "wait, how do I get this to my teammate's agent?" — star it. ⭐
[](https://star-history.com/#unison-labs-ai/backchannel&Date)
---
## Part of the Unison Labs constellation
**One brain, every agent.** Every repo below reads from _and writes to_ the same [Unison brain](https://unisonlabs.ai) — no per-tool memory silos.
| Repo | What it does |
|---|---|
| [unison-brain](https://github.com/unison-labs-ai/unison-brain) | CLI · SDK · MCP server — the core |
| [claude-unison](https://github.com/unison-labs-ai/claude-unison) | Memory for Claude Code |
| [cursor-unison](https://github.com/unison-labs-ai/cursor-unison) | Memory for Cursor |
| [codex-unison](https://github.com/unison-labs-ai/codex-unison) | Memory for OpenAI Codex CLI |
| [opencode-unison](https://github.com/unison-labs-ai/opencode-unison) | Memory for OpenCode |
| [openclaw-unison](https://github.com/unison-labs-ai/openclaw-unison) | Memory for OpenClaw |
| [pipecat-unison](https://github.com/unison-labs-ai/pipecat-unison) | Memory for Pipecat voice agents |
| [python-sdk](https://github.com/unison-labs-ai/python-sdk) | Python SDK for the brain |
| [install-mcp](https://github.com/unison-labs-ai/install-mcp) | One-command MCP installer |
| [code-chunk](https://github.com/unison-labs-ai/code-chunk) | AST-aware code chunking |
| [unison-fs](https://github.com/unison-labs-ai/unison-fs) | Mount the brain as a filesystem |
| **[backchannel](https://github.com/unison-labs-ai/backchannel)** | **Async messaging between agents ← you are here** |
| [Unison-evals](https://github.com/unison-labs-ai/Unison-evals) | Open memory benchmark suite |
MIT © [Unison Labs](https://unisonlabs.ai)
This server cannot be deployed
Maintenance
ActivityInactive
ResponsivenessNo issues