From c71175e1c77fce675020230fc7f84f6927a99f13 Mon Sep 17 00:00:00 2001 From: Dai Ha Date: Sat, 11 Jul 2026 15:52:17 +0200 Subject: [PATCH] =?UTF-8?q?wiki:=20redraw=20diagrams=20=E2=80=94=20bridged?= =?UTF-8?q?=20as=20standalone=20daemon=20(SERVER/CLIENT=20faces=20+=20MCP)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- 1-Architecture.md | 26 ++++++++------ 2-Message-Server.md | 86 +++++++++++++++++++++++++-------------------- 6-Team.md | 16 ++++++--- Home.md | 18 ++++++---- 4 files changed, 85 insertions(+), 61 deletions(-) diff --git a/1-Architecture.md b/1-Architecture.md index e88991c..97eb1fc 100644 --- a/1-Architecture.md +++ b/1-Architecture.md @@ -33,11 +33,15 @@ flowchart TB end subgraph work["SECONDARY worker host — off-subscription"] - BD["bridged
message server
(not a claude process)"] - HERDR["herdr server
panes · agent-status"] - WCC["claude (worker)
ANTHROPIC_BASE_URL set"] + subgraph BD["bridged — standalone daemon (not a claude process)"] + SRV["SERVER face
MCP server · REST/SSE · policy"] + CLI["CLIENT face
herdr socket client"] + SRV --> CLI + end + HERDR["herdr
panes · agent-status"] + WCC["worker pane · claude
ANTHROPIC_BASE_URL set · MCP client"] HOOK["Stop-hook
long-poll client"] - BD -->|"Unix socket
send_text · events.subscribe"| HERDR + CLI -->|"Unix socket
send_text · events.subscribe"| HERDR HERDR -->|"drives PTY"| WCC WCC --- HOOK end @@ -45,23 +49,25 @@ flowchart TB BROKER["Broker
Redis Streams / NATS JetStream
inbox-primary · inbox-worker"] MODEL["ollama.ltms.dev /v1
or GX10 vLLM
(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.* diff --git a/2-Message-Server.md b/2-Message-Server.md index a4d3cd2..3ee79db 100644 --- a/2-Message-Server.md +++ b/2-Message-Server.md @@ -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
(Claude Code, env CLEAN)
MCP client"] - BUS["External event bus
(webhook / NATS / Redis)"] - HUMAN["Human / CLI / chat UI"] + subgraph herd["herdr — agent multiplexer (Claude sessions run here, same host)"] + PP["primary pane · Opus
env CLEAN · MCP client"] + WP["worker pane(s) · claude
ANTHROPIC_BASE_URL set · MCP client"] end - subgraph server["bridged — message server (NOT a claude process)"] - API["North API
MCP server · REST · SSE"] - SESS["Session manager
spawn · health · recycle"] - INJ["Injector
queue + status gate"] - COLL["Reply rendezvous
bridge_reply | event | pane.read"] - GUARD["Subscription guard
enforces the boundary"] - HCL["herdr socket client
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
bridge_send · reply · ask · status"] + REST["REST / SSE
(non-Claude clients)"] + POL["policy brain
session tracker · subscription guard
· reply rendezvous"] + end + subgraph cli["CLIENT — south face"] + INJ["injector
status-gated"] + HCL["herdr socket client
send_text · events · pane.read"] + end + MCP --> POL + REST --> POL + POL --> INJ --> HCL + HCL -->|"events · replies"| POL end - BROKER["Broker (optional)
Redis Streams / NATS JetStream
inbox-primary · inbox-worker"] - HERDR["herdr server
workspaces · panes · agent-status"] - WCC["worker claude pane(s)
ANTHROPIC_BASE_URL set
MCP client"] - MODEL["ollama.ltms.dev /v1
or GX10 vLLM"] + MODEL["ollama.ltms.dev / GX10 vLLM
(worker model)"] + BROKER["Broker (optional)
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
:8080 HTTP/SSE"] + BD["bridged
:8080 MCP · REST/SSE"] HS["herdr server"] W2["worker claude pane(s)"] BD -->|"Unix socket"| HS --> W2 diff --git a/6-Team.md b/6-Team.md index 06e7ad1..3e20420 100644 --- a/6-Team.md +++ b/6-Team.md @@ -30,8 +30,12 @@ alike. Scale each kind horizontally by adding panes. ```mermaid flowchart TB - LEAD["lead — Opus
(Claude Code, env CLEAN)"] - BD["bridged
message server + router"] + LEAD["lead — Opus
(Claude Code, env CLEAN)
MCP client"] + subgraph BD["bridged — standalone daemon"] + SRV["SERVER face
MCP · REST/SSE · role router"] + CLI["CLIENT face
herdr socket"] + SRV --> CLI + end HERDR["herdr
panes · agent-status"] WC1["w-claude-1
Sonnet · CLEAN"] WC2["w-claude-2
Sonnet · CLEAN"] @@ -40,9 +44,11 @@ flowchart TB ANT["api.anthropic.com
(Pro/Max)"] OLL["ollama.ltms.dev
(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 ``` diff --git a/Home.md b/Home.md index e39f3b6..d3bf979 100644 --- a/Home.md +++ b/Home.md @@ -22,22 +22,26 @@ env-clean and calls `bridged`'s MCP tools. ```mermaid flowchart LR - OPUS["Opus — primary
(Claude Code, env CLEAN)"] - BD["bridged
message server
(not a claude process)"] + OPUS["Opus — primary
(Claude Code, env CLEAN)
MCP client"] + subgraph BD["bridged — standalone daemon (not a claude process)"] + SRV["SERVER face
MCP · REST/SSE · policy"] + CLI["CLIENT face
herdr socket"] + SRV --> CLI + end HERDR["herdr
panes · agent-status"] - W["worker claude
ANTHROPIC_BASE_URL set"] + W["worker claude pane
ANTHROPIC_BASE_URL set
MCP client"] M["ollama.ltms.dev
(worker model)"] - OPUS -->|"MCP bridge_send (blocks)"| BD - W -.->|"MCP bridge_reply"| BD - BD -->|"Unix socket
send_text · events.subscribe"| HERDR + OPUS -->|"MCP bridge_send (blocks)"| SRV + W -.->|"MCP bridge_reply"| SRV + CLI -->|"Unix socket
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