Metadata-Version: 2.4
Name: agent-bridge-orchestrator
Version: 0.3.3
Summary: Local message bus between terminal coding agents: Claude Code, Codex, Muse, OpenCode, Pi, Cursor
Keywords: agents,message-bus,claude-code,codex,muse,opencode,acp
Author: GenjiruSUchiwa
License-Expression: MIT
License-File: LICENSE
Classifier: Development Status :: 3 - Alpha
Classifier: Environment :: Console
Classifier: Intended Audience :: Developers
Classifier: Operating System :: MacOS
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: Software Development
Requires-Python: >=3.12
Project-URL: Repository, https://github.com/GenjiruSUchiwa/agent-bridge
Project-URL: Changelog, https://github.com/GenjiruSUchiwa/agent-bridge/blob/main/CHANGELOG.md
Project-URL: Issues, https://github.com/GenjiruSUchiwa/agent-bridge/issues
Description-Content-Type: text/markdown

# 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.

```bash
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":

```bash
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

1. Go to the project you work on.
2. Open your agent through the bridge:

```bash
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.

3. Tell your agent what you want, in your own words:

> Discuss with codex through the bridge. Give it the task to add a `--json` flag to
> `src/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:

```bash
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`.

```json
{"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 `ask` and `send`. It listens
  only while `ask` waits.
- A background agent works in the directory where `ask` started it. If you change project,
  stop the agent first.
- A reply is the whole turn. There is no streaming to the bus.

## Development

```bash
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](CONTRIBUTING.md) to take part, and [CHANGELOG.md](CHANGELOG.md) for
what changed. The license is MIT.
