Skip to content

fix(claude): portable launch commands and host-aware init next steps (#2462, #2453) - #2470

Open
bradygaster wants to merge 7 commits into
devfrom
squad/2462-2453-claude-init-portable
Open

bradygaster wants to merge 7 commits into
devfrom
squad/2462-2453-claude-init-portable

Conversation

@bradygaster

@bradygaster bradygaster commented Nov 12, 2026 •

Copy link
Copy Markdown
Collaborator

Two first-run fixes from the Claude Code end-to-end test (epic #2438, checklist #2469).

Closes #2462
Closes #2453

#2462: committed files carry no machine paths

With the Squad CLI installed (global, project, or a source build), squad init and squad upgrade wrote node /abs/path/cli-entry.js state-mcp into .mcp.json, the other hosts' MCP configs and every Claude hook in .claude/settings.json. Any other clone failed, and the commit leaked the local username and layout.

Committed files now use a portable form, chosen in resolveCommittedSquadStateMcpSpec (mcp-spec.ts), which every writer of committed files calls (init, upgrade, syncClients, squad client list, read-only):

Running CLI Committed command
installed (local-entry) node .squad/squad.mjs state-mcp: the repository launcher
standalone bundle squad state-mcp (bundles put squad on PATH and may have no Node)
run through npx (pinned) unchanged: npx -y @bradygaster/squad-cli@<version> state-mcp
  • Repository launcher. It's generated from the same template as the plugin launcher from feat(claude): Squad Claude Code plugin and team dashboard (#2443, #2459, #2460) #2463 (squadRepoLauncher in claude-plugin.ts), so there's one implementation. It resolves SQUAD_CLI, then the repository's node_modules, then squad on PATH, skipping a CLI older than the version that wrote it. It uses npx only with SQUAD_ALLOW_NPX=1. It finds the repository from its own location, not the working directory. A user-authored file at that path is never overwritten; Squad keeps the old spec instead.
  • Found on this machine too. squad init and squad upgrade record the CLI entry in <Squad home>/cli.json (outside the repository). Both launchers try it after PATH, so a CLI that only runs by path (a source build, CI) works on the machine that set up the repository. Package-runner caches (_npx, dlx) are never recorded, and keep the exact-version npx command instead.
  • Safe writes. The launcher path goes through resolveInsideRoot, so symlinks can't redirect the write outside the workspace. It lives at .squad/squad.mjs, not under bin/, which many repositories ignore.
  • Upgrade matrix. .squad/squad.mjs is declared Squad-owned in upgrade-matrix.json and the upgrading guide. That changes the harness hash, so the recorded Linux and Windows runs are refolded from this PR's matrix run.
  • Claude hooks call node "$CLAUDE_PROJECT_DIR/.squad/squad.mjs" hook claude <Event>, the documented form for project hooks. isSquadHookHandler matches that exact shape, so refresh and rollback still strip only Squad's handlers, and squad upgrade replaces old machine-specific handlers.
  • squad doctor gets a new portable squad_state launch check. It fails on a committed path that doesn't exist on this machine or a missing launcher, and warns on this machine's own absolute path.
  • x-squad.machineSpecific is now false for the portable forms.
  • The plugin's scripts/squad.mjs was regenerated from the shared template. The only change is a projectStart() helper, with the same behaviour. It's still pinned to 2.0.0-preview.4.

#2453: init names the host you chose

squad init --client claude ended with "Run copilot --agent squad" and a Copilot-only tip. initNextSteps now builds the closing lines from the chosen hosts:

  • Claude Code: claude --agent squad --mcp-config .mcp.json, or claude in plugin mode, plus a matching claude -p tip.
  • Other hosts: one line each.
  • No --client: Copilot, as before.

Testing

  • New test/portable-launch.test.ts (15 tests) covers the spec mapping, launcher writes (created, unchanged, updated, a user file skipped), hook form, merge and strip, the look-alike guard, and the launcher run for real (project install, older CLI skipped, SQUAD_CLI, hooks a no-op until opted in). It also covers the doctor check.
  • New test/init-next-steps.test.ts (5 tests).
  • Updated: test/cli/upgrade-portability.test.ts now asserts the portable form and that no machine path is present; mcp-spec-init source check; the Copilot snapshot in host-projection guard 1 (.mcp.json hash only: the launch command is the intended change).
  • Manual: squad init --client claude from a source build in a scratch repo writes no /Users/ path anywhere. The hooks come out in $CLAUDE_PROJECT_DIR form and one runs from another directory. The launcher skips the Homebrew preview.3 on PATH and prints install instructions.
  • Full npm test locally: 13,432 passed, 32 failed. The failures are the known macOS ones (export-import, upstream-, memory-, profile-fs-guard), files that fail only under full-suite load (they pass alone: hostile-integration, squad-observer, gh-aw), and three that fail the same way on a clean origin/dev worktree (the squad-20 monorepo-subfolder and satellite-repo bridge scenarios, and upgrade-profile-teamroot).
  • npm run lint clean; docs markdownlint and cspell clean for the changed files.

Docs: features/mcp.md explains the launcher; scenarios/troubleshooting.md covers "squad_state or Claude hooks fail after cloning". There are changesets and [Unreleased] CHANGELOG entries; no version bump.

🤖 Generated with Claude Code

bradygaster and others added 2 commits November 11, 2026 19:05
`squad init --client claude` ended with "Run copilot --agent squad" and a
Copilot-only tip. initNextSteps builds the closing lines from the chosen
hosts: Claude Code gets `claude --agent squad --mcp-config .mcp.json` (or
`claude` in plugin mode) and a matching `claude -p` tip, other hosts get
one line each, and no --client still means Copilot.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…2462)

With the CLI installed, init and upgrade wrote `node /abs/cli-entry.js
state-mcp` into .mcp.json, the other hosts' MCP configs and every Claude
hook, so other clones failed and the commit leaked local paths.

Committed files now come from resolveCommittedSquadStateMcpSpec:
- an installed CLI becomes `node .squad/bin/squad.mjs state-mcp`, a
  launcher generated from the plugin launcher's template that finds a
  CLI per machine (SQUAD_CLI, the repo's node_modules, squad on PATH;
  npx only with SQUAD_ALLOW_NPX=1) and skips older CLIs
- a standalone bundle becomes `squad state-mcp`; pinned npx is kept
- Claude hooks run the launcher through "$CLAUDE_PROJECT_DIR", and
  isSquadHookHandler recognises that exact form for refresh and rollback

`squad doctor` gains a portable-launch check. The plugin launcher is
regenerated from the shared template (same behaviour, still preview.4).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Copilot AI auto review requested due to automatic review settings November 12, 2026 03:05
@github-actions

github-actions Bot commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

🟠 Impact Analysis — PR #2470

Risk tier: 🟠 HIGH

📊 Summary

Metric Count
Files changed 25
Files added 4
Files modified 21
Files deleted 0
Modules touched 6

🎯 Risk Factors

  • 25 files changed (21-50 → HIGH)
  • 6 modules touched (5-8 → HIGH)

📦 Modules Affected

docs (3 files)
  • docs/src/content/docs/features/mcp.md
  • docs/src/content/docs/scenarios/troubleshooting.md
  • docs/src/content/docs/scenarios/upgrading.md
root (5 files)
  • .changeset/init-next-steps.md
  • .changeset/portable-launch.md
  • CHANGELOG.md
  • plugins/squad/scripts/squad.mjs
  • test-fixtures/spec/suite-v0.2/upgrade-matrix.json
scripts (1 file)
  • scripts/docs-site-location.mjs
squad-cli (7 files)
  • packages/squad-cli/src/cli/commands/client.ts
  • packages/squad-cli/src/cli/commands/doctor.ts
  • packages/squad-cli/src/cli/core/clients.ts
  • packages/squad-cli/src/cli/core/init.ts
  • packages/squad-cli/src/cli/core/mcp-root.ts
  • packages/squad-cli/src/cli/core/mcp-spec.ts
  • packages/squad-cli/src/cli/core/upgrade.ts
squad-sdk (2 files)
  • packages/squad-sdk/src/client/adapters/claude-hooks.ts
  • packages/squad-sdk/src/client/adapters/claude-plugin.ts
tests (7 files)
  • test/__snapshots__/host-projection-regression-guards.test.ts.snap
  • test/cli/upgrade-portability.test.ts
  • test/docs-site-location.test.ts
  • test/init-next-steps.test.ts
  • test/mcp-spec-init.test.ts
  • test/portable-launch.test.ts
  • test/squad-20-upgrade-matrix.test.ts

This report is generated automatically for every PR. See #733 for details.

@github-actions

github-actions Bot commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

🏗️ Architectural Review

Authoritative evidence: scanners from the PR base commit, posted by the default-branch workflow_run reporter.
Results for head commit 82419090308b91e4e481aeeac9536d358954149e.

⚠️ Architectural review: 2 warning(s).

Severity Category Finding Files
🟡 warning bootstrap-area 5 file(s) in the bootstrap area (packages/squad-cli/src/cli/core/) were modified. These files must maintain zero external dependencies. Review carefully. packages/squad-cli/src/cli/core/clients.ts, packages/squad-cli/src/cli/core/init.ts, packages/squad-cli/src/cli/core/mcp-root.ts, packages/squad-cli/src/cli/core/mcp-spec.ts, packages/squad-cli/src/cli/core/upgrade.ts
🟡 warning sweeping-refactor This PR touches 25 files (25 modified/added, 0 deleted). Large PRs are harder to review — consider splitting if possible. —

Automated architectural review — informational only.

@github-actions

github-actions Bot commented Nov 12, 2026 •

Copy link
Copy Markdown
Contributor

🛫 PR Readiness Check

ℹ️ This comment updates on each push. Last checked: commit 8241909

PR Scope: 📦🔧 Mixed (product + infrastructure)

⚠️ 2 item(s) to address before review

Status Check Details
❌ Single commit 7 commits — consider squashing before review
✅ Not in draft Ready for review
✅ Branch up to date Up to date with dev
❌ Copilot review No Copilot review yet — it may still be processing
✅ Changeset present Changeset file found
✅ Scope clean No .squad/ or docs/proposals/ files
✅ No merge conflicts No merge conflicts
✅ Copilot threads resolved 1 active Copilot thread(s) resolved (4 outdated skipped)
✅ CI passing All checks passing

Files Changed (25 files, +1115 −337)

File +/−
.changeset/init-next-steps.md +5 −0
.changeset/portable-launch.md +6 −0
CHANGELOG.md +9 −1
docs/src/content/docs/features/mcp.md +2 −0
docs/src/content/docs/scenarios/troubleshooting.md +10 −0
docs/src/content/docs/scenarios/upgrading.md +8 −7
packages/squad-cli/src/cli/commands/client.ts +4 −2
packages/squad-cli/src/cli/commands/doctor.ts +78 −0
packages/squad-cli/src/cli/core/clients.ts +2 −2
packages/squad-cli/src/cli/core/init.ts +55 −10
packages/squad-cli/src/cli/core/mcp-root.ts +2 −2
packages/squad-cli/src/cli/core/mcp-spec.ts +142 −2
packages/squad-cli/src/cli/core/upgrade.ts +10 −2
packages/squad-sdk/src/client/adapters/claude-hooks.ts +32 −7
packages/squad-sdk/src/client/adapters/claude-plugin.ts +109 −28
plugins/squad/scripts/squad.mjs +22 −5
scripts/docs-site-location.mjs +0 −5
test-fixtures/spec/suite-v0.2/upgrade-matrix.json +248 −247
test/__snapshots__/host-projection-regression-guards.test.ts.snap +1 −1
test/cli/upgrade-portability.test.ts +9 −5
test/docs-site-location.test.ts +0 −9
test/init-next-steps.test.ts +80 −0
test/mcp-spec-init.test.ts +2 −1
test/portable-launch.test.ts +277 −0
test/squad-20-upgrade-matrix.test.ts +2 −1

Total: +1115 −337


This check runs automatically on every push. Fix any ❌ items and push again.
See CONTRIBUTING.md and PR Requirements for details.

…ed (#2462)

The upgrade matrix caught two gaps:
- On a machine where the CLI runs only by path (no `squad` on PATH, no
  project install), the repository launcher found nothing and the
  squad_state probe failed right after upgrade. init/upgrade now record
  the CLI entry in `<Squad home>/cli.json` (outside the repository), and
  both launchers try it after PATH, with the same version floor.
- `.squad/bin/squad.mjs` is a Squad-owned path a plain upgrade may
  create: add it to the matrix fixture's squadOwned list and the
  upgrading guide. The recorded runs are refolded in a follow-up commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@bradygaster

Copy link
Copy Markdown
Collaborator Author

Status: the upgrade matrix (ubuntu) caught two real gaps, fixed in f3ac9bd: the launcher now also finds the CLI that ran squad init/upgrade on this machine (recorded in ~/.squad/cli.json, outside the repo), and .squad/bin/squad.mjs is declared Squad-owned in the matrix fixture. Changing the fixture changes the matrix harness hash, so upgrade-matrix.json integrity will fail until the recorded Linux and Windows runs are refolded from this run's artifacts (render-upgrade-matrix.mjs --merge); that commit follows.

🤖 Generated with Claude Code

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Unresolved launcher flaws permit executable writes outside the workspace through symlinks and can exclude the required script from commits, breaking fresh clones.

5 open issues
What changed in this PR

This PR addresses two Claude Code first-run issues (#2462 and #2453): machine-specific launch commands in committed files and init instructions that recommend the wrong host.

Changes:

  • Introduces a shared repository launcher and routes committed MCP configurations and Claude hooks through portable commands.
  • Adds portability diagnostics to squad doctor and host-aware next steps to squad init.
  • Adds regression coverage, documentation, and release notes.
File Description
test/​portable-launch.test.ts Tests portable specs, launcher behavior, hooks, and diagnostics.
test/​mcp-spec-init.test.ts Accepts the committed-file resolver in init.
test/​init-next-steps.test.ts Tests host-specific instructions and plugin mode.
test/​cli/​upgrade-portability.test.ts Checks portable upgrade output and launcher creation.
test/​__snapshots__/​host-projection-regression-guards.test.ts.snap Updates the MCP configuration snapshot hash.
plugins/​squad/​scripts/​squad.mjs Regenerates the plugin launcher with shared project lookup.
packages/​squad-sdk/​src/​client/​adapters/​claude-plugin.ts Shares launcher generation between plugins and repositories.
packages/​squad-sdk/​src/​client/​adapters/​claude-hooks.ts Generates and recognizes repository-launcher hook commands.
packages/​squad-cli/​src/​cli/​core/​upgrade.ts Uses and describes portable launch specs during upgrade.
packages/​squad-cli/​src/​cli/​core/​mcp-spec.ts Resolves committed specs and writes repository launchers.
packages/​squad-cli/​src/​cli/​core/​mcp-root.ts Marks portable specs as non-machine-specific.
packages/​squad-cli/​src/​cli/​core/​init.ts Uses portable specs and prints host-aware next steps.
packages/​squad-cli/​src/​cli/​core/​clients.ts Uses portable specs for client synchronization.
packages/​squad-cli/​src/​cli/​commands/​doctor.ts Adds committed-launch portability diagnostics.
packages/​squad-cli/​src/​cli/​commands/​client.ts Resolves portable specs without writing during client listing.
docs/​src/​content/​docs/​scenarios/​troubleshooting.md Documents recovery from clone-related launch failures.
docs/​src/​content/​docs/​features/​mcp.md Explains launcher resolution and installation options.
CHANGELOG.md Records portability and host-instruction fixes.
.changeset/​portable-launch.md Adds SDK and CLI patch release notes.
.changeset/​init-next-steps.md Adds CLI release notes for host-aware instructions.

Review effort: Balanced (auto)

Comment thread packages/squad-cli/src/cli/core/init.ts Resolved
bradygaster and others added 3 commits November 11, 2026 19:15
- Launcher writes go through resolveInsideRoot, so a symlinked squad
  directory or a dangling link at the launcher path can't redirect the
  write outside the workspace; Squad keeps the previous spec instead.
- The launcher moves to `.squad/squad.mjs`: many repositories ignore
  `bin/`, which would leave `.squad/bin/squad.mjs` uncommitted.
- A CLI running from a package runner's cache (npm `_npx`, pnpm `dlx`,
  yarn `dlx-`/`xfs-`) keeps the exact-version npx command and is not
  recorded in cli.json: that install is gone after the command exits.
- doctor recognises Windows and POSIX absolute paths on every OS and
  only checks the command on disk when it is absolute (a bare `node` is
  found on PATH).
- init's next steps use the clients and plugin mode .squad/config.json
  records when no flag is given, so re-running init stays accurate.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The repository moved from bradygaster/squad to github/squad. The API no
longer serves the 1.0.1 and 1.1.0 release assets under the old name
(HTTP 404), so those rows were silently skipping; the asset ids and
sha256s are unchanged under github/squad. Recorded runs are refolded
from this head's matrix run in the next commit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Linux and Windows re-recorded from the pull-request matrix run at
9b254ba (both 35 pass, 7 skipped, the same coverage as before), folded
with render-upgrade-matrix.mjs's mergeRun, and the "Tested upgrade paths"
section re-rendered. Only runs data and the generated docs change.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@bradygaster

Copy link
Copy Markdown
Collaborator Author

Refolded the upgrade matrix (a7f53bdf): Linux and Windows re-recorded at 9b254ba, both 35 pass / 7 skipped, the same coverage as the previous recorded runs. Along the way the 1.0.1 and 1.1.0 release rows were found silently skipping on dev too: the fixture fetched assets from bradygaster/squad, which now 404s since the repository moved; they now fetch from github/squad (same asset ids and sha256s) and pass again.

🤖 Generated with Claude Code

The refolded upgrade matrix links to github/squad runs and releases, so
its generated section keeps no bradygaster/squad links and the
HISTORICAL_REPO_LINKS entry for upgrading.md was flagged as unused.
Remove it and the test cases that used it as their example; whatsnew.md
still covers section-scoped exemptions.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants