Repository navigation
feat!: runtime upstream inheritance, remove personal squads, host feature matrix (pre-preview follow-up) - #2274
tamirdresher wants to merge 6 commits into
Conversation
🏗️ Architectural Review
Automated architectural review — informational only. |
🛫 PR Readiness Check
PR Scope: 📦🔧 Mixed (product + infrastructure)
|
| Status | Check | Details |
|---|---|---|
| ❌ | Single commit | 6 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 | 0 active Copilot thread(s) resolved (5 outdated skipped) |
| ❌ | CI passing | 1 check(s) still running |
Files Changed (104 files, +9619 −6571)
| File | +/− |
|---|---|
.changeset/squad-2-0-upstream-runtime-and-personal-removal.md |
+12 −0 |
.github/agents/squad.agent.md |
+8 −23 |
.squad-templates/README.md |
+1 −1 |
.squad-templates/skills/personal-squad/SKILL.md |
+0 −66 |
.squad-templates/spawn-reference.md |
+0 −12 |
.squad-templates/squad.agent.md |
+8 −23 |
README.md |
+2 −2 |
cspell.json |
+2 −0 |
docs/src/content/docs/concepts/portability.md |
+2 −2 |
docs/src/content/docs/concepts/squad-2-0-architecture.md |
+1 −1 |
docs/src/content/docs/features/consult-mode.md |
+0 −260 |
docs/src/content/docs/features/enterprise-platforms.md |
+2 −0 |
docs/src/content/docs/features/gitlab-issues.md |
+1 −1 |
docs/src/content/docs/features/upstream-inheritance.md |
+86 −29 |
docs/src/content/docs/get-started/installation.md |
+8 −5 |
docs/src/content/docs/guide.md |
+1 −1 |
docs/src/content/docs/guide/personal-squad.md |
+0 −350 |
docs/src/content/docs/reference/api-reference.md |
+1 −1 |
docs/src/content/docs/reference/cli.md |
+2 −2 |
docs/src/content/docs/reference/config.md |
+1 −1 |
docs/src/content/docs/reference/host-feature-matrix.md |
+1055 −0 |
docs/src/content/docs/reference/sdk.md |
+3 −3 |
docs/src/content/docs/scenarios/upgrading.md |
+21 −0 |
docs/src/content/docs/scenarios/using-squad-across-clients.md |
+2 −2 |
docs/src/content/docs/tour-gitlab-issues.md |
+1 −1 |
docs/src/content/docs/whatsnew.md |
+5 −0 |
docs/src/navigation.ts |
+1 −2 |
packages/squad-cli/README.md |
+2 −2 |
packages/squad-cli/src/cli-entry.ts |
+32 −30 |
packages/squad-cli/src/cli/commands/cast.ts |
+16 −74 |
packages/squad-cli/src/cli/commands/consult.ts |
+0 −103 |
packages/squad-cli/src/cli/commands/doctor.ts |
+56 −0 |
packages/squad-cli/src/cli/commands/extract.ts |
+0 −332 |
packages/squad-cli/src/cli/commands/import-legacy-personal.ts |
+172 −0 |
packages/squad-cli/src/cli/commands/personal.ts |
+0 −248 |
packages/squad-cli/src/cli/commands/state-mcp.ts |
+11 −3 |
packages/squad-cli/src/cli/commands/upstream.ts |
+312 −250 |
packages/squad-cli/src/cli/core/command-help.ts |
+10 −31 |
packages/squad-cli/src/cli/core/init.ts |
+6 −41 |
packages/squad-cli/src/cli/core/personal-squad-notice.ts |
+57 −0 |
packages/squad-cli/src/cli/core/upgrade.ts |
+8 −0 |
packages/squad-cli/templates/README.md |
+1 −1 |
packages/squad-cli/templates/skills/personal-squad/SKILL.md |
+0 −66 |
packages/squad-cli/templates/spawn-reference.md |
+0 −12 |
packages/squad-cli/templates/squad.agent.md.template |
+8 −23 |
packages/squad-sdk/package.json |
+0 −4 |
packages/squad-sdk/src/agents/index.ts |
+0 −8 |
packages/squad-sdk/src/agents/personal.ts |
+0 −97 |
packages/squad-sdk/src/client/adapters/capabilities.ts |
+1 −1 |
packages/squad-sdk/src/client/adapters/coordinator.ts |
+2 −0 |
| ... | +54 more files |
Total: +9619 −6571
This check runs automatically on every push. Fix any ❌ items and push again.
See CONTRIBUTING.md and PR Requirements for details.
🔴 Impact Analysis — PR #2274Risk tier: 🔴 CRITICAL 📊 Summary
🎯 Risk Factors
📦 Modules Affectedci-workflows (1 file)
docs (19 files)
root (11 files)
scripts (1 file)
squad-cli (18 files)
squad-sdk (20 files)
templates (4 files)
tests (30 files)
|
There was a problem hiding this comment.
🟡 Changes recommended
Destructive test cleanup, an unusable migration recipe and inconsistent upstream precedence and configuration roots remain unresolved.
5 open issues
Isolate global squad fixtures from the real installation · New Read upstream configuration from the working-tree directory · New Fix legacy squad migration export and import workflow · New Align upstream configuration roots across linked-project commands · New Include all local skill roots in upstream override detection · New
What changed in this PR
This Squad 2.0 follow-up connects upstream inheritance to the multi-host runtime, removes personal-squad functionality, and aligns capability reporting and documentation with supported behavior.
Changes:
- Adds runtime upstream resolution, provenance, precedence rules, coordinator instructions and diagnostic reporting.
- Removes personal-squad commands, APIs and templates; adds legacy detection, migration notices and preservation tests.
- Corrects state-backend reporting, root listing and Claude background capabilities; adds host-matrix rendering and documentation updates.
| File | Description |
|---|---|
test/upstream.test.ts |
Updates upstream diagnostic expectations. |
test/tools.test.ts |
Expects the upstream runtime tool. |
test/template-extra-classification.test.ts |
Removes deleted personal-template exceptions. |
test/standalone-release-workflow.test.ts |
Removes the deleted personal-squad guide. |
test/squad-20-pack-smoke.test.ts |
Removes the retired personal-squad switch. |
test/squad-20-all-scenarios.e2e.test.ts |
Updates Claude background-capability assertions. |
test/sdk-feature-parity.test.ts |
Removes consult-mode API tests. |
test/resolution.test.ts |
Tests read-only legacy detection. |
test/personal-squad-removal.test.ts |
Adds preservation, isolation and notice coverage. |
test/multi-squad.test.ts |
Clarifies global-squad terminology in a comment. |
test/docs-build.test.ts |
Removes deleted documentation expectations. |
test/cross-package-exports.test.ts |
Updates removed APIs and detector exports. |
test/compat-v041.test.ts |
Updates built-in tool counts. |
test/clients.test.ts |
Tests upstream instructions and documented digest gaps. |
test/cli/extract.test.ts |
Deletes obsolete extract-command tests. |
test/cli/consult.test.ts |
Deletes obsolete consult-command tests. |
test/cli/command-help.test.ts |
Removes retired commands from help expectations. |
test/cli/cast.test.ts |
Removes the personal-agent mock. |
test/cli-packaging-smoke.test.ts |
Removes retired command expectations. |
test/cli-global.test.ts |
Changes routing fixtures to global squads. |
test/acceptance/features/extract-command.feature |
Deletes extract acceptance scenarios. |
test/acceptance/features/consult-command.feature |
Deletes consult acceptance scenarios. |
test/acceptance/acceptance.test.ts |
Unregisters deleted acceptance features. |
test-fixtures/spec/suite-v0.2/capability-matrix.json |
Declares Claude background runs. |
templates/squad.agent.md.template |
Adds inheritance instructions; removes personal routing. |
templates/spawn-reference.md |
Removes Ghost Protocol spawn instructions. |
templates/skills/personal-squad/SKILL.md |
Deletes the personal-squad skill mirror. |
templates/README.md |
Updates the spawn-reference description. |
templates/personal-charter.md |
Deletes the personal-agent charter template. |
templates/ghost-protocol.md |
Deletes personal-agent behavior rules. |
scripts/render-host-feature-matrix.mjs |
Adds matrix rendering, summaries and freshness checks. |
README.md |
Clarifies global init and upgrade terminology. |
packages/squad-sdk/templates/squad.agent.md.template |
Mirrors updated coordinator instructions. |
packages/squad-sdk/templates/spawn-reference.md |
Removes packaged Ghost Protocol instructions. |
packages/squad-sdk/templates/skills/personal-squad/SKILL.md |
Deletes the SDK personal-squad skill. |
packages/squad-sdk/templates/README.md |
Updates the packaged spawn-reference description. |
packages/squad-sdk/src/upstream/types.ts |
Defines provenance, statuses and effective context. |
packages/squad-sdk/src/upstream/index.ts |
Exports expanded upstream APIs. |
packages/squad-sdk/src/tools/index.ts |
Adds upstream tooling and backend identification. |
packages/squad-sdk/src/state-backend.ts |
Maps root listing to the empty state key. |
packages/squad-sdk/src/sharing/index.ts |
Removes consult-module exports. |
packages/squad-sdk/src/resolution.ts |
Replaces personal helpers with legacy detection. |
packages/squad-sdk/src/multi-squad.ts |
Clarifies global-squad terminology in a comment. |
packages/squad-sdk/src/index.ts |
Updates public exports for personal-squad removal. |
packages/squad-sdk/src/config/init.ts |
Removes consult extraction configuration. |
packages/squad-sdk/src/client/adapters/coordinator.ts |
Adds the upstream inheritance digest contract. |
packages/squad-sdk/src/client/adapters/capabilities.ts |
Declares Claude background-run support. |
packages/squad-sdk/src/agents/personal.ts |
Deletes ambient personal-agent discovery. |
packages/squad-sdk/src/agents/index.ts |
Removes personal-agent exports. |
packages/squad-sdk/package.json |
Removes the personal-agent subpath export. |
packages/squad-cli/templates/squad.agent.md.template |
Mirrors updated coordinator instructions. |
packages/squad-cli/templates/spawn-reference.md |
Removes packaged Ghost Protocol instructions. |
packages/squad-cli/templates/skills/personal-squad/SKILL.md |
Deletes the CLI personal-squad skill. |
packages/squad-cli/templates/README.md |
Updates the packaged spawn-reference description. |
packages/squad-cli/src/cli/core/upgrade.ts |
Prints legacy personal-squad notices. |
packages/squad-cli/src/cli/core/personal-squad-notice.ts |
Adds removal and migration messages. |
packages/squad-cli/src/cli/core/init.ts |
Removes personal-directory creation and automatic linking. |
packages/squad-cli/src/cli/core/command-help.ts |
Removes retired commands and updates terminology. |
packages/squad-cli/src/cli/commands/upstream.ts |
Clarifies local-snapshot startup behavior. |
packages/squad-cli/src/cli/commands/state-mcp.ts |
Exposes upstream tooling and passes backend identity. |
packages/squad-cli/src/cli/commands/personal.ts |
Deletes personal-squad management commands. |
packages/squad-cli/src/cli/commands/extract.ts |
Deletes consult-learning extraction. |
packages/squad-cli/src/cli/commands/doctor.ts |
Adds upstream and legacy-personal diagnostics. |
packages/squad-cli/src/cli/commands/consult.ts |
Deletes consult-mode setup. |
packages/squad-cli/src/cli/commands/cast.ts |
Removes personal-agent merging and display columns. |
packages/squad-cli/src/cli-entry.ts |
Adds removal handling and upstream status output. |
packages/squad-cli/README.md |
Clarifies global-squad behavior. |
docs/src/navigation.ts |
Removes retired pages and links the host matrix. |
docs/src/content/docs/whatsnew.md |
Documents runtime additions and breaking changes. |
docs/src/content/docs/tour-gitlab-issues.md |
Marks the walkthrough as planned functionality. |
docs/src/content/docs/scenarios/using-squad-across-clients.md |
Clarifies headless Claude setup and legacy linking. |
docs/src/content/docs/scenarios/upgrading.md |
Adds personal-squad removal and migration guidance. |
docs/src/content/docs/reference/sdk.md |
Updates resolution terminology and helper descriptions. |
docs/src/content/docs/reference/config.md |
Uses global-squad terminology. |
docs/src/content/docs/reference/cli.md |
Clarifies global initialization and resolution. |
docs/src/content/docs/reference/api-reference.md |
Updates the global-path API description. |
docs/src/content/docs/guide/personal-squad.md |
Deletes the retired personal-squad guide. |
docs/src/content/docs/guide.md |
Clarifies global initialization behavior. |
docs/src/content/docs/get-started/installation.md |
Replaces personal-squad setup guidance. |
docs/src/content/docs/features/upstream-inheritance.md |
Documents runtime resolution, precedence and APIs. |
docs/src/content/docs/features/gitlab-issues.md |
Marks GitLab integration as not shipped. |
docs/src/content/docs/features/enterprise-platforms.md |
Defines the scope of Azure DevOps support. |
docs/src/content/docs/features/consult-mode.md |
Deletes retired consult-mode documentation. |
docs/src/content/docs/concepts/squad-2-0-architecture.md |
Updates Claude capability documentation. |
cspell.json |
Adds names used in documentation. |
.squad-templates/squad.agent.md |
Adds canonical inheritance instructions; removes personal routing. |
.squad-templates/spawn-reference.md |
Removes canonical Ghost Protocol instructions. |
.squad-templates/skills/personal-squad/SKILL.md |
Deletes the canonical personal-squad skill. |
.squad-templates/README.md |
Updates the canonical spawn-reference description. |
.github/agents/squad.agent.md |
Synchronizes the active coordinator contract. |
.changeset/squad-2-0-upstream-runtime-and-personal-removal.md |
Records major releases and migration changes. |
Review effort: Balanced
… untrusted marking, working legacy import, project-local upstream root Copilot review threads + Worf FUP-1..12 on #2274: Upstream inheritance - FUP-2: all snapshot reads go through a ContainedReader rooted at the upstream (clone dir / declared source / export dir): per-component lstat refuses symlinks and junctions, realpath must stay inside the root; any refusal marks the upstream `invalid` and serves nothing from it. - FUP-9: per-file cap UPSTREAM_MAX_FILE_BYTES (1 MiB); larger files invalidate the upstream with a diagnostic. - FUP-3: report header states inherited content is UNTRUSTED third-party data, every body in detail mode is fenced with BEGIN/END UNTRUSTED markers; the canonical `### Upstream Inheritance` section and digest 16a say the same. - FUP-11: relative local/export sources resolve against the declaring squad's project root, never process.cwd(). - Copilot P2 (root policy): upstream declarations are project-local (`squad upstream add` writes them beside config.json, `squad externalize` keeps them local). ToolRegistry gains `upstreamDir`; state-mcp passes context.paths.projectDir while state tools keep operating on the team root; `squad doctor` reads the local .squad/ too. - Copilot P2 / FUP-8: local-wins scans all five skill roots (.squad, .copilot, .github, .claude, .agents). - FUP-7: doctor reports an unsynced/stale git upstream as a warning with the sync hint; only missing/invalid/cycle/depth fail. - FUP-4: concepts/portability.md now says earlier entries win. Personal squad removal - FUP-1 / Copilot P2: the advertised `squad export` recipe could not read a 1.x layout (no .squad/, no team.md; flag is --out). New read-only `squad import --legacy-personal [<dir>] [--dry-run]` registers each 1.x agent through the normal cast flow (charter/history kept verbatim, existing names skipped, source never written). Notice, doctor, upgrading guide, whatsnew, changeset and matrix text updated to it. - FUP-5: notice also printed by `squad init` and by the already-up-to-date upgrade path. - FUP-6: detection honours a still-set SQUAD_PERSONAL_DIR. - FUP-12: external-state tests no longer assert the dead `consult` field; "fiery death" phrasing removed from the public matrix page. Tests (all mutation-proven against the pre-fix code): junction/symlink escape, file-symlink escape, oversized file, untrusted fences around an injection payload, relative source from another cwd, linked-project upstream root over the bridge, five skill roots, real-1.x-layout legacy import round trip (dry-run, import, re-run skips, source sha256-identical), SQUAD_PERSONAL_DIR detection, notice on init/up-to-date upgrade, doctor severity; digest regex asserts the untrusted sentence on all 7 hosts. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: b822a455-fa94-49a2-9127-eee479ab954e
…enCode runs and bridge tests Adds test-fixtures/spec/suite-v0.2/host-feature-matrix.json (source of truth), scripts/render-host-feature-matrix.mjs, the rendered reference page, and test/squad-20-host-feature-matrix.test.ts (schema/evidence integrity, rendered page in sync, runtime flags vs capability tokens, deterministic bridge scenarios: monorepo subfolder, remote-mode satellite, orphan/two-layer squad_decide). Live validation: Claude Code 2.1.296 + OpenCode across 15 scenarios; Kiro/Antigravity/Cursor/Codex blocked (quota/auth) and kept static-only. Cherry-picked from tamirdresher-microsoft-squad2-host-feature-matrix. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: b822a455-fa94-49a2-9127-eee479ab954e
`squad upstream add/sync` wrote `.squad/upstream.json` but `resolveUpstreams()` had no caller and no coordinator prompt mentioned it, so no host ever inherited anything. This makes inheritance real at session start: - SDK resolver: provenance (`upstream:<name>@<ref>`) on every upstream, status (`ok|stale|missing|unavailable|invalid|cycle|depth-exceeded`) with actionable diagnostics, transitive resolution (declared order, depth-first, default depth 3) with cycle detection and diamond de-duplication, deterministic precedence (local `.squad/` wins, then order) via `buildEffectiveUpstreamContext`, and a `formatUpstreamReport` renderer. Never fetches: git upstreams are read from the clone `squad upstream sync` materialized. Accepts a source that already is a `.squad/` dir (the documented `squad upstream add ../org/.squad` form). - New `squad_state_upstreams` runtime tool, exposed over `squad state-mcp` so all 7 hosts see inherited skills/decisions/routing/wisdom/casting policy with provenance (`detail: true` returns the bodies). - `squad doctor` gains an "upstream inheritance" check; `squad status` prints the inherited-context display. - Coordinator contract: canonical `### Upstream Inheritance` section plus digest item 16a in coordinator.ts (CANONICAL_COORDINATOR_HEADINGS updated), mirrored to all template copies. - Tests: test/upstream-runtime.test.ts (precedence, provenance, depth, cycles, diamond, soft failures, no fetch, ToolRegistry + stdio bridge, doctor check); F1 digest `it.fails` flipped to a positive assertion; bridge scenario added to the host-feature-matrix suite. - Docs: features/upstream-inheritance.md now describes exactly what ships (earlier entries win, no implicit fetch, statuses, SDK API). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: b822a455-fa94-49a2-9127-eee479ab954e
BREAKING CHANGE: `squad personal`, `squad consult`, `squad extract`, ambient `~/.config/squad/personal-squad` agent discovery, Ghost Protocol spawn rules, consult-mode routing and the `SQUAD_NO_PERSONAL` / `SQUAD_PERSONAL_DIR` switches are removed. `squad init` no longer points `config.json` `teamRoot` at the global squad root (the F9 bug that made every project a satellite of the personal squad) and never writes outside the project `.squad/`. SDK removals: resolvePersonalSquadDir, ensurePersonalSquadDir, ensureSquadPathTriple, isConsultMode, ResolvedSquadPaths.personalDir, SquadDirConfig.consult/extractionDisabled, InitOptions.extractionDisabled, the `agents/personal` subpath and the `sharing/consult` module. Added read-only `legacyPersonalSquadPath()` / `detectLegacyPersonalSquad()`. Safety contract (Q/Bubu redlines): - Nothing is deleted, moved or rewritten. `squad upgrade` and `squad doctor` print a one-time notice naming the untouched legacy directory and/or the leftover `teamRoot`, with the reversible path (`squad export` there, `squad import` here; user decides about shared `teamRoot`). The dead subcommands print the same notice and exit non-zero. - test/personal-squad-removal.test.ts: with a legacy personal squad present, init -> cast -> upgrade -> upgrade (idempotent) -> client install/rollback leaves the legacy tree byte-identical (sha256 fingerprint) and populates the project roster; two side-by-side projects stay independent; detection never mkdirs; doctor/notice text is asserted. `squad init --global` / `squad upgrade --global` keep managing the *global* squad but no longer bootstrap `personal-squad/`. Docs/nav, canonical coordinator (+ all template mirrors), help text, acceptance features, the matrix row and dead tests are updated; changeset added under `major`. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: b822a455-fa94-49a2-9127-eee479ab954e
… Claude background-runs; matrix + docs (F5–F8, F2/F3)
- F6: `squad_state_health` now reports `State backend: local|orphan|two-layer`
plus the storage class and team squad dir (ToolRegistry takes a trailing
`{ backendName }` option; state-mcp passes `context.backend.name`).
- F8: `StateBackendStorageAdapter.toRelative()` maps the squad root to the
empty key instead of `.`, so `squad_state_list` without `dir` lists the
root on orphan/two-layer instead of failing key validation.
- F7: Claude Code declares `background-runs` in capability-matrix.json,
CAPABILITY_TOKENS_BY_HOST and the architecture doc (live run showed
background Agent spawns).
- Upstream tool output is bounded (UPSTREAM_REPORT_MAX_CHARS, summary kept,
detail truncated with an explicit marker) per reviewer redline.
- Host feature matrix: F1 cells -> supported with validated-test evidence
for all 7 hosts; F6/F8 notes; Claude background-agents -> supported;
consult-personal-squad -> n/a (removed); renderer escapes `|` in feature
names; cspell words for the live-run names; F6 `it.fails` flipped and F8
asserted in the bridge test.
- Docs: headless Claude needs `--mcp-config .mcp.json` (F5; no
enableAllProjectMcpServers projection); ADO = detection + triage/watch via
`az`, interactive Issues mode GitHub-only (F3); GitLab marked planned, not
shipped (F2).
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: b822a455-fa94-49a2-9127-eee479ab954e
… untrusted marking, working legacy import, project-local upstream root; CI/test fixes Copilot review threads + Worf FUP-1..12 on #2274, plus the CI fix. Upstream inheritance - FUP-2: all snapshot reads go through a ContainedReader rooted at the upstream (clone dir / declared source / export dir): per-component lstat refuses symlinks and junctions, realpath must stay inside the root; any refusal marks the upstream `invalid` and serves nothing from it. - FUP-9: per-file cap UPSTREAM_MAX_FILE_BYTES (1 MiB); larger files invalidate the upstream with a diagnostic. - FUP-3: report header states inherited content is UNTRUSTED third-party data, every body in detail mode is fenced with BEGIN/END UNTRUSTED markers; the canonical `### Upstream Inheritance` section and digest 16a say the same. - FUP-11: relative local/export sources resolve against the declaring squad's project root, never process.cwd(). - Copilot P2 (root policy): upstream declarations are project-local (`squad upstream add` writes them beside config.json, `squad externalize` keeps them local). ToolRegistry gains `upstreamDir`; state-mcp passes context.paths.projectDir while state tools keep operating on the team root; `squad doctor` reads the local .squad/ too. - Copilot P2 / FUP-8: local-wins scans all five skill roots (.squad, .copilot, .github, .claude, .agents). - FUP-7: doctor reports an unsynced/stale git upstream as a warning with the sync hint; only missing/invalid/cycle/depth fail. - FUP-4: concepts/portability.md now says earlier entries win. - FUP-10: render-host-feature-matrix.mjs --check compares CRLF-insensitively. Personal squad removal - FUP-1 / Copilot P2: the advertised `squad export` recipe could not read a 1.x layout (no .squad/, no team.md; flag is --out). New read-only `squad import --legacy-personal [<dir>] [--dry-run]` registers each 1.x agent through the normal cast flow (charter/history kept verbatim, existing names skipped, source never written). Notice, doctor, upgrading guide, whatsnew, changeset and matrix text updated to it. - FUP-5: notice also printed by `squad init` and by the already-up-to-date upgrade path. - FUP-6: detection honours a still-set SQUAD_PERSONAL_DIR. - FUP-12: external-state tests no longer assert the dead `consult` field; "fiery death" phrasing removed from the public matrix page. Tests - CI: the satellite fixture wrote teamRoot '..\base' (Windows separator), which fails to lstat on Linux; use '../base'. - Copilot P1: test/cli-global.test.ts stubs the platform config home under TMP instead of creating/deleting the developer's real global .squad. - test/cli/cast.test.ts drops the mock of the removed agents/personal subpath. - test/upstream-runtime.test.ts: restart determinism, monorepo subfolder bridge, upgrade leaves upstream state intact, junction/symlink escape, file-symlink escape, oversized file, untrusted fences around an injection payload, relative source from another cwd, linked-project upstream root over the bridge, five skill roots, doctor severity. - test/personal-squad-removal.test.ts: real-1.x-layout legacy import round trip (dry-run, import, re-run skips, source sha256-identical), SQUAD_PERSONAL_DIR detection, notice on init/up-to-date upgrade. - test/clients.test.ts: digest regex asserts the untrusted sentence on all 7 hosts. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: b822a455-fa94-49a2-9127-eee479ab954e
61a94ed to
73a4de5
Compare
…, traversal budgets, git source allow-list, untrusted-wording, expected-fail labels Upstream inheritance (Layer B scope) - TOCTOU: ContainedReader opens first (O_NOFOLLOW where available), fstat()s the descriptor and requires dev/ino/size to match the pre-open lstat chain, re-checks the directory chain realpath after open, reads via the fd only. Injectable `beforeOpen` seam (resolveUpstreams options) for deterministic race tests. - Traversal budgets enforced from lstat sizes BEFORE any read: 1 MiB/file, 8 MiB and 2000 files per upstream, 500 entries per directory, depth 8 (DEFAULT_UPSTREAM_READ_LIMITS, overridable via readLimits). Exceeding ⇒ upstream `invalid` with diagnostic. - Git source hardening in `squad upstream add|sync`: allow-list https://, ssh://, git@host:path; refuse leading-dash, remote helpers (ext::, fd::), file://, http://, whitespace; `--` before every positional in clone/pull; subprocess env GIT_CONFIG_PARAMETERS disables protocol.ext/file and re-enables only https/ssh; GIT_TERMINAL_PROMPT=0. `unsafeGitSourceReason` and `gitSyncEnv` exported for tests. - Wording: report header, canonical section, digest 16a, changeset and docs now say inherited bodies are data-only, cannot change tools/permissions/ approvals/MCP/host settings, and the UNTRUSTED fences are a mitigation, not a sandbox or authorization boundary. - Matrix: the five expected-fail digest gaps are labelled `failing` with an explanatory note on every degraded cell, listed under a new `expectedFailures` block rendered as "Expected failures (it.fails)". Personal squad removal (Layer C scope) - `squad import --legacy-personal` reads the legacy tree with lstat/open/ fstat (no symlinks or junctions, 1 MiB cap), refuses unsafe slugs, and copies no machine-specific path into the project. Tests: test/cli/upstream-source-hardening.test.ts (20: allow-list, env, add refuses 4 dangerous sources before write/spawn, `--` placement, sync skips hand-edited ext::/dash entries, pull uses `--`); upstream-runtime +6 (hook-driven dir→junction swap, leaf replaced between stat/open, every inherited type + nested + dangling link, no-open proof for oversized file, byte/file/entry/depth budgets, tool output fence + non-sandbox wording); personal-squad-removal +1 (junctioned legacy agent refused, no absolute path copied, dry-run keeps project sha256-identical); clients.test asserts the canonical section carries the untrusted/non-sandbox rule. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: b822a455-fa94-49a2-9127-eee479ab954e


