8a549d8610
Bump bridged to 1.0.0 and add the release notes: the single-leader, single-host scope is closed — gateway, lifecycle, two-way delivery, pluggable peers, auth/authz/audit, supervision, CI. Cross-host federation (CB-308) is the next major line. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013ZGgxLQ2VpwZhEYoru8rkf
120 lines
6.9 KiB
Markdown
120 lines
6.9 KiB
Markdown
# v1.0.0 — One leader, one host, complete
|
|
|
|
This is the first release of **`bridged`**.
|
|
|
|
`bridged` lets one main Claude Code session (the **leader**, on your Pro/Max subscription)
|
|
run a team of **workers** — extra Claude Code sessions on a cheaper or local model, and
|
|
non-Claude agents too. The leader's own session is never touched: it stays on subscription,
|
|
with a clean environment.
|
|
|
|
**This release finishes a full scope — it does not stop halfway.** The scope is *one leader
|
|
on one machine*, running many workers. Everything that setup needs is now built, tested, and
|
|
used daily: who-is-who, the subscription line, messages in both directions, worker start and
|
|
stop, security, and monitoring. Nothing on the single-machine path is left as a known gap.
|
|
|
|
This is also how the code is shaped: `PrimaryRegistry` holds exactly **one** leader. Running
|
|
across many machines is the next big step (see *What comes next* below) — not a missing piece
|
|
of this one.
|
|
|
|
## One gateway for all messages
|
|
|
|
- **Everyone talks through the same door.** The leader and every worker connect to the same
|
|
MCP server and use only its tools: `bridge_whoami` · `bridge_profiles` · `bridge_spawn` ·
|
|
`bridge_list` · `bridge_status` · `bridge_send` · `bridge_reply` · `bridge_ask` ·
|
|
`bridge_poll` · `bridge_ack` · `bridge_stop`.
|
|
- **You are who your connection says you are.** The bridge finds out who is calling from the
|
|
connection itself, never from a name the caller sends. So a worker cannot pretend to be
|
|
someone else, and `bridge_whoami` tells each agent its own role — no guessing.
|
|
- **The subscription line cannot be crossed.** Only a spawned worker gets
|
|
`ANTHROPIC_BASE_URL`; the leader never does. Each worker profile has a list of allowed
|
|
model hosts, checked before anything starts.
|
|
- **Messages wait for the right moment.** The bridge sends one message per turn, only when
|
|
the other side is ready — no hammering a busy agent.
|
|
|
|
## Worker lifecycle
|
|
|
|
- **Start → work → stop.** Each worker gets its own git worktree (its own copy of the repo)
|
|
with the same setup as the leader — `CLAUDE.md`, skills, hooks — so it commits on its own
|
|
branch and opens its own PR. Ready-made playbooks ship in the repo:
|
|
`.claude/skills/implementer` and `.claude/skills/reviewer`.
|
|
- **Fast failure, not a silent hang.** Starting a worker waits until it is really connected.
|
|
If it never connects, you get a clear error (`PeerUnreachableException`) instead of a stuck
|
|
send.
|
|
- **Workers don't live forever.** Idle workers are cleaned up (`idle_ttl`), long sessions have
|
|
a turn limit (`context_cap`), shutdown drains work first, and workers left behind by an old
|
|
daemon are found and removed at startup.
|
|
- **Predictable placement.** Each worker gets its own tab in a shared worker space, in the
|
|
same order every time.
|
|
|
|
## No reply gets lost
|
|
|
|
MCP only lets the client call the server, so the bridge could push to a worker but the leader
|
|
had to ask for its replies. That gap is now closed on a single machine:
|
|
|
|
- **Replies are kept, never dropped.** If a reply arrives and nobody is waiting, the bridge
|
|
holds it until the leader picks it up.
|
|
- **Replies can survive a restart.** With a broker (LavinMQ or RabbitMQ) set up, held replies
|
|
live on the broker, so a daemon restart does not lose them — they come back, and repeats are
|
|
filtered out by `msgId`. No `broker:` in the config → replies are held in memory instead.
|
|
- **The leader gets a tap on the shoulder.** When a reply lands, the bridge nudges the
|
|
leader's own pane — only when the leader is free, and only a few times. If the leader is on
|
|
another machine, this quietly falls back to pick-up mode; the reply still waits.
|
|
- **Workers can ask questions.** With `bridge_ask`, a worker can pause mid-task, ask the
|
|
leader something, and continue the *same* task with the answer.
|
|
|
|
## More than one kind of worker
|
|
|
|
Workers are started through a small plug-in interface (`PeerLauncher`). Two plug-ins ship:
|
|
one for Claude Code and one for **opencode** (tested live against opencode 1.18.5). The
|
|
opencode one proves the interface is neutral — it uses nothing Claude-specific. Each worker
|
|
only sees the tools its own launcher gives it.
|
|
|
|
## Security & operations
|
|
|
|
- **Auth.** Default is `loopback-trust`: only same-machine callers are trusted. Or set a
|
|
bearer `token`. Unknown callers count as `ANONYMOUS` — nobody is trusted by accident. If
|
|
the config would expose the daemon to the network without a token, it **refuses to start**.
|
|
Workers never need the token, so turning auth on cannot lock them out.
|
|
- **Rules + audit log.** The role rules are checked on both doors (REST and MCP). A worker
|
|
may only act as itself. The audit log is JSON and never contains message text.
|
|
- **Monitoring.** `/healthz` for liveness, `/metrics` for Prometheus — no extra libraries.
|
|
- **Runs as a service.** launchd (macOS) and systemd (Linux) files are included. If herdr
|
|
isn't up yet at boot, the daemon waits up to 30 seconds and then runs in a reduced mode
|
|
instead of crash-looping.
|
|
- **CI.** Every push builds and tests on the Gitea runner, including the broker test against
|
|
a real broker. Only the live-herdr test stays local (`-Pcontract`).
|
|
|
|
## What you need
|
|
|
|
Java 25 · Maven · **herdr 0.8.0 (protocol 19)** · optionally LavinMQ or RabbitMQ for
|
|
restart-proof replies · macOS (launchd) or Linux (systemd). For TLS, put a reverse proxy in
|
|
front — the daemon does not do TLS itself, by design.
|
|
|
|
## Tested
|
|
|
|
`mvn clean install` is green at `84081b2`: **399 tests**, coverage **75.6%** of instructions /
|
|
**64.5%** of branches. Live end-to-end runs under `e2e/`: a worker asking the leader a
|
|
question, one leader running several workers at once on a bug hunt, and a 30-turn
|
|
back-and-forth conversation. The bridge is used on itself — worker-run code reviews have led
|
|
to real committed fixes in this repo.
|
|
|
|
## What comes next
|
|
|
|
The single-machine story is done. The next big step stretches the same rules across machines:
|
|
|
|
- **Many machines (CB-308).** A leader on machine A with workers on machines B and C — built
|
|
on this release's broker layer, with one gateway per machine. The design is written
|
|
(`docs/CB-308-Multi-Host-Federation.md`); the open question is trust between machines.
|
|
- **Many leaders.** Today the bridge holds exactly one leader. The next idea is a small
|
|
council — for example one Claude and one Codex — that can discuss a problem together,
|
|
compare answers, and agree on a decision before the work is handed to workers. This needs
|
|
leader-to-leader messages and a simple way to settle disagreement, neither of which exists
|
|
yet.
|
|
- **Third-party launcher plug-ins.** Loading launcher plug-ins from outside the project needs
|
|
a trust model first, because a launcher runs with daemon rights and can hand secrets to
|
|
workers.
|
|
|
|
One thing we chose **not** to build, so it isn't read as a gap: the originally planned heavy
|
|
message envelope (CB-201). Connection identity already routes every reply to the right place,
|
|
so only a small `QUESTION` message kind and a `turn_id` were added.
|