Release 1.0.0 — one leader, one host, complete
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
This commit is contained in:
+1
-1
@@ -6,7 +6,7 @@
|
||||
|
||||
<groupId>dev.ltms</groupId>
|
||||
<artifactId>bridged</artifactId>
|
||||
<version>0.1.0-SNAPSHOT</version>
|
||||
<version>1.0.0</version>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>bridged</name>
|
||||
|
||||
@@ -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.
|
||||
Reference in New Issue
Block a user