8311f2db7f
The eleven tool names become fleet_* throughout the portable block. The fallback ladder keeps mcp__bridge__* unchanged and that is deliberate: both launchers still mount the server as "bridge", so a spawned member really does see that prefix. Renaming the mount is a separate surface CB-622 did not touch. Separately, a pre-existing defect: the ladder quoted the reply charter as "You are an off-subscription worker in the claude-bridge fleet", while REPLY_CHARTER says "You are a spawned member in the claude-bridge fleet". A member matching that quote found nothing, so the ladder's first rung could never fire. Now quoted verbatim. wiki/7-Use-Cases.md is advanced to the matching template commit; the sync check prints in sync: True.
359 lines
24 KiB
Markdown
359 lines
24 KiB
Markdown
# 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 `fleet_*` 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 **member**) mount the *same* MCP server and talk only
|
||
through its `fleet_*` tools. No session addresses a peer, a broker, or the network directly.
|
||
|
||
### Which role am I? — settle this before acting
|
||
|
||
**Every role reads this file.** A member runs in a git worktree of this same repo, so it inherits
|
||
this `CLAUDE.md` verbatim, and every rule below is role-conditional.
|
||
|
||
**Call `fleet_whoami`.** It returns `primary`, `worker`, or `architect`, resolved by the daemon from
|
||
your connection — unforgeable, and the same resolution its authorization gate uses. A worker also
|
||
carries its `sessionId`, `profile`, `worktree` and `branch`; an architect carries the slot name it
|
||
was bound to. 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 a spawned member in the
|
||
claude-bridge fleet"*) ⇒ **spawned member**; bridge tools prefixed `mcp__bridge__*` ⇒ **spawned
|
||
member** (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 ⇒ **spawned member** (Claude-model members run
|
||
on a clean env, so its *absence* proves nothing). None of these separate a worker from an architect —
|
||
only `fleet_whoami` does. **Still unsure ⇒ act as a worker**, the most restricted member role. The
|
||
two mistakes are not symmetric: a primary acting as a worker is refused by the authorization gate —
|
||
loud and self-correcting — while a member acting as the primary ends its turn with no `fleet_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 member 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 `fleet_*` 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/drain are lead-only; **send is lead or architect**;
|
||
reply/ask are only-as-itself — any peer may answer for its own pane, and for no other. 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` or
|
||
`done`. A spawned member must **also** have mounted the bridge MCP: until it has, it is not
|
||
deliverable, and a send waits on that gate for ~60s and then fails without ever reaching its pane.
|
||
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 `fleet_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** — `fleet_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** — `fleet_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** — `fleet_send{sessionId, content, wait:false}`. Line 1 of every brief is
|
||
`Load the <name> 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** — `fleet_poll{ticket}` → `fleet_ack{target, msgId}`. Answer a worker's `fleet_ask`
|
||
with `fleet_send{turnId, content}` — **not** `sessionId`. A worker gone quiet is diagnosed with
|
||
`fleet_status`, never by reading its terminal; it also reports an open question and the `turnId`
|
||
that answers it. **A worker's ask waits ~55 seconds, and no nudge makes that longer** — so never
|
||
brief a worker to "ask me". Decide before you delegate, or give it an explicit default.
|
||
6. **Verify yourself.** Re-run the build and the checks. A worker cannot run your IDE tooling, any
|
||
forge tools it appears to have hold a blocked credential and fail, 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 `fleet_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` + `fleet_poll` for anything non-trivial: a blocking `fleet_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 | `fleet_whoami` |
|
||
| See backends available | `fleet_profiles` |
|
||
| Start a member | `fleet_spawn{role?, profile?, cwd?, worktree?, ticket?, sessionName?, resumeSessionId?}` → `sessionId` + `paneId` |
|
||
| See the fleet | `fleet_list` → `leads` (your peers) + `members` (each carries `agentSessionId` when its backend knows one) · one peer's state: `fleet_status{sessionId}` |
|
||
| Delegate (blocking) | `fleet_send{sessionId, content}` |
|
||
| Delegate (long task) | `fleet_send{sessionId, content, wait:false}` → ticket → `fleet_poll{ticket}` |
|
||
| Answer a member's `fleet_ask` | `fleet_send{turnId, content}` — **not** `sessionId` |
|
||
| Message a **peer lead** | `fleet_send{sessionId: <their terminal>, content}` — `fleet_list` → `leads` reports it. Coordination only, **never** a task |
|
||
| Answer a peer lead that messaged you | `fleet_reply{content}` — the one case a lead replies |
|
||
| Collect a held reply | `fleet_poll{target}` · then `fleet_ack{target, msgId}` |
|
||
| Tear down a member | `fleet_stop{paneId}` |
|
||
|
||
### Lead ↔ lead — coordinate, never delegate
|
||
|
||
`fleet_list` returns `leads` alongside `members`; your own row carries `self: true`. Every other row
|
||
is a peer — an orchestrator with its own context, its own members, and its own judgment. An empty
|
||
`members` array means no members are spawned; it says nothing about peers.
|
||
|
||
**A lead never assigns a task to another lead.** Work goes to members — only ever downward, never
|
||
sideways. Sending a peer a brief with acceptance criteria is a category error: a brief is a member's
|
||
artefact, and a peer is not yours to task. If a unit needs doing and it falls in your area, spawn a
|
||
member and delegate it yourself; if it falls in the peer's area, say so and let the peer assign it.
|
||
The traffic between leads is coordination and nothing else:
|
||
|
||
1. **Divide the map, not the work.** Agree who owns which area, then each of you assigns inside your
|
||
own. Split by **context ownership** — whoever already holds the context owns that area — and say
|
||
who takes what, in one message, before either of you starts. Two leads silently working the same
|
||
unit is the failure mode here, and neither notices until the merge.
|
||
2. **Share findings, hazards, and corrections.** What you have already discovered, what broke, what
|
||
the next person will trip on. This is the traffic that actually pays for the channel: it costs one
|
||
message and saves a peer a rediscovery.
|
||
3. **Verify a peer exactly as you verify yourself.** Peer status buys nothing: check the claim
|
||
against the code, and re-run the build. A peer's correction gets the same treatment — right or
|
||
wrong on the evidence, not on who said it. Neither of you merges the other's work unreviewed.
|
||
|
||
Being messaged by a peer does not make you its worker: answer with `fleet_reply`, and push back on
|
||
the substance if it is wrong. A peer that simply complies has thrown away the reason there are two of
|
||
you.
|
||
|
||
### Member (worker or architect) — 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. **`fleet_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 `fleet_reply{content}`**, carrying your complete answer. This is
|
||
the whole handoff. No `fleet_reply` ⇒ the sender gets nothing and the exchange stalls.
|
||
Do **not** lean on the completion fallback to carry your answer for you: when you end a turn
|
||
without replying, the bridge scrapes your pane, and it can return only the last 4000 characters.
|
||
A clipped scrape is marked as partial, but the missing text is gone — your report reaches the
|
||
lead with its end cut off.
|
||
5. **Report honestly.** State only what you actually ran and its real output, including failures,
|
||
and never claim the result of a check you had no way to run. **Measure your own tools; do not
|
||
assume them.** What you mount depends on your backend: an opencode member gets the bridge and
|
||
nothing else, while a Claude Code member also inherits the operator's user-scope MCP servers,
|
||
which the bridge never chose for you. Two rules follow. The primary's IDE tooling is still not
|
||
yours, whatever you see. And **a mounted tool is not a working tool** — the forge server you may
|
||
find there holds a deliberately blocked credential and fails every call, by design.
|
||
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 `fleet_reply`* | every spawned member, at launch, every peer kind — never a lead |
|
||
| **this section** | protocol + orchestration policy | primary **and** every member that reads the repo — tracked in git, so worktrees inherit it |
|
||
| role agent definition files | role contract and per-job procedure | a member whose launcher binds its role to the matching file in its worktree |
|
||
| role playbook skills | per-job procedure (commit/PR recipe, finding format) | a member 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. A member without a
|
||
repo checkout still gets the launcher's reply charter, which is why that one rule stays there.
|
||
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.
|
||
- **Primary-side skills** (not delegation playbooks — a worker cannot use them):
|
||
`port-to-opencode` (make an OpenCode session a participant in this workspace).
|
||
- **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, `fleet_ask`, detached delivery, turn-done fallback —
|
||
are diagrammed in `docs/MCP-Contract.md` **§6 only**. The rest of that page is a pre-build design
|
||
doc whose tool names, parameter names and REST paths never caught up with the code, so do not use
|
||
it as the tool reference (CB-609). Section 6 is kept out of this file because this file loads into
|
||
every session's context.
|
||
|
||
### Redeploying the daemon — the lead may do this (primary only)
|
||
|
||
**A merge is not a deployment.** The running `bridged` holds the jar it was started with, so a
|
||
feature merged to `main` does nothing until the daemon is rebuilt and restarted. Saying "shipped"
|
||
about code the live daemon has never loaded is a false report. The lead **may and should** redeploy
|
||
rather than hand the job back to the operator.
|
||
|
||
Workers must never do this. A worker has no business restarting the daemon it is talking through,
|
||
and stopping it kills the worker's own channel mid-turn.
|
||
|
||
**Use the script — do not hand-roll the steps.**
|
||
|
||
```bash
|
||
scripts/redeploy-bridged.sh --check # report state, change nothing
|
||
scripts/redeploy-bridged.sh # build, confirm drain, restart, verify
|
||
scripts/redeploy-bridged.sh --yes # skip the drain prompt (fleet already checked)
|
||
```
|
||
|
||
It builds before it stops anything, so a failed build never leaves the fleet down; it waits for the
|
||
old process to exit rather than assuming; it polls `/healthz`; and it anchors its log checks to a
|
||
line marker taken before the restart, so old errors cannot be misread as new ones. Run `--check`
|
||
first — it is read-only and reports whether the forge token resolves, which nothing else tells you.
|
||
|
||
The script encodes the five things below, each of which has gone wrong here before. Read them anyway:
|
||
if the script is unavailable or a step fails, this is what it was protecting you from.
|
||
|
||
1. **Login shell, or workers silently lose their forge token.** The daemon inherits
|
||
`WORKER_GITEA_TOKEN` from the shell that starts it, and that comes from
|
||
`${SHARED_ENV}/tools/secrets.sh`. Start it from a non-login shell and the variable is empty, the
|
||
daemon starts fine, and the failure appears much later as workers that cannot open a PR. Nothing
|
||
logs this at startup — the script's `--check` is the only thing that reports it, and it checks
|
||
whether the name resolves without ever printing the value.
|
||
2. **Drain live members first.** `fleet_list`, then `fleet_stop` each member, and collect anything
|
||
you still want with `fleet_poll` before you kill anything. A restart drops in-flight tickets and
|
||
rendezvous, and a member's report is not recoverable once its ticket is gone.
|
||
3. **A restart is the only way deferred config keys take effect.** That is usually the reason to do
|
||
it. The startup log names which keys it accepted and which it deferred — read those lines rather
|
||
than assuming.
|
||
4. **Re-check identity afterwards.** Call `fleet_whoami` and confirm it still answers `primary`. The
|
||
lead is found by its tab label (`fleet.leaders.*.tab`), and a lead whose tab no longer matches is
|
||
demoted to worker, which refuses every orchestration call.
|
||
5. **Prove the new jar is the one running.** Confirm a *fresh* `bridged listening` line at the end of
|
||
`bridged/bridged.out`, dated after the restart. An old daemon that never died looks identical from
|
||
the outside.
|
||
|
||
**Permission.** A `CLAUDE.md` rule grants intent, not tool permission — the command classifier
|
||
refuses a bare `kill` on the daemon whatever this file says. The script is the seam that fixes that:
|
||
it is one auditable command, so the operator allow-lists it once instead of approving a stop and a
|
||
start every time. The rule lives in the operator's Claude Code settings:
|
||
|
||
```json
|
||
{ "permissions": { "allow": ["Bash(scripts/redeploy-bridged.sh:*)"] } }
|
||
```
|
||
|
||
Granted by the operator on 2026-08-15. If a call is still refused, do **not** route around it by
|
||
running the stop and start as separate commands — that is exactly the approval the script replaced.
|
||
Say what you were going to run and why, and let the operator decide.
|
||
|
||
### 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 `fleet_*` 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 `fleet_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 |
|
||
| **anything an operator can use, configure, or observe** — an MCP tool, a `bridged.yaml` knob, an endpoint, a visible behaviour | **[Features](wiki/11-Features.md)** — one entry: what it does · the knob that turns it on · **why it exists** · the gotcha |
|
||
|
||
That last row is not bookkeeping. Chapters 1–10 answer *how is this built* and *why this way*;
|
||
none of them has a home for *what can it do and how do I turn it on*, so for twenty tickets a
|
||
shipped capability landed nowhere and the Roadmap went on claiming the stage was finished. The
|
||
*why* line is the one that matters — without it a decision gets re-litigated from scratch a month
|
||
later. Internal contract changes go to `wiki/9-Implementation.md` instead; test and coverage work
|
||
is a Roadmap line. A change that touches none of the three earns no entry, and that is a normal
|
||
outcome rather than an omission.
|
||
|
||
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`.
|