CB-634: let a member use the IDE MCP against its own worktree — opt-in per profile #162
Open
opened 2026-08-23 15:46:19 +02:00 by ltms
·
2 comments
No Branch/Tag Specified
main
worker/fleetd-612-unita-87807e-1
worker/612-b3-mcpwirings-da2b58-3
worker/612-b2-cb185-176d3a-2
worker/612-b1-completion-457459-1
worker/612-agaps-73a926-2
worker/608-sleeps-3a64ff-3
worker/621-b4520b-1
worker/618-b83894-2
worker/fleetd-615-e05481-5
worker/lead-autocompact-5f1ab2-3
worker/fleetd-613-f85deb-3
worker/fleetd-608-flaky-nudge-test-d0c2d1-3
worker/lead-context-gauge-ad404f-1
worker/gauge-wiring-9158c1-4
worker/redeploy-slowstart-ead0e5-5
worker/charter-bytes-13668c-6
worker/rollover-outcome-291483-2
worker/589-f64303-2
worker/593-1a8025-5
worker/589-fcd2aa-1
worker/568-9fdaa2-3
worker/571-attempted-outcome-5739f7-2
worker/581-completionresolver-cas-sites-0542b7-6
worker/562-loop-health-wiring-test-99611c-5
worker/562-surface-loop-health-7df5cc-4
worker/575-waiter-cleanup-sites-62ad80-1
worker/572-answer-lock-release-46a9ae-5
worker/567-probe-channel-leak-a38fc5-6
worker/551-record-before-send-7cbf56-1
worker/561-listener-fanout-survives-a-throw-61d538-2
worker/555-redeploy-main-flow-seam-65c2f5-2
worker/556-injector-owns-registration-e027a5-1
worker/552-post-restart-mktemp-abort-bc2672-4
worker/553-onstatus-completion-leak-0da881-2
worker/550-shasum-linux-196132-1
worker/538-loop-dies-on-error-4a5eeb-6
worker/426-health-coverage-ef1fd4-4
worker/504-failed-reported-clean-3cfd66-3
worker/537-capturedlog-close-e4c437-2
worker/459-broken-link-targets-cadc17-5
worker/535-appender-leak-fe74c1-1
worker/512-part2-shutdown-detection-434701-9
worker/529-logger-level-sweep-2a5533-8
worker/528-drain-gate-call-site-5de83d-7
charter/forge-mcp-vs-token
worker/521-swap-guard-unpinned-28e931-5
worker/519-probe-test-harness-d25ab8-4
worker/525-logger-level-leak-1b4eb0-6
worker/518-fleetmcp-resolver-wiring-8ef96c-1
worker/512-drain-complete-line-7edd71-3
worker/517-abort-branch-and-jar-id-41b641-2
worker/500-9e52c9-3
worker/509-4912f4-2
worker/511-9a4b23-1
worker/493-479f45-2
worker/505-03f8b2-1
worker/492-followup-detect-unclear
worker/501-a31fa0-7
worker/498-451d1c-5
worker/494-1015ce-2
worker/492-209647-1
worker/489-001902-2
worker/480-relative-handover-path-906323-1
worker/480-b-handover-skill-45bf1f-5
worker/474-followup-source-pin-f54a55-17
worker/474-charter-check-on-reload-f54a55-17
worker/466-quarantine-repeatcount-report
worker/393-opencode-skill-seeding-71854b-13
worker/469-canonical-tool-names-2a472a-16
worker/466-quarantine-escalation-5ae9c1-15
worker/446-hot-exhausted-pattern-0af580-6
worker/464-charter-tool-name-guard-a85635-12
worker/463-listfleet-default-fails-open-f1c76c-11
worker/458-invariant-5-by-purpose-862f9a-10
worker/439-coordinator-row-gate-bc032a-8
worker/449-herdr-protocol-576015-4
worker/450-abstract-spawn-599e1c-5
worker/437-ack-refuses-177d91-1
worker/444-placement-window-feb56a-2
worker/440-helddurable-derived-d462d7-13
worker/425-rework-placement-resolve-c58ba1-9
worker/421-lead-peek-held-msgs-cdbad2-10
worker/435-fixed-policy-cap-fe11de-12
worker/422-gate-state-observability-9e79d6-11
worker/431-memberregistry-live-readers-cdbad2-10
worker/424-architect-slot-hot-038b41-7
worker/422-model-gate-spawn-c29f48-6
worker/425-default-profile-live-f55534-8
worker/415-coverage-wording-2cbf9c-5
worker/416-3ad1da-1
worker/418-588283-3
worker/deterministic-stamp-race-409-3cb7b6-10
worker/armed-reads-live-config-404-ed931f-9
worker/reply-peer-refusal-391-5a34bd-7
worker/models-allowlist-aa9e9b-3
worker/ttl-stamp-race-399-f1122f-8
worker/scrub-receipt-400-316b3e-5
worker/exhaustion-detection-395-105105-6
worker/scrub-abort-394-316b3e-5
fix/scrub-uid-abort
worker/task-scrub-517574-2
worker/t386-clock-bd5b78-4
worker/t384-scrub-813790-5
worker/t381-cc-748314-2
worker/t373-336973-2
worker/t365-3920c5-3
worker/t358-6e989b-1
worker/t355-8b321c-1
worker/fleetd-369-hermetic-git-tests-e8b19a-3
worker/fleetd-368-stale-lead-binding-f5682e-2
worker/fleetd-360-deploy-units-0d3793-1
worker/359-dead-lead-tabs-f1253b-4
worker/362-worktree-skills-c03e51-3
worker/361-coord-visibility-655144-1
362-plugin-visibility-and-drift
worker/errscan-bed2ca-2
worker/amqp-log-identity-bed2ca-2
worker/withdefaults-guard-561704
worker/sleepguard-82076d-1
worker/fd334-9ee1b6-5
worker/fd348-f1ab27-4
worker/fd335-a71c35-1
worker/fd342-174a17-2
worker/fd345-490d0f-3
worker/fleetd-337-5ec7d4-21
worker/fleetd-341-af5a6b-24
worker/fleetd-339-5ca0a2-23
worker/fleetd-338-83a4a1-22
worker/fleetd-333-281f46-18
worker/fleetd-329-11bdbb-16
worker/fleetd-330-2770fb-17
worker/fix-326-50506e-15
worker/fix-324-3e9bbf-14
worker/fix-323-b8287d-13
worker/fix-316b-bd0860-11
worker/fix-318-76ca36-9
worker/fix-317-486aec-8
worker/fix-315-ce47c5-6
worker/fix-307-275890-6
worker/fix-308-b4f664-7
worker/fix-309-ec3939-8
worker/fix-310-7a3974-9
worker/fix-302-52ad0e-9
worker/fix-298-ce1acb-8
worker/fix-297-66bd11-7
worker/fix-296-104622-6
worker/fix-293-bare-closetab-eb22b5-3
worker/fix-280-gone-ask-lapse-bca98e-2
worker/fix-290-reapidle-guard-coverage-9b0dd1-1
worker/fix-285-trust-seed-8f3565-10
worker/fix-284-backend-error-seat-85912c-11
worker/fix-282-chained-ask-e6d0bb-8
worker/fix-283-teardown-leaks-f40dfa-9
worker/fix-281-pin-handler-actions-4921ac-7
worker/audit-rendezvous-lifecycle-d072ae-2
worker/audit-health-placement-1a2476-6
worker/audit-teardown-exits-e207a5-3
worker/audit-launcher-asymmetry-27e370-4
worker/audit-rest-authz-6ca53c-5
worker/investigate-275-abandon-asking-fdef52-8
worker/fix-274-worktree-leak-b0095d-7
worker/fix-273-exhausted-pattern-9665b5-6
worker/fleetd-267-model-check-bd8068-1
worker/fleetd-131-archunit-18b834-7
worker/fleetd-266-sshagent-rename-a014ff-6
worker/fleetd-184-uid-claim-8e1f31-4
worker/fleetd-184-warn-b381ee-10
worker/fleetd-184-docs-be1d12-9
worker/fleetd-257-9bf010-7
worker/fleetd-103-23a113-6
worker/fleetd-247-342356-5
worker/fleetd-116-04dea8-4
worker/fleetd-252-a830e0-3
worker/fleetd-111-7e8673-9
worker/fleetd-155c-f8ef4b-8
worker/fleetd-176-b928ca-3
worker/fleetd-249-7a7878-2
worker/cb248-composition-root-b-9acdf7-15
worker/cb148-envrc-default-fa6c82-12
worker/cb201-unit5-wiring-6c12e6-8
worker/cb241-fallback-echo-1175e9-11
worker/cb149-trust-dialog-2392a5-9
worker/cb134-148-overlay-visible-c9b986-10
worker/cb234-session-id-keyed-04e1fc-1
worker/cb201-unit3-nudge-abdf5c-6
worker/cb201-unit2-policy-c1102c-5
worker/cb201-unit4-outcome-a13bfa-7
worker/cb201-unit1-classifier-91b9b1-4
worker/cb201-227-refine-831980-3
worker/cb175-model-readback-0f085f-1
worker/cb222-charter-tmpdir-17f013-1
worker/cb226-architect-slot-race-cd3aa8-3
worker/cb224-worktree-root-group-024523-2
worker/cb-123-role-demotion-c600f7-2
worker/cb-219-opencode-roots-1f677e-1
worker/cb214-claude-session-id-b9eab4-4
worker/cb213-zdotdir-wrong-process-dd6de4-3
worker/cb211-exhaustion-classification-9546e0-2
worker/cb137-ambiguous-task-4df3d8-4
worker/cb209-agentsessionid-4dfdb6-2
worker/cb185-hostenvnames-2692b5-3
worker/cb206-opencode-sqlite-128718-2
worker/cb185-worktree-group-fc0c99-1
worker/cb-137-ask-ticket-e7760c-2
worker/cb-172-broker-uri-d36ae4-4
worker/cb-175-model-readback-76ead6-3
worker/cb-161-pane-ancestry-293510-1
worker/cb-164-rebase-885863-8
worker/cb-164-empty-scrape-false-success-1a80af-3
fix/cb-197-ticket-ttl-from-completion
worker/cb-189-remote-url-coverage-4692f3-1
worker/cb-185-blockers-027756-4
worker/cb-192-gap-log-11b631-2
worker/cb-633-fix-5f4396-3
worker/cb185-router-d6436d-3
worker/cb185-router-routing-gaps-9e9d33-3
worker/cb185-paneids-992586-2
worker/cb-633-allow-list-union-ed374b-1
worker/cb-157-credential-in-remote-url-496e44-2
worker/cb-641-health-herdr-evidence-8f1f54-6
worker/cb-640-health-msg-evidence-99c9cd-1
worker/cb-642-fleets-status-skill-bbbc40-5
cb-634-ide-mcp
worker/lead-comms-wiring-c014b9-7
worker/lead-mailbox-c19577-6
worker/autocompact-window-82bc2f-5
worker/cb-634-probe-18056f-4
worker/cb635-broker-urienv
worker/cb-632-config-retry-8e0efa-7
lead/cb-622e-claude-md
lead/cb-622-followup
worker/cb-622a-165dff-1
lead/cb-622d-opencode-mount
worker/cb-622b-717c67-2
worker/cb-622c-ab7759-3
worker/cb-617b2-20ca4b-3
worker/cb-617a-5c2f4a-1
worker/cb596-4e49ef-3
worker/cb586-10500c-1
worker/cb-606-b9343a-25
worker/cb604-1445f8-24
worker/cb582-477374-21
worker/cb584-8c2281-22
worker/cb600-e6b9a9-20
worker/cb602-ce257f-19
worker/cb601-b42837-18
worker/cb598-6c7ba7-17
worker/cb599-740fe4-16
worker/cb597-282224-15
worker/cb590fix-185e9a-10
worker/cb528-recovery-race
worker/cb594-96bead-8
worker/cb590-916766-2
worker/cb527-997d99-3
worker/cb592-env-leak-3cbf9c-1
worker/cb588-async-ticket-nudge-3218f7-5
worker/cb578b-9dcb13-6
worker/cb581-d24826-5
worker/m2-u5-ef8c42-15
worker/cb578a-516499-2
worker/cb576-01a04b-17
worker/cb579-lead-tab-acba06-20
worker/cb580-terminal-health-ed6058-21
worker/cb577-f36fdc-18
worker/cb573b-3db06f-16
worker/cb568c-f36fdc-18
worker/cb568-drop-cause-c3ac1c
worker/cb575-cancelled-notification-c3ac1c
worker/m4-sol-a2cbec-3
worker/cb574-async-ask-c3ac1c
worker/cb573-health-model-8ca857-14
worker/cb572-unknown-target-7f2e35-13
worker/u4-700706-9
worker/u3-b9fcb6-6
worker/u2-ef5b68-4
worker/u1-469dce-1-clean
worker/u1-469dce-1
worker/cb-564-health-events-70cf7e-2
worker/cb-565-recycle-drops-role-98e58f-3
worker/cb-563-missing-reply-df2866-1
worker/cb-562-readiness-gate-silent-6c23c9-3
worker/cb-560-architect-presence-da8155-1
worker/cb-561-architect-silent-off-a71cab-2
worker/cb-548-bind-architect-slot-fe1b8c-1
worker/parity-overlay-settings-5fb711-1
secrets-central-store
cb-559-hot-key-correction
cb-557-fleet-role-pools
worker/cb-553-maxload-explicit-spawn-305ee3-6
worker/cb-551-idle-lead-heartbeat-f1633c-1
worker/cb-544-drain-preserves-worktree-925fad-3
worker/cb-552-docs-sync-1cb9cf-4
worker/cb-548-rendezvous-guard-rebased
worker/cb-548-rendezvous-guard-116b53-10
worker/cb-548-authz-v2-586df6-8
worker/cb-548-authz-264363-5
salvage/cb-528b-codex-home
salvage/cb-528a-codex-launcher
CB-518-primary-flow
feature/peer-launcher-spi
cb-103-injector
v1.1.0
v1.0.0
Labels
Clear labels
blocked
needs-live-proof
ready-to-delegate
silent-default
Cannot start until something else lands. The body says what.
Merged and green, but never shown working on the running daemon. Not the same as done.
Scope, files and acceptance criteria are written. A worker can be briefed from the body alone.
A feature that compiles, passes tests, and ships turned off. Nine recurrences and counting.
No Label
Milestone
No items
No Milestone
2.0 — one operation centre, many hosts
Projects
Clear projects
No project
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: fleet/fleetd#162
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Raised 2026-08-23 from the
kbhost, after wiring its lead to the IDE Index MCP. Operator ask: the fleet should use IDE MCP tools, not just the lead.Status: design agreed, ready to build. Full design note lives on the
kbhost atfleetd/docs/CB-634-Worker-IDE-Worktree.md(untracked); this ticket carries its essence so it is durable.Relationship to other tickets
project_pathinCLAUDE.md) stays separate — it is an operator action, not this code change.Goal
Let a member use IntelliJ code intelligence against its own worktree — opt-in per profile, default off — without reopening the CB-523/CB-525 path-confusion bugs.
Today a member gets nothing:
GitWorktrees.isolateToolSurfaceneutralizes each worktree's.mcp.jsonto{"mcpServers": {}}, andparityOverlaywithholds.claude/settings.local.json. That is correct and this ticket does not undo it. The member's mount arrives by launcher flag or not at all.Why this is newly safe (the rebuttal to #117 §3)
Measured live on the
kbhost with two projects open:127.0.0.1:29170serves every open project; each call selects its project with aproject_pathargument.project_patherrors instead of guessing. So the CB-525 failure — a worker silently navigating the primary's tree — becomes structurally preventable by pinningproject_pathto the member's own worktree, rather than by withholding the server.read_file,file_structure, and the build/terminal tools are disabled, so this does not hand a member a second way to run commands (answers #117 §3(b)).Design
ideMcpUrl(String, null/blank means off) toFleetConfig.Profile. A URL, not a boolean — host and port are host-specific, mirroringmcpUrl. Default off. So a member gets the IDE only on a host where the IDE is actually mounted (e.g.kb), and nothing on a host with no IDE (e.g. the Mac today)..mcp.json. InClaudeCodeLauncher.argvWithFleet, extend the inline--mcp-configJSON with a second server namedintellijwhenideMcpUrlis set. ⚠ The currentcfg.hasMcp()gate keys onmcpUrlalone and must also fire when onlyideMcpUrlis set, or the flag is never emitted.ideMcpUrlis set, append an IDE charter fragment: "prefer IDE MCP tools over grep; everyide_*call must passproject_path=<your worktree>and no other." CB-618 forbids--append-system-promptand--append-system-prompt-fileon the same command line, so this folds into the existing charter combination, ordered role -> ide -> reply. The reply charter stays last — it is the rule that must survive. This is what replaces the hand-pasted "IDE MCP Tools" block some projects added to their ownCLAUDE.md: the rule now rides the launch charter, gated on the mount actually being present.git worktree add, shellidea <worktree>(the native launcher forwards into the running IDE). At release, close the project beforeWorktrees.remove(). Ordering is load-bearing: aworktree remove --forceunder a live IDE project leaves a stale project pointing at a deleted directory. A member must not own this.ide_set_project_mode/ide_release_project. TheideaCLI has no "close project" verb, so this is the only close mechanism.Files (from the note)
config/FleetConfig.javaProfile.ideMcpUrlcomponent + factory overloads + compact-constructor defaultconfig/ConfigRef.javamember/ClaudeCodeLauncher.javaargvWithFleet: second MCP server + IDE charter fragment; fix thehasMcp()gatesession/GitWorktrees.javaisolateToolSurfaceuntouchedsession/SessionManager.javabridged/fleetd.example.yamlideMcpUrl; also fix the staleparityOverlaydefault that still lists.claude/settings.local.jsonFleetConfigTest,GitWorktreesTest,ClaudeCodeLauncherargv testsGuard rails — do not regress
.mcp.jsontoparityOverlay(CB-525); keepisolateToolSurfaceneutralizing it unconditionally..claude/settings.local.jsontoparityOverlay. It pre-approvesmcp__intellij-*grants a member must not hold ambiently.dormantmode.Non-goals
OPENCODE_CONFIG, not inline flags (CB-402), and does not readCLAUDE.mdat all. Extending both the mount and the guidance to opencode is a separate follow-on ticket..mcp.jsonneutralization.Verification
mvn clean installinfleetd.ideMcpUrlset;fleet_whoami-> confirm itsworktree.ide_project_statuslists the worker's worktree as its own project.ide_*call errorsmultiple_projects_open; the pinned call succeeds and returns only paths under the member's worktree — never a path in the primary checkout..mcp.jsonis still{"mcpServers": {}}and still--skip-worktree.Design change (operator, 2026-08-23): deliver the IDE guidance as an on-disk overlay at spawn, not as a system-prompt charter.
Reason: a project usually ships its own
CLAUDE.md, and we must not clobber it. An overlay file sits beside the project file and merges with it. Confirmed against OpenCode's own docs (opencode.ai/docs/rules): OpenCode readsAGENTS.md(primary) andCLAUDE.md(fallback), but notCLAUDE.local.md; its combine-don't-replace seam is theinstructionsfield inopencode.json.So the delivery is backend-specific:
CLAUDE.local.mdinto the worktree root at spawn. Claude reads it and merges with the project's ownCLAUDE.md.opencode.jsoninstructionsarray.The IDE mount (
--mcp-configintellijserver) is unchanged. Only the IDE guidance text moves out of--append-system-prompt-fileand into the overlay.Safety gate (the key point): a provisioned worktree's
.gitis a regular file (a gitdir pointer); the primary's main checkout's.gitis a directory. Write the overlay only when<cwd>/.gitis a regular file, so a non-worktree spawn can never pollute the real repo. Add the overlay filename to the worktree's.git/info/excludeso it never shows as untracked and a worker cannot stage it. Teardown is free — the file dies with the worktree.This supersedes the "guidance as charter" step in the design above. Content scope for the first cut: the IDE guidance only; the canonical bridge-block delivery can reuse the same overlay later.
Implemented (Mac lead, 2026-08-24). Not yet merged to
main.The design here is built and deployed. It is live on branch
cb-634-ide-mcp(tip7655f1b), 918 tests green, and proven end to end on the fleet01 host with zero manual IDE steps. Please do not file a new issue for this — it is #162, and it is done pending merge.What shipped, and where it went beyond the plan above:
CLAUDE.local.mdin the worktree root; opencode → anide-rules.mdfile added to the generated config'sinstructionsarray. The.git-is-a-regular-file safety gate is in place.intellijserver + guidance), so it is no longer a non-goal. The follow-on ticket the Non-goals section reserved is not needed.bridged/, so opening the worktree root imports no module andide_*resolves nothing. The overlay now pinsproject_pathto<worktree>/bridged, and the IDE opens that same dir.idea <worktree>. Two new opt-in per-Profilekeys, read only whenideMcpUrlis set:ideProjectDir(the module subdir) andideOpenCommand(e.g.env DISPLAY=:10.0 idea {dir}, run through/bin/sh -c, best-effort and non-fatal). Both are documented infleetd.example.yaml.info/excludeentry was written to the per-worktree gitdir, which git ignores for a worktree — git reads a worktree's excludes from the common dir. SoCLAUDE.local.mdshowed as untracked and could be swept into a worker's PR. It now writes to the common dir; verified live that the overlay is not untracked.Deferred (not shipped): the close half — §4's close-before-
Worktrees.remove()ordering and §5'side_release_project. So open IDE projects accumulate; nothing closes them yet. This is the main open piece.Guard rails held:
GitWorktrees.isolateToolSurfacestill neutralizes.mcp.jsonunconditionally;.mcp.jsonand.claude/settings.local.jsonare still absent fromparityOverlay.Live proof on fleet01: spawned a
localmember; the daemon logged the auto-open of<worktree>/bridged;ide_project_statuslisted that module as an open project;ide_find_classresolved the member's ownClaudeCodeLauncheragainst its worktree (stale:false).Next: build the close half, then merge to
mainand add thewiki/11-Features.mdentry.