wiki: redraw diagrams — bridged as standalone daemon (SERVER/CLIENT faces + MCP)
Declutter every component diagram to show bridged as ONE standalone daemon split into a SERVER (north) face — MCP server + REST/SSE + policy brain — and a CLIENT (south) face — status-gated injector + herdr socket client. Claude sessions are shown as herdr panes that mount the MCP server (call up) while the client drives them down over the socket. - 2-Message-Server: main architecture flowchart rebuilt (herd subgraph of panes + bridged subgraph with srv/cli); intro reframed; split-host node label - 1-Architecture: components diagram — bridged subgraph with SERVER/CLIENT faces - 6-Team: topology — bridged split into faces + role router; worker bridge_reply - Home + README: overview flowchart — bridged subgraph with SERVER/CLIENT faces All 16 mermaid blocks validated with mmdc.
+16
-10
@@ -33,11 +33,15 @@ flowchart TB
|
||||
end
|
||||
|
||||
subgraph work["SECONDARY worker host — off-subscription"]
|
||||
BD["bridged<br/>message server<br/>(not a claude process)"]
|
||||
HERDR["herdr server<br/>panes · agent-status"]
|
||||
WCC["claude (worker)<br/>ANTHROPIC_BASE_URL set"]
|
||||
subgraph BD["bridged — standalone daemon (not a claude process)"]
|
||||
SRV["SERVER face<br/>MCP server · REST/SSE · policy"]
|
||||
CLI["CLIENT face<br/>herdr socket client"]
|
||||
SRV --> CLI
|
||||
end
|
||||
HERDR["herdr<br/>panes · agent-status"]
|
||||
WCC["worker pane · claude<br/>ANTHROPIC_BASE_URL set · MCP client"]
|
||||
HOOK["Stop-hook<br/>long-poll client"]
|
||||
BD -->|"Unix socket<br/>send_text · events.subscribe"| HERDR
|
||||
CLI -->|"Unix socket<br/>send_text · events.subscribe"| HERDR
|
||||
HERDR -->|"drives PTY"| WCC
|
||||
WCC --- HOOK
|
||||
end
|
||||
@@ -45,23 +49,25 @@ flowchart TB
|
||||
BROKER["Broker<br/>Redis Streams / NATS JetStream<br/>inbox-primary · inbox-worker"]
|
||||
MODEL["ollama.ltms.dev /v1<br/>or GX10 vLLM<br/>(worker model)"]
|
||||
|
||||
OPUS -->|"MCP bridge_send → reply in tool result"| BD
|
||||
WCC -.->|"MCP bridge_reply / bridge_ask"| BD
|
||||
BD -.->|"SSE /events (status, for observers)"| OPUS
|
||||
OPUS -->|"MCP bridge_send → reply in tool result"| SRV
|
||||
WCC -.->|"MCP bridge_reply / bridge_ask"| SRV
|
||||
SRV -.->|"SSE status (observers)"| OPUS
|
||||
OPUS -.->|"write / long-poll (async)"| BROKER
|
||||
HOOK -.->|"long-poll / write (async)"| BROKER
|
||||
BD -.->|"bridge inbox ↔ session"| BROKER
|
||||
SRV -.->|"bridge inbox ↔ session"| BROKER
|
||||
WCC -->|"inference"| MODEL
|
||||
|
||||
classDef sub fill:#2b6cb0,stroke:#1a365d,color:#ffffff;
|
||||
classDef pick fill:#2f855a,stroke:#22543d,color:#ffffff;
|
||||
classDef warn fill:#b7791f,stroke:#7b341e,color:#ffffff;
|
||||
class OPUS sub
|
||||
class BD,HERDR,WCC pick
|
||||
class SRV,CLI,HERDR,WCC pick
|
||||
class BROKER warn
|
||||
```
|
||||
|
||||
*Figure: solid arrows = the blocking request/response `bridged`/herdr channel; dotted = the optional async
|
||||
*Figure: `bridged` is one **standalone daemon** split into a **SERVER face** (the MCP server
|
||||
the Claude sessions mount, plus REST/SSE + policy) and a **CLIENT face** (the herdr socket
|
||||
client). Solid arrows = the blocking MCP request/response channel; dotted = the optional async
|
||||
broker. The primary's env stays clean; only the worker sets `ANTHROPIC_BASE_URL`, and
|
||||
`bridged` — a plain daemon — enforces that boundary in code.*
|
||||
|
||||
|
||||
+47
-39
@@ -139,58 +139,66 @@ bridge on either side is subscription-safe by construction (see
|
||||
|
||||
## Architecture
|
||||
|
||||
`bridged` is the hub. Its **south side** speaks herdr's Unix-socket JSON-RPC; its **north
|
||||
side** speaks HTTP/SSE to synchronous clients and (optionally) a broker for async duplex.
|
||||
herdr, `bridged`, the worker panes, and the model endpoint are colocated on the
|
||||
off-subscription **worker host**; the primary reaches in over HTTP and/or the broker.
|
||||
`bridged` is a **standalone daemon** — one component, two faces:
|
||||
|
||||
- a **SERVER (north face)** — an **MCP server** the Claude Code sessions mount, plus REST/SSE
|
||||
for non-Claude clients, sitting over the session tracker, subscription guard, and reply
|
||||
rendezvous (the policy brain); and
|
||||
- a **CLIENT (south face)** — a herdr socket client that injects turns (status-gated) and
|
||||
subscribes to agent-status.
|
||||
|
||||
The Claude sessions themselves live **as panes inside herdr**. Each pane reaches *up* to
|
||||
`bridged`'s MCP server (to send/reply); `bridged`'s herdr client reaches *down* through
|
||||
herdr's socket to drive those same panes and read their status. herdr, `bridged`, the panes,
|
||||
and the model are colocated on one host (same-host scenario); a broker is optional for async
|
||||
duplex.
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
subgraph clients["NORTH — clients"]
|
||||
OPUS["Primary Opus<br/>(Claude Code, env CLEAN)<br/>MCP client"]
|
||||
BUS["External event bus<br/>(webhook / NATS / Redis)"]
|
||||
HUMAN["Human / CLI / chat UI"]
|
||||
subgraph herd["herdr — agent multiplexer (Claude sessions run here, same host)"]
|
||||
PP["primary pane · Opus<br/>env CLEAN · MCP client"]
|
||||
WP["worker pane(s) · claude<br/>ANTHROPIC_BASE_URL set · MCP client"]
|
||||
end
|
||||
|
||||
subgraph server["bridged — message server (NOT a claude process)"]
|
||||
API["North API<br/>MCP server · REST · SSE"]
|
||||
SESS["Session manager<br/>spawn · health · recycle"]
|
||||
INJ["Injector<br/>queue + status gate"]
|
||||
COLL["Reply rendezvous<br/>bridge_reply | event | pane.read"]
|
||||
GUARD["Subscription guard<br/>enforces the boundary"]
|
||||
HCL["herdr socket client<br/>NDJSON, id-correlated + events"]
|
||||
API --> SESS --> INJ --> HCL
|
||||
HCL --> COLL --> API
|
||||
SESS --> GUARD
|
||||
HCL -->|"events.subscribe"| INJ
|
||||
subgraph bridged["bridged — standalone daemon (NOT a claude process)"]
|
||||
subgraph srv["SERVER — north face"]
|
||||
MCP["MCP server<br/>bridge_send · reply · ask · status"]
|
||||
REST["REST / SSE<br/>(non-Claude clients)"]
|
||||
POL["policy brain<br/>session tracker · subscription guard<br/>· reply rendezvous"]
|
||||
end
|
||||
subgraph cli["CLIENT — south face"]
|
||||
INJ["injector<br/>status-gated"]
|
||||
HCL["herdr socket client<br/>send_text · events · pane.read"]
|
||||
end
|
||||
MCP --> POL
|
||||
REST --> POL
|
||||
POL --> INJ --> HCL
|
||||
HCL -->|"events · replies"| POL
|
||||
end
|
||||
|
||||
BROKER["Broker (optional)<br/>Redis Streams / NATS JetStream<br/>inbox-primary · inbox-worker"]
|
||||
HERDR["herdr server<br/>workspaces · panes · agent-status"]
|
||||
WCC["worker claude pane(s)<br/>ANTHROPIC_BASE_URL set<br/>MCP client"]
|
||||
MODEL["ollama.ltms.dev /v1<br/>or GX10 vLLM"]
|
||||
MODEL["ollama.ltms.dev / GX10 vLLM<br/>(worker model)"]
|
||||
BROKER["Broker (optional)<br/>Redis / NATS — async duplex"]
|
||||
|
||||
OPUS -->|"MCP: bridge_send / poll / status"| API
|
||||
BUS -.->|"async"| BROKER
|
||||
HUMAN --> API
|
||||
BROKER -.-> API
|
||||
HCL -->|"Unix socket"| HERDR
|
||||
HERDR -->|"drives PTY"| WCC
|
||||
WCC -->|"inference"| MODEL
|
||||
WCC -.->|"MCP: bridge_reply / bridge_ask"| API
|
||||
PP -->|"MCP tools"| MCP
|
||||
WP -->|"MCP tools"| MCP
|
||||
HCL -->|"Unix socket · drive + status"| herd
|
||||
WP -->|"inference"| MODEL
|
||||
POL -.->|"async"| BROKER
|
||||
|
||||
classDef core fill:#2f855a,stroke:#22543d,color:#ffffff;
|
||||
classDef ext fill:#2b6cb0,stroke:#1a365d,color:#ffffff;
|
||||
classDef warn fill:#b7791f,stroke:#7b341e,color:#ffffff;
|
||||
class API,SESS,INJ,COLL,GUARD,HCL core
|
||||
class OPUS ext
|
||||
class BROKER,HERDR,BUS warn
|
||||
class MCP,REST,POL,INJ,HCL core
|
||||
class PP ext
|
||||
class MODEL,BROKER warn
|
||||
```
|
||||
|
||||
*Figure: `bridged` translates a clean north-side message API into herdr socket calls, gating
|
||||
every injection on live agent-status events. Only the worker panes carry
|
||||
`ANTHROPIC_BASE_URL`; `bridged` itself is a plain daemon and may poll/subscribe freely
|
||||
because it consumes no Anthropic quota.*
|
||||
*Figure: `bridged` is one standalone daemon with a **SERVER** face (the MCP endpoint the
|
||||
Claude panes mount, over the policy brain) and a **CLIENT** face (the herdr socket client).
|
||||
The Claude sessions are herdr **panes**: they call *up* into the MCP server, while `bridged`'s
|
||||
client drives them *down* through herdr's socket and gates every injection on live
|
||||
agent-status. Only worker panes carry `ANTHROPIC_BASE_URL`; `bridged` holds no quota, so it
|
||||
subscribes freely. (Split-host moves the primary out of herdr — see [Deployment model](#deployment-model).)*
|
||||
|
||||
### Components
|
||||
|
||||
@@ -471,7 +479,7 @@ flowchart LR
|
||||
end
|
||||
subgraph host["Worker host (off-subscription, near model)"]
|
||||
direction TB
|
||||
BD["bridged<br/>:8080 HTTP/SSE"]
|
||||
BD["bridged<br/>:8080 MCP · REST/SSE"]
|
||||
HS["herdr server"]
|
||||
W2["worker claude pane(s)"]
|
||||
BD -->|"Unix socket"| HS --> W2
|
||||
|
||||
+11
-5
@@ -30,8 +30,12 @@ alike. Scale each kind horizontally by adding panes.
|
||||
|
||||
```mermaid
|
||||
flowchart TB
|
||||
LEAD["lead — Opus<br/>(Claude Code, env CLEAN)"]
|
||||
BD["bridged<br/>message server + router"]
|
||||
LEAD["lead — Opus<br/>(Claude Code, env CLEAN)<br/>MCP client"]
|
||||
subgraph BD["bridged — standalone daemon"]
|
||||
SRV["SERVER face<br/>MCP · REST/SSE · role router"]
|
||||
CLI["CLIENT face<br/>herdr socket"]
|
||||
SRV --> CLI
|
||||
end
|
||||
HERDR["herdr<br/>panes · agent-status"]
|
||||
WC1["w-claude-1<br/>Sonnet · CLEAN"]
|
||||
WC2["w-claude-2<br/>Sonnet · CLEAN"]
|
||||
@@ -40,9 +44,11 @@ flowchart TB
|
||||
ANT["api.anthropic.com<br/>(Pro/Max)"]
|
||||
OLL["ollama.ltms.dev<br/>(local model)"]
|
||||
|
||||
LEAD -->|"MCP bridge_send (target role)"| BD
|
||||
BD -->|"Unix socket · send_text · events.subscribe"| HERDR
|
||||
LEAD -->|"MCP bridge_send (target role)"| SRV
|
||||
CLI -->|"Unix socket · send_text · events.subscribe"| HERDR
|
||||
HERDR --> WC1 & WC2 & WL1 & WL2
|
||||
WC1 -.->|"MCP bridge_reply"| SRV
|
||||
WL1 -.->|"MCP bridge_reply"| SRV
|
||||
WC1 --> ANT
|
||||
WC2 --> ANT
|
||||
WL1 --> OLL
|
||||
@@ -52,7 +58,7 @@ flowchart TB
|
||||
classDef core fill:#2f855a,stroke:#22543d,color:#ffffff;
|
||||
classDef local fill:#6b46c1,stroke:#44337a,color:#ffffff;
|
||||
class LEAD,WC1,WC2 ext
|
||||
class BD,HERDR core
|
||||
class SRV,CLI,HERDR core
|
||||
class WL1,WL2 local
|
||||
```
|
||||
|
||||
|
||||
+11
-7
@@ -22,22 +22,26 @@ env-clean and calls `bridged`'s MCP tools.
|
||||
|
||||
```mermaid
|
||||
flowchart LR
|
||||
OPUS["Opus — primary<br/>(Claude Code, env CLEAN)"]
|
||||
BD["bridged<br/>message server<br/>(not a claude process)"]
|
||||
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/>herdr socket"]
|
||||
SRV --> CLI
|
||||
end
|
||||
HERDR["herdr<br/>panes · agent-status"]
|
||||
W["worker claude<br/>ANTHROPIC_BASE_URL set"]
|
||||
W["worker claude pane<br/>ANTHROPIC_BASE_URL set<br/>MCP client"]
|
||||
M["ollama.ltms.dev<br/>(worker model)"]
|
||||
|
||||
OPUS -->|"MCP bridge_send (blocks)"| BD
|
||||
W -.->|"MCP bridge_reply"| BD
|
||||
BD -->|"Unix socket<br/>send_text · events.subscribe"| HERDR
|
||||
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 BD,HERDR core
|
||||
class SRV,CLI,HERDR core
|
||||
```
|
||||
|
||||
- **Subscription boundary:** the *primary* never sets `ANTHROPIC_BASE_URL` (stays on
|
||||
|
||||
Reference in New Issue
Block a user