# claude-bridge — project instructions ## Bridge communication (enforced — read this first) > **Canonical block.** Everything down to §Layering is the portable bridge charter, copied verbatim > into every project that mounts the bridge MCP. Keep it byte-identical with the template in the > wiki ([Use Cases](https://git.ltms.dev/lms/claude-bridge/wiki/7-Use-Cases) → *The portable > CLAUDE.md block*); improvements go to the template first, then out to each project. Anything > specific to *this* repo lives under §Project addendum below, never inline above it. If no `bridge_*` MCP tools are mounted in this session, this section does not apply — skip it. `bridged` is the **sole communication gateway** between agents here. The orchestrating session (the **primary**) and every delegated peer (a **worker**) mount the *same* MCP server and talk only through its `bridge_*` tools. No session addresses a peer, a broker, or the network directly. ### Which role am I? — settle this before acting **Both roles read this file.** A worker runs in a git worktree of this same repo, so it inherits this `CLAUDE.md` verbatim, and every rule below is role-conditional. **Call `bridge_whoami`.** It returns `{"role":"primary"}` or `{"role":"worker","sessionId":…, "profile":…,"worktree":…,"branch":…}`, resolved by the daemon from your connection — unforgeable, and the same resolution its authorization gate uses. Don't infer what you can ask. Only if that call is unavailable, fall back to these — each is one-way, so keep reading until one fires: the reply charter in your system prompt (*"You are an off-subscription worker in the claude-bridge fleet"*) ⇒ **worker**; bridge tools prefixed `mcp__bridge__*` ⇒ **worker** (the launcher fixes that mount name; a primary's mount is named by whoever wrote its `.mcp.json`, so it varies); `ANTHROPIC_BASE_URL` set ⇒ **worker** (Claude-model workers run on a clean env, so its *absence* proves nothing). **Still unsure ⇒ act as a worker.** The two mistakes are not symmetric: a primary acting as a worker is refused by the authorization gate — loud and self-correcting — while a worker acting as the primary ends its turn with no `bridge_reply`, and the sender silently receives nothing. Fail toward the recoverable error. ### Invariants — both roles, no exceptions 1. **Never set, export, or forward `ANTHROPIC_BASE_URL`** (or `ANTHROPIC_AUTH_TOKEN`). The primary stays on subscription; only the bridge puts a worker off it, at spawn. Mounting the bridge must never move a session across that boundary. 2. **The bridge is the only channel.** Text you print in your terminal reaches nobody — the other side cannot see your screen. An answer that isn't in a `bridge_*` call is silently discarded. 3. **Identity comes from the connection, never an argument.** Workers never pass a target; you cannot act as another session. Spawn/stop/send/drain are primary-only; reply/ask are worker-only-and-only-as-itself. A call outside your role is refused, not queued. 4. **Delivery is status-gated: one message per turn.** Don't busy-poll a peer's terminal and don't re-send because a call looks slow — the bridge delivers when the peer is `idle`/`blocked`. 5. **Never drive the terminal multiplexer directly** (no `herdr` CLI, no socket). The bridge owns policy; the multiplexer owns PTYs. Going around the bridge bypasses every rule above. ### Primary (lead) — run this on every task, in order **Delegate by default — that is the job.** With the bridge mounted you are an orchestrator on a metered subscription, and workers are cheap, parallel, and disposable. The default answer to "who does this?" is **a worker**, not you. Reach for `bridge_send` before you reach for `Edit`. The steps below are the procedure — run them in order, every task, not only the big ones. 0. **Know your role** — `bridge_whoami`, once per session, before anything else. 1. **Split.** Write the unit list. Every unit carries: scope · the files or PR in question · acceptance criteria · exactly what to report back. A unit with no acceptance criteria is not ready to delegate — refine it or keep it. 2. **Gate each unit** on one question: **"can I write a brief good enough for a worker to succeed?"** — *not* "could I do this faster myself?" (usually you could; doing it yourself costs your context and your subscription, while a wasted worker turn costs a worker turn). Yes ⇒ delegate. The keep-list is closed: the conversation with the user, decomposition and planning, the final judgment call, verification, merges, and anything that depends on context only you hold. Nothing else is yours by default. 3. **Spawn every delegated unit first** — `bridge_spawn{profile, worktree:true, ticket}`, one per unit, *before* sending any. Pass `profile` explicitly: profiles differ in model and cost, not in tier, so the default is rarely what you want. 4. **Then send them all** — `bridge_send{sessionId, content, wait:false}`. Line 1 of every brief is `Load the skill.` naming the worker's playbook; those skills are opt-in and that line is what makes them reliable. Where the project ships no such skill, spell the procedure out in the brief instead. The brief is self-contained — the worker sees your message and the repo, nothing of your context, your plan, or your screen. 5. **Collect** — `bridge_poll{ticket}` → `bridge_ack{ticket, msgId}`. Answer a worker's `bridge_ask` with `bridge_send{turnId, content}` — **not** `sessionId`. A worker gone quiet is diagnosed with `bridge_status`, never by reading its terminal. 6. **Verify yourself.** Re-run the build and the checks. A worker mounts only the bridge MCP and cannot run your other tooling, and a piped command (`… | tail`) hides failures behind a zero exit — never promote a worker's "clean" to a fact. 7. **Review — fan out.** Spawn reviewers against the diff, one per dimension or per file, with `wait:false`. Never the implementer of the scope it reviews, and brief them from the diff — not from the implementer's rationale, which carries its own blind spot. Dispatch each PR's reviewers as it lands; don't wait for the last implementer. Under ~50 changed lines, skip the fan-out and read it yourself. 8. **Adjudicate, merge, tear down — yours alone.** Read the diff yourself: fully if it is small, targeted at the reported findings and the risky paths if it is large. Reviewer findings direct your attention; they never substitute for it. Then merge, then `bridge_stop{paneId}`. **Steps 3 and 4 are separate on purpose** — spawning and sending in one loop is how parallel work silently becomes serial, and it is the most common way this layer is wasted. For the same reason, prefer `wait:false` + `bridge_poll` for anything non-trivial: a blocking `bridge_send` is capped by *your own* MCP client call timeout (~60s), well below the task's real runtime. **Delegating does not delegate responsibility.** Workers open PRs; you are the gate. Never delegate the merge — and merging on a reviewer's word is delegating it by proxy. | Intent | Tool | |---|---| | Confirm your own role | `bridge_whoami` | | See backends available | `bridge_profiles` | | Start a worker | `bridge_spawn{profile?, cwd?, worktree?, ticket?}` → `sessionId` + `paneId` | | See the fleet | `bridge_list` · one worker's state: `bridge_status{sessionId}` | | Delegate (blocking) | `bridge_send{sessionId, content}` | | Delegate (long task) | `bridge_send{sessionId, content, wait:false}` → ticket → `bridge_poll{ticket}` | | Answer a worker's `bridge_ask` | `bridge_send{turnId, content}` — **not** `sessionId` | | Collect a held reply | `bridge_poll{target}` · then `bridge_ack{target, msgId}` | | Tear down | `bridge_stop{paneId}` | ### Worker — the turn contract 1. **Load the playbook skill the lead named** before doing anything else. 2. **Do the assigned scope only.** Note anything you spot outside it in one line; don't go hunt it. 3. **`bridge_ask{question}`** when a decision is genuinely the lead's (ambiguous requirement, two defensible fixes, "bug or intended?"). It blocks and you resume the *same* turn with the answer. Don't ask what you could decide yourself. 4. **End the turn with exactly one `bridge_reply{content}`**, carrying your complete answer. This is the whole handoff. No `bridge_reply` ⇒ the sender gets nothing and the exchange stalls. 5. **Report honestly.** State only what you actually ran and its real output, including failures. You mount **only** the bridge MCP — the primary's other servers (IDE, forge, docs) are not yours, so never claim the result of a check you had no way to run. 6. **Never merge.** Stage files explicitly — never `git add -A` — and leave alone anything the project marks as not-yours-to-commit. ### Where each rule lives (don't duplicate — extend the right layer) | Layer | Scope | Reaches | |---|---|---| | the launcher's reply charter | the one rule that must survive with no repo: *end every turn with `bridge_reply`* | every worker, at launch, every peer kind | | **this section** | protocol + orchestration policy | primary **and** every Claude worker — tracked in git, so worktrees inherit it | | role playbook skills | per-job procedure (commit/PR recipe, finding format) | a worker told to load one | | the bridge's own docs | design detail, flows, error model | on demand | A rule belongs in **exactly one** layer — the outermost one that must obey it. Peers that don't read `CLAUDE.md` (non-Claude adapters) get the charter only, so any rule *they* must obey belongs in the charter, not here. ## Project addendum — claude-bridge (not part of the canonical block) - **This repo is the bridge.** The daemon is `bridged`, its MCP mount is `http://127.0.0.1:8765/mcp`, and the code behind the rules above is `mcp/BridgeMcp` (tools), `auth/Authz` (the role table), `mcp/ConnectionIdentity` (connection→role), and `worker/*Launcher` (`REPLY_CHARTER`). - **Skills available to delegate:** `implementer` (worktree → commit → push → own PR) and `reviewer` (scoped review → one structured finding). Name one in every delegation. - **Never commit** `.mcp.json` (the primary's local copy, flagged `--skip-worktree`) or `wiki/` (a submodule with its own remote). - **Flows and the error model** — rendezvous, `bridge_ask`, detached delivery, turn-done fallback — are diagrammed in `docs/MCP-Contract.md` §6, kept out of this file because it loads into every session's context. ### The prompt is part of the product — update it with the code (mandatory) This repo *is* the bridge, so the canonical block above is not documentation about someone else's system: it is the instruction surface this codebase ships. **Every change here must end by asking whether the block still tells the truth.** A code change that silently invalidates it is an incomplete change — the agents reading it have no other source. Before you call any work done, check the row that matches what you touched: | You changed… | Re-read and update… | |---|---| | a `bridge_*` tool — added, removed, renamed, or its params/semantics | the primary's intent→tool table; any rule that names that tool | | `Authz` / the role table | invariant 3, and the primary-only vs worker-only claims | | `ConnectionIdentity` / how a caller is resolved | the `bridge_whoami` paragraph and the fallback ladder | | `REPLY_CHARTER`, or a launcher's mount/flags | the fallback ladder (`mcp__bridge__*`), and the layering table's top row | | the injector / status gating | invariant 4 | | worktree provisioning or the parity overlay | the "both roles read this file" premise — it rests on the worker's worktree being a checkout of this repo | | `.claude/skills/**` | the addendum's skill list, and the "name the playbook" rule | | a new peer kind (non-Claude adapter) | what that peer can read — anything it must obey belongs in its charter, not in the block | Then **propagate**: the block in this file and the template in the wiki ([Use Cases](https://git.ltms.dev/lms/claude-bridge/wiki/7-Use-Cases) → *The portable `CLAUDE.md` block*) must stay byte-identical, and other projects carrying the block need the same edit. Verify rather than trust: ```bash python3 - <<'PY' import pathlib c = pathlib.Path("CLAUDE.md").read_text() w = pathlib.Path("wiki/7-Use-Cases.md").read_text() S, E = "## Bridge communication (enforced", "## Project addendum — claude-bridge" block = c[c.index(S):c.index(E)].rstrip() + "\n" i = w.index("```markdown\n") + len("```markdown\n") print("in sync:", w[i:w.index("\n```\n", i) + 1] == block) PY ``` ## IDE MCP tools & validation workflow (enforced) > **Primary only.** Workers have no IDE MCP mount — if you are a worker, skip this section and > report the build/test output you actually ran (see §Bridge communication → Worker). Two IDE MCP servers are connected: **intellij-index** (semantic code intelligence) and **jetbrains** (file problems, reformat, debugger). IntelliJ has multiple projects open; our module is **`bridged`**. Always pass these to IDE MCP tools: - `project_path` = `/Users/dai.ha/LTMS/claude-bridge/bridged` - IDE paths are relative to `bridged/` (e.g. `src/main/java/dev/ltms/bridged/...`) ### After editing any file — mandatory 1. **`ide_sync_files{paths}`** — the built-in Edit/Write tools write to disk; the IDE index is stale until synced, or IDE nav/refactor/diagnostics give wrong results. 2. **`ide_diagnostics{file}`** (or `jetbrains get_file_problems`) — clear **all** errors *and* warnings. IDE inspections catch what a build won't (unused params/fields, redundant modifiers, resource leaks, "always same arg", …). These diagnostics are **per-file**. 3. **`mvn clean install`** (Bash) — required for **overall project health** (clean build + full test run). A per-file-clean file can still break the build or another module. This is the whole-project gate before declaring work done or committing. **Whenever dependencies change (or a `pom.xml` edit), validate CVEs with `jetbrains get_file_problems{filePath: "bridged/pom.xml"}`** — its Mend.io check reflects the dependencies on disk. (Note: `ide_diagnostics` / intellij-index does NOT re-resolve dependencies after a pom edit without a full Maven reimport, so it reports stale CVE results — don't trust it for this.) Treat a CVE warning like any other: bump to a patched version and confirm `mvn clean install` still passes. If the latest available version is still flagged (EOL line, "insufficient information", or config-file-only advisories), document it as accepted in the pom rather than chasing a fix that doesn't exist. ### Use IDE MCP tools for navigation, refactoring, and diagnostics only - **Navigate (prefer over Grep/Read for symbols):** `ide_find_definition`, `ide_find_class`, `ide_find_file`, `ide_find_references`, `ide_find_implementations`, `ide_find_super_methods`, `ide_call_hierarchy`, `ide_type_hierarchy`, `ide_search_text` (regex: `jetbrains search_in_files_by_regex`). - **Refactor (prefer over multi-file Edit / rm / mv):** `ide_refactor_rename` (position-based, updates all refs/overrides/tests), `ide_refactor_safe_delete`, `ide_move_file`, `jetbrains reformat_file`. - **Diagnose:** `ide_diagnostics` / `jetbrains get_file_problems`. ### Do NOT route build/test/one-offs through the IDE Keep `mvn` (compile/test/package/`clean install`) and **all** one-off shell commands on **Bash**. Do not use `jetbrains build_project`, `execute_run_configuration`, or `execute_terminal_command` to replace them. ### Java 25 notes Prefer the unnamed lambda parameter `_` for required-but-unused params; a non-public `static void main(String[])` is valid (JEP 512) and boots via `java -jar`.