What
Squad 2.0 pre-preview follow-up for the true blockers surfaced by the host-feature-matrix audit (#2255 stack reviews, Data's findings F1–F9). Three product changes and one evidence change: (1) upstream inheritance is now real at runtime on all 7 hosts (F1); (2) personal squads are removed rather than patched (F9, Brady: "personal squads can die a fiery death"); (3) state-bridge fixes F6/F7/F8 plus doc corrections for F2/F3/F5; (4) Data's Squad-feature × host matrix (
test-fixtures/spec/suite-v0.2/host-feature-matrix.json, rendered reference page, integrity + bridge tests) ships with its cells updated to the post-fix state.Why
squad upstream add/syncwrote.squad/upstream.json,resolveUpstreams()existed in the SDK, but nothing called it and no coordinator prompt mentioned it. Docs promised "the coordinator reads upstreams at session start"; no host did. Brady: "upstream inheritance is critical".squad initsilently setteamRootto the global squad root whenever%APPDATA%\squad\personal-squadexisted, sosquad castwrote the project's members into the personal squad and the projectteam.mdstayed empty. Decision: remove the feature (insider-first 2.0.0-preview.1), never touch existing personal data.squad_state_healthreturned the storage class name, not the backend the digest promises;squad_state_listwithoutdirfailed on orphan/two-layer. F7: Claude Code runsAgentspawns in the background but the matrix under-declared it. F2/F3/F5: docs over-promised GitLab, blurred what "ADO support" means, and under-documented headless Claude.Related: #2251 #2252 #2253 #2254 (cascade now on
dev), #2255.How
F1 — Upstream inheritance at runtime (
0723af44,5d274f8f)upstream/resolver.ts: everyResolvedUpstreamcarriesprovenance(upstream:<name>@<ref>),origin,ref,depth,via,status(ok|stale|missing|unavailable|invalid|cycle|depth-exceeded),diagnostic,squadDir,lastSynced. Resolution recurses into each upstream's ownupstream.jsondepth-first in declared order (default depth 3), de-duplicates diamonds (repo→org, repo→team→org inherits org once), detects cycles, and never fetches — git upstreams are read only from the clonesquad upstream syncmaterialized (unavailable+ sync hint otherwise;staleafter 30 days, still read).buildEffectiveUpstreamContextapplies precedence (local.squad/wins, then order; losers kept withoverriddenBy).formatUpstreamReportrenders the tool output and is bounded (UPSTREAM_REPORT_MAX_CHARS= 48k; summary intact, detail truncated with an explicit marker). Also fixes the documentedsquad upstream add ../org/.squadform (a source that is the.squaddir).squad_state_upstreams(detail: truereturns inherited bodies) registered inToolRegistryand aliased insquad state-mcp, so every host gets it.squad doctorgains an "upstream inheritance" check (pass/warn/fail with diagnostics);squad statusprints the inherited-context display;squad upstream addmessages no longer claim "read live".### Upstream Inheritancesection in.squad-templates/squad.agent.md(synced to.github/agents/squad.agent.mdand all template mirrors) + digest item 16a incoordinator.ts;CANONICAL_COORDINATOR_HEADINGSupdated (sync test green). Rules: call once after the handshake, never fetch, local wins then returned order, cite provenance, fail soft.features/upstream-inheritance.mdrewritten to what ships — note the precedence correction: earlier entries win (old docs said later-wins).F9 — Personal squads removed (
480ecf8a)squad personal|consult|extract(CLI),agents/personal.ts+sharing/consult.ts(SDK),resolvePersonalSquadDir/ensurePersonalSquadDir/ensureSquadPathTriple/isConsultMode,ResolvedSquadPaths.personalDir,SquadDirConfig.consult|extractionDisabled,InitOptions.extractionDisabled, the@bradygaster/squad-sdk/agents/personalsubpath, initteamRootauto-link, Ghost Protocol spawn block,personal-squadskill (+3 mirrors),ghost-protocol.md/personal-charter.md, coordinator "Personal Squad (Ambient Discovery)" / "Consult Mode Detection" / consult routing row, docs pages + nav, 7 dead test files.squad init|upgrade --global(manages the global squad only; no longer bootstrapspersonal-squad/),squad export/import, Human Team Members,squad cast(minus personal/Ghost Protocol columns).legacyPersonalSquadPath()/detectLegacyPersonalSquad()(computes the path withoutmkdir);cli/core/personal-squad-notice.tsused bysquad upgrade,squad doctorand the dead subcommands (which exit 1)..changeset/squad-2-0-upstream-runtime-and-personal-removal.md(major × 3), whatsnew v2.0.0 rows, upgrading guide "Personal squads removed".F6/F7/F8 — state bridge (
3792e629)squad_state_health→State backend: local|orphan|two-layer+ storage class + team squad dir (ToolRegistryaccepts a trailing{ backendName }; state-mcp passescontext.backend.name).StateBackendStorageAdapter.toRelative()maps the squad root to the empty key instead of., so root listing works on git-backed backends.background-runsincapability-matrix.json,CAPABILITY_TOKENS_BY_HOST, the architecture doc; R3-12 test flipped.F2/F3/F5 — docs only
claude -p) needs--mcp-config .mcp.json; Squad deliberately does not projectenableAllProjectMcpServers: true.squad triage|watchviaaz; interactive Issues mode is GitHub-only for now.Matrix (
1cff52e5,e2985918cherry-picked from Data; cells updated in3792e629)F1 cells →
supportedwithvalidated-testevidence on all 7 hosts;consult-personal-squad→n/a(removed); Claudebackground-agents→supported; F6/F8 notes. Renderer now escapes|in feature names (markdownlint was red on Data's branch); cspell words for live-run names.Reviewer redlines (Q/Bubu) → tests
test/personal-squad-removal.test.ts› "init → cast → upgrade → client install/rollback leaves a legacy personal squad byte-identical…" (sha256 fingerprint of the legacy tree before/after each step;teamRootnever set; roster lands in the project)runUpgradeidentical;installClients→uninstallClientsremoves the projection and leaves the legacy tree identicalpersonal-squad-removal.test.ts› "two projects initialised side by side … are independent"teamRootpersonal-squad-removal.test.ts› "squad doctor warns about the legacy directory and about a teamRoot…" (path named, "untouched", export/import recipe, "remove the key … or keep it"); "squad personal|consult|extract print the removal notice…"; detection "never creates the legacy directory"test/upstream-runtime.test.ts› "reports missing local paths, unsynced git clones, stale clones and invalid entries…" (asserts no clone dir created) and both bridge tests assert_upstream_reposis never createdtest/squad-20-host-feature-matrix.test.ts› "squad_state_upstreams over the bridge serves inherited skills and decisions with provenance and never fetches".changeset/squad-2-0-upstream-runtime-and-personal-removal.md,major× 3)PR Readiness Checklist
Branch & Commit
dev(notmain) — rebased withgit rebase --onto origin/dev c7190a86after the feat(clients): add --client host adapters for Claude, Kiro, OpenCode, Cursor, Codex, and Antigravity [1/4] #2251–docs: consolidate Squad 2.0 multi-client and experimental backend documentation [4/4] #2254 cascade (510aa250)devgit diff --cached --statbefore each commit; 100 files, +8040/−6237 — the deletions are the personal-squad removal)Build & Test
SKIP_BUILD_BUMP=1 npm run build— passednpm run lint— passed (SDK + CLItsc --noEmit)npm run lint:eslint— 0 errors (2224 pre-existing warnings repo-wide)npm run lint:docs— passed (markdownlint 0 issues, cspell 0 issues; was red on the matrix branch before the renderer/cspell fix)npx vitest run test/clients.test.ts test/clients-real-cli.test.ts test/squad-20-host-feature-matrix.test.ts test/cli-command-wiring.test.ts test/ux-gates.test.ts test/speed-gates.test.ts test/template-sync.test.ts test/squad-20-all-scenarios.e2e.test.ts test/squad-20-real-clients-stdio.e2e.test.ts test/backend.test.ts test/specification-suite.test.ts test/docs-build.test.ts test/squad-20-pack-smoke.test.ts test/upstream-runtime.test.ts test/upstream.test.ts test/upstream-e2e.test.ts test/personal-squad-removal.test.ts test/tools.test.ts test/compat-v041.test.ts --testTimeout=120000 --hookTimeout=120000— 779 passed / 5 expected-fail / 0 failed. The 5it.failsare the remaining known digest gaps (team-root, ADO, GitLab, model-selection, marketplace) that this PR does not claim to close. The raised timeout was needed because the Windows host running this was saturated (single git ops took 10–60 s); the gate tests themselves pass.npm test(full): 11482 passed / 358 failed / 263 skipped / 47 todo across 2418 files — honestly not all green on this host. Every failure was triaged and is environmental, not caused by this branch: gh-aw suites requiregh aw v0.91.5(v0.89.22 installed) orworkflowspath resolution;state-backend*,storage-provider,notes-promote,create-if-absent,upgrade-state-backend= git hook timeouts + Windows 8.3 short-path realpath ("Symlink traversal blocked: café");charter-spec,coordinator-scope-control,gh-aw-command-parse= CRLF working copy;repl-ux*,journey-power-user= no TTY;speed-gates= load; acceptancedoctorscenarios pass when run serially and the acceptanceinitscenario trips the git-worktree guard (I'm in a worktree);team-root-resolutionexpects no~/.squadon the machine. The two failures that were branch-caused were fixed in-branch (test/cli/cast.test.tsmocked the deletedagents/personalsubpath;compat-v041tool count 18→19). Requesting CI as the authoritative full run.Changeset
.changeset/squad-2-0-upstream-runtime-and-personal-removal.md)CHANGELOG.mdentry — N/Askip-changeloglabel applied — N/ADocs
--globalwording; personal-squad references removed in README + CLI README)features/upstream-inheritance.mdrewritten;scenarios/upgrading.md"Personal squads removed";whatsnew.mdv2.0.0;reference/host-feature-matrix.md;scenarios/using-squad-across-clients.md,features/enterprise-platforms.md,features/gitlab-issues.md,tour-gitlab-issues.md,get-started/installation.md,guide.md,reference/{cli,config,sdk,api-reference}.md,concepts/squad-2-0-architecture.md)Exports
./agents/personal;./upstreamalready existed and now exportsUpstreamStatus,ResolveUpstreamsOptions,InheritedSkill,InheritedDocument,EffectiveUpstreamContext,DEFAULT_UPSTREAM_MAX_DEPTH,DEFAULT_UPSTREAM_STALE_DAYS,UPSTREAM_REPORT_MAX_CHARS,upstreamProvenance,buildEffectiveUpstreamContext,formatUpstreamReport; root barrel exportslegacyPersonalSquadPath,detectLegacyPersonalSquad,LegacyPersonalSquadInfoBreaking Changes
Personal squads are removed (Squad 2.0).
squad personal,squad consult,squad extract, ambient~/.config/squad/personal-squad(%APPDATA%\squad\personal-squad) agent discovery, Ghost Protocol spawn rules, consult-mode routing and theSQUAD_NO_PERSONAL/SQUAD_PERSONAL_DIRswitches no longer exist.squad initnever setsconfig.jsonteamRootto the global squad root and never writes outside the project.squad/. SDK removals are listed under "How → F9" above (resolvePersonalSquadDir,ensurePersonalSquadDir,ensureSquadPathTriple,isConsultMode,ResolvedSquadPaths.personalDir,SquadDirConfig.consult|extractionDisabled,InitOptions.extractionDisabled,@bradygaster/squad-sdk/agents/personal,sharing/consult).Nothing is deleted, moved or rewritten.
squad upgradeandsquad doctorprint this once when 1.x leftovers are detected (andsquad personal|consult|extractprint it and exit 1):Upstream precedence clarified: the local
.squad/wins, then earlier entries inupstream.jsonwin conflicts (the 1.x docs said later-wins; the code never implemented either). Git upstreams are read only from the clone made bysquad upstream sync— run it after upgrading.ToolRegistrygains a 7th optional{ backendName }parameter (additive).squad_state_healthoutput format changed from a single line toState backend: … / State backend storage: … / Team squad dir: ….Waivers
Requesting a waiver for the "
npm testpasses (all tests green)" item on the contributor's host: reason — the 358 failures are environmental on a saturated Windows worktree (gh-aw version pin, git timeouts, 8.3 short paths, CRLF, no TTY, worktree guard) and are enumerated above; CI is requested as the authoritative run. To be approved by the current Lead or Quality role owner in PR comments before merge.Working as B'Elanna (Durable Systems Engineer). Decision context: Brady — "insider first (2.0.0-preview.1); upstream inheritance is critical; personal squads can die a fiery death." Scope cut approved by the Squad 2.0 research session; Q/Bubu redlines addressed as tabulated above.