Dogfood found the gap: a turn that dies into an error screen herdr reports as 'unknown' (e.g. the worker hitting API ENOTFOUND) never produces a working->idle boundary, so CB-106 never fires and the async send rides its full 30-min timeout. The injector now counts consecutive 'unknown' samples while a delegation is outstanding; any working/idle sample resets the streak, so only a genuine wedge (~30s continuous unknown) trips it. It then fires TurnListener.onTurnFailed; CompletionResolver scrapes the error screen and resolves the send via Rendezvous.resolveFailure (Kind.FAILED -> Outcome.WORKER_FAILED), surfaced as async phase=failed / REST status=failed / a [worker failed] MCP note, with the error context as the reason. This also frees a delivery that wedged before pickup, which the injectable-only pickup grace could never release.
claude-bridge
A subscription-safe bridge that lets a primary Claude Code (Opus 4.8, on Pro/Max)
session drive a secondary Claude agent running a different model via its own
ANTHROPIC_BASE_URL — without ever putting a proxy on the primary session.
Sibling of crush-bridge (which drives a headless
Crush worker on GX10 DeepSeek). claude-bridge keeps the worker a real Claude Code
process, so it inherits CLAUDE.md, hooks, skills, and MCP — just pointed at a
cheaper/local model.
Leading approach — herdr-centric message server (bridged)
A small always-on message server, bridged, controls
herdr (an agent multiplexer) over its Unix-socket API and exposes a
clean 2-way messaging API as an MCP server that both the primary and the workers mount —
one unified Claude setup and the sole communication gateway (REST/SSE stays for non-Claude
clients; any broker is bridged-internal, below the gateway).
herdr owns the PTYs, multiplexing, persistence, and agent-status events; bridged owns
policy (subscription boundary, session lifecycle, status-gated delivery) and the client
contract. The worker claude launches with ANTHROPIC_BASE_URL=https://ollama.ltms.dev + a
bearer token; the primary Opus stays env-clean and calls bridged's MCP tools.
flowchart LR
OPUS["Opus — primary<br/>(Claude Code, env CLEAN)<br/>MCP client"]
subgraph BD["bridged — standalone daemon (not a claude process)"]
SRV["SERVER face<br/>MCP · REST/SSE · policy"]
CLI["CLIENT face<br/>status-gated injector · herdr socket"]
SRV --> CLI
end
HERDR["herdr<br/>panes · agent-status"]
W["worker claude pane<br/>ANTHROPIC_BASE_URL set<br/>MCP client"]
M["ollama.ltms.dev<br/>(worker model)"]
OPUS -->|"MCP bridge_send (blocks)"| SRV
W -.->|"MCP bridge_reply"| SRV
CLI -->|"Unix socket<br/>send_text · events.subscribe"| HERDR
HERDR -->|"drives PTY"| W
W -->|"inference"| M
classDef ext fill:#2b6cb0,stroke:#1a365d,color:#ffffff;
classDef core fill:#2f855a,stroke:#22543d,color:#ffffff;
class OPUS ext
class SRV,CLI,HERDR core
- Subscription boundary: the primary never sets
ANTHROPIC_BASE_URL(stays on Pro/Max). Only the secondary process is off-subscription — andbridgeditself is a plain daemon (no Anthropic quota), so it may poll/subscribe freely. - One gateway (unified MCP setup):
bridgedis the sole communication path for every Claude session. Primary and workers each mount it as an MCP server (oneclaude mcp addline, same on both) and talk over MCP tools —bridge_send/bridge_reply/bridge_ask/bridge_status. No Claude session ever addresses a broker, a peer, or the network directly; any queue isbridged-internal. MCP tool I/O never setsANTHROPIC_BASE_URL, so mounting the bridge is subscription-safe by construction. - How the primary consumes a reply: a single blocking MCP call (
bridge_send);bridgedholds it open until the worker callsbridge_replyor its turn hitsagent_status=done, then returns the reply as the tool result. No cross-turn busy-poll, so no quota burn. SSE is an optional side-channel for humans/dashboards watching status. - Worker → primary rides
bridged's MCP rendezvous — the reply resolves the primary's blocking call (or, for detached work,bridgedinjects the primary's idle pane when it's ready), so no keystroke-into-primary and no broker are involved, even single-host. The one exception: a split-host primary that isn't a herdr pane wakes via its ownStop-hook, which pollsbridged(never a broker). See the wiki for the two topologies. - Different model per process sidesteps Claude Code's lack of per-subagent provider routing — the worker isn't a subagent, it's its own configured process.
- AgentAPI (
coder/agentapi) is retained only as a swappable fallback injector behind the same interface. See the wiki for the full design, comparison, and rationale.
Docs
Full design, setup, and operations live in the wiki,
vendored here as a submodule under wiki/:
git clone --recurse-submodules ssh://git@git.ltms.dev:2224/lms/claude-bridge.git
# or, after a plain clone:
git submodule update --init
Edit docs in wiki/, then cd wiki && git commit && git push to publish them to the
Gitea wiki.
Status
🟢 Design — herdr-centric bridged message server selected as the primary approach
(2026-07-11), superseding the AgentAPI plan (2026-07-08). AgentAPI retained as fallback
injector.