From 8a549d8610200cc5461364a4b6d3139ada8d53b3 Mon Sep 17 00:00:00 2001 From: Kevin Nguyen Date: Mon, 10 Aug 2026 20:58:06 +0700 Subject: [PATCH] =?UTF-8?q?Release=201.0.0=20=E2=80=94=20one=20leader,=20o?= =?UTF-8?q?ne=20host,=20complete?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) Claude-Session: https://claude.ai/code/session_013ZGgxLQ2VpwZhEYoru8rkf --- bridged/pom.xml | 2 +- docs/RELEASE-NOTES-1.0.0.md | 119 ++++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+), 1 deletion(-) create mode 100644 docs/RELEASE-NOTES-1.0.0.md diff --git a/bridged/pom.xml b/bridged/pom.xml index ce22107..b252fab 100644 --- a/bridged/pom.xml +++ b/bridged/pom.xml @@ -6,7 +6,7 @@ dev.ltms bridged - 0.1.0-SNAPSHOT + 1.0.0 jar bridged diff --git a/docs/RELEASE-NOTES-1.0.0.md b/docs/RELEASE-NOTES-1.0.0.md new file mode 100644 index 0000000..cf604ce --- /dev/null +++ b/docs/RELEASE-NOTES-1.0.0.md @@ -0,0 +1,119 @@ +# 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.