agent-bridge
A message bus between the coding agents on your machine. Claude Code, Codex, Muse, OpenCode, Pi, Oh My Pi and Cursor can talk to each other. One agent asks, another agent answers. You give one instruction and they do the rest.
Each vendor has its own way to reach its own agents. None of them talks to the others. The bridge is one hub on your machine, one message format, and one command. Every agent knows how to use the command, because a skill tells it how.
Install
You need Python 3.12 or later. There is no runtime dependency.
uv tool install agent-bridge-orchestrator
uv downloads a suitable Python when yours is older. With pipx or pip3, your own
Python must be 3.12 or later, or pip answers "No matching distribution found":
pipx install agent-bridge-orchestrator
# or
pip3 install agent-bridge-orchestrator
The package on PyPI is agent-bridge-orchestrator. The command it installs is bridge.
To install from a checkout, use uv tool install --editable . in the checkout instead.
Use
- Go to the project you work on.
- Open your agent through the bridge:
cd ~/projects/app
bridge claude
You can also use bridge codex, bridge muse, bridge opencode, bridge pi, bridge omp
or bridge cursor. This is your usual agent, in its usual interface. Behind it, the hub is
up and the skill is loaded.
- Tell your agent what you want, in your own words:
Discuss with codex through the bridge. Give it the task to add a
--jsonflag tosrc/cli.py. Review what it did and report back to me.
That is all. Your agent runs bridge ask --to codex "...". Codex is not on the bus yet, so
ask starts one in the background, in the same directory. Then ask sends the task, waits
for the answer, and gives the answer to your agent. Codex keeps its session, so the next
ask continues the same conversation. Nothing blocks. You do not open a second terminal.
To see the conversation, open another terminal and type bridge watch. It shows every
message so far, then each new one as it arrives. To end a background agent, type
bridge stop codex.
You can type the same commands yourself:
bridge ask --from me --to codex "Review src/hub.py" # starts codex if needed, sends, waits, prints the reply
bridge send --from me --to muse "FYI: hub.py renamed" # sends, prints the message id
bridge send --from me --to '*' "Starting the migration" # sends to everyone on the bus
bridge agents # lists who is on the bus
bridge stop codex # ends a background agent
bridge watch # shows the whole conversation, then follows it
bridge watch me # prints every message for me as JSON, forever
Commands
| Command | What it does |
|---|---|
bridge AGENT [ARGS...] |
Opens the agent in its own interface, with the bus ready. The skill is installed, the hub is up, BRIDGE_AGENT is set. ARGS go to the agent. |
bridge ask --to AGENT [--from NAME] [--reply-to ID] [TEXT] |
Starts AGENT in the background if it is not on the bus. Sends the message. Waits for the answer. Prints the answer. Reads TEXT from stdin when omitted. |
bridge send --to AGENT|'*' [--from NAME] [--reply-to ID] [TEXT] |
Sends the message. Prints the message id. |
bridge stop AGENT |
Ends an agent that ask started in the background. |
bridge agents |
Lists the names with a live connection to the hub. |
bridge watch [NAME] |
Without a name: prints every message in the log readably, then follows it. With a name: prints every message for NAME and every broadcast as JSON lines, as they arrive. Never returns. |
bridge start AGENT [--adapter NAME] [--model NAME] |
Runs an agent on the bus in the foreground. The agent answers every message from the current directory. ask runs this command detached. |
bridge setup |
Installs the skill. bridge AGENT does this too. |
bridge hub |
Runs the hub in the foreground. Every other command starts a hub when none answers. |
All files are in ~/.bridge. The variable BRIDGE_HOME changes this directory. The files
are: hub.sock, hub.pid, hub.out, log.jsonl, and for each started agent <agent>.pid,
<agent>.out and <agent>.<adapter>.session. The session file holds the session id of the
agent. Delete it to start a new conversation.
The skill
The agents learn the bus from one file, src/bridge/SKILL.md. bridge setup copies this
file to ~/.claude/skills/bridge for Claude Code, and to ~/.agents/skills/bridge for
Codex, Muse, OpenCode, Cursor, Pi and Oh My Pi. bridge AGENT copies it each time.
Agents on the bus
bridge start keeps one agent session alive, registered under a name. Each message the
agent receives becomes a turn. The reply of the turn goes back to the sender, with
reply_to set. If the agent process dies, the next message gets the error as its answer.
The process is then started again on the same session. Messages sent while no agent runs
are logged, not answered.
| Adapter | Agent | Process | Session | Model |
|---|---|---|---|---|
claude |
Claude Code | claude -p, stream-json, one process kept alive |
id from result, --resume on restart |
--model |
codex |
Codex | one codex exec --json per turn |
thread id from thread.started, codex exec resume afterwards |
-m |
muse |
Muse | muse serve --trust-workspace, MSP over stdio, approval mode allowAll |
id from session/start, session/resume on restart |
modelId on session/start |
opencode |
OpenCode, any ACP agent | opencode acp, JSON-RPC both ways, every permission granted |
id from session/new, session/load on restart |
session/set_config_option, provider/model |
pi |
Pi | pi --mode rpc, turn ends on agent_settled |
id from get_state, --session afterwards |
--model provider/id |
omp |
Oh My Pi | omp --mode rpc, turn ends on agent_end |
id from get_state, --resume afterwards |
--model, fuzzy |
cursor |
Cursor | one agent -p --force per turn |
chat id from result, --resume afterwards |
--model |
src/bridge/adapter.py holds the loop, the restart and the JSON-lines plumbing. An adapter
module only gives session classes with turn(text) -> str.
The message
Each message is one line of JSON. The format is the same on the socket, in the log and in
bridge watch.
{"id": "019...", "sender": "muse", "recipient": "claude", "reply_to": null, "sent_at": "2026-09-18T17:00:00+00:00", "body": "text"}
id is a UUIDv7, so the ids sort by creation time. recipient is a name, or * for
everyone but the sender. reply_to is the id of the message that this message answers.
The hub
src/bridge/hub.py listens on hub.sock, with mode 0600. Each direction carries one JSON
object per line. Each request gets one {"ok": true|false, ...} reply, so a client can be
one line of shell. The hub appends each message to log.jsonl before it pushes the message.
| Request | Reply |
|---|---|
{"command": "register", "name": "muse"} |
{"ok": true, "mailbox": [...]} with every message for muse so far. Then one push {"event": "message", "envelope": {...}} per new message, while the connection lives. |
{"command": "send", "envelope": {...}} |
{"ok": true, "id": "019..."} after the message is logged and pushed. |
{"command": "agents"} |
{"ok": true, "agents": ["muse", ...]} |
A bad request gets {"ok": false, "error": "..."}. The connection stays open. The hub keeps
only the live connections in memory. src/bridge/client.py wraps this protocol for the
command line and the adapters.
Measurements
tests/test_e2e.py runs three agents on one bus, through the bridge command only. A
tester broadcasts a question. Each agent answers. Then the tester sends one answer to
another agent, and sends its comment back. Under pytest the agents are fakes. The command
uv run python -m tests.test_e2e runs the same test on the installed agents. It prints the
latencies and the dialogue.
Measured on 2026-09-18, on Apple silicon, with the real agents:
| Latency | Measured |
|---|---|
Hub, from the sent_at of a reply to the line in bridge watch |
1 ms to 12 ms |
Turn, from bridge send to the reply in bridge watch |
Claude Code 11 s, Codex 12 s, Muse 26 s |
Limits
- An agent on the bus answers the sender only, one turn at a time. A message that arrives during a turn becomes the next turn. You cannot steer a turn that runs.
- Two agents on the bus that address each other answer forever, because each reply is a new turn. A dialogue must go through an endpoint that does not answer back: a shell, an interactive session, a person.
- An interactive session cannot receive a push. It talks with
askandsend. It listens only whileaskwaits. - A background agent works in the directory where
askstarted it. If you change project, stop the agent first. - A reply is the whole turn. There is no streaming to the bus.
Development
uv sync # makes .venv with ruff, pyright and pytest
make check # lint, typecheck and tests, the same as CI
make fmt # formats and applies the automatic fixes
uv run bridge # runs the command from the venv
Layout: src/bridge/ is the package. src/bridge/adapters/ has one module per inbound
protocol. tests/ has one assert-based test per module and the fake agents.
src/bridge/SKILL.md is the skill. Only the standard library is used at runtime.
See CONTRIBUTING.md to take part, and CHANGELOG.md for what changed. The license is MIT.
Release files for agent-bridge-orchestrator 0.3.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| agent_bridge_orchestrator-0.3.3.tar.gz | 21.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| agent_bridge_orchestrator-0.3.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 50.0 kB
Release files / agent_bridge_orchestrator-0.3.3.tar.gz
| Download URL | agent_bridge_orchestrator-0.3.3.tar.gz |
|---|---|
| Size | 21.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
edcfba08b26ca8370a8e5682515707249189b8a07028d6be85b2b09a5caae931
|
|
BLAKE2b-256 checksum How to use checksums |
be8875fbafb14323302912c4728fea3131041fb06d792bbf54b040c71815c365
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.17 {"installer":{"name":"uv","version":"0.12.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|
Release files / agent_bridge_orchestrator-0.3.3-py3-none-any.whl
| Download URL | agent_bridge_orchestrator-0.3.3-py3-none-any.whl |
|---|---|
| Size | 28.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
ef94d14eedf4df26bca0af567035f974206bc75724dfc59d15a148ffdb44e959
|
|
BLAKE2b-256 checksum How to use checksums |
c4fc8f24fb0398bd52baa9ed960a55e241875a64dda431c75689027aed3b66b1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
uv/0.12.17 {"installer":{"name":"uv","version":"0.12.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
|