Repository navigation
feat: Squad 2.0 decoupled backend and multi-host client adapters (Claude, Kiro, OpenCode, Cursor, Codex, Antigravity) - #2239
tamirdresher wants to merge 51 commits into
Conversation
Add SquadBackend contract with versioned envelope protocol, local and durable-http backends, harness registry, capability negotiation, versioned approvals, cancel-by-runId, and squad_backend_* MCP transport adapter. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
Add security/isolation proposal and executable contract suite covering path/MCP/epoch guards, configured-vs-negotiated capabilities, versioned approvals with runId cancellation, loss-tolerant projection, and the golden cross-adapter conformance trace. Include packages/squad-sdk tests in vitest config. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
Add ClientAdapter/ProjectionFile architecture in squad-sdk (copilot, claude, kiro, opencode, cursor) with host-agnostic coordinator core, per-host dispatch sections, declared ClientCapabilities, resolveEffectiveCapabilities, and portable clients[] sanitization. Non-clobbering JSON/marker-block merging. CLI: --client <list|all> on init and upgrade, persisted to .squad/config.json clients[]; upgrade refreshes configured clients. Tests in test/clients.test.ts. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
Bring Brady's specification suite updates into the Squad 2.0 worktree, add the new v0.2 client/backend and client/harness protocol specs, and freeze the rc1 protocol baseline with ADR and immutable fixtures. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
…store clobbered spec docs Backend capabilities now use the v0.2 capability-matrix vocabulary; lastAcceptedSeq is the last accepted event sequence; conversation.created no longer leaks the lease epoch; MCP send_message accepts typed parts without content. Restore Charter/Core/Ceremony/Governance/Interop/README/inventory docs that the spec branch regressed to older revisions, keeping only the v0.2 profile additions. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
…ebase Covers client projections, capability intersection vs capability-matrix.json, LocalSquadBackend across 5 harnesses, DurableHttpSquadBackend against a mock DurableSquad, the MCP bridge on local and durable-http, and the normative golden trace. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
Closes #2069 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
…tion, clean-room) Add uninstallClients/removeProjection for clean rollback of client projections, make harness event delivery idempotent (duplicate/out-of-order), and rehydrate harness subscriptions for in-flight turns after a broker restart. New e2e tests cover v0.1 upgrade+rollback, partial/duplicate/shuffled delivery and restart with an approval in flight, and a clean-room client+harness checked against golden-trace.json and capability-matrix.json. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
Project claude/opencode/kiro configs, parse them from disk, spawn state-mcp as a real child process over stdio JSON-RPC and exercise squad_state_* and all squad_backend_* tools including process restart and resume. Smoke-test installed claude/opencode/kiro binaries against the workspaces when present on PATH. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
…I tests Real Kiro CLI resolves agent `resources` file:// paths against the workspace root (only `prompt` is relative to the agent config), so use file://.squad/team.md rather than ../../. Skip the Coordinator row when projecting Claude member subagents (it produced a bogus squad-squad agent). Add real-binary tests (claude, opencode, kiro-cli) that skip when absent. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
…I tests Real Kiro CLI resolves agent `resources` file:// paths against the workspace root (only `prompt` is relative to the agent config), so use file://.squad/team.md rather than ../../. Skip the Coordinator row when projecting Claude member subagents (it produced a bogus squad-squad agent). Add real-binary tests (claude, opencode, kiro-cli) that skip when absent. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
Codex: AGENTS.md managed block (id-scoped), .codex/config.toml [mcp_servers.squad_state] via a non-destructive TOML table merge (startup timeout defaulted to 60s for cold npx), .codex/agents/squad-<member>.toml. Antigravity: .agents/agents/squad.md (+ member subagents, mcpServers frontmatter) and a GEMINI.md block. Block markers can carry an id so several clients share one file. Real-binary tests for codex and agy; verified against codex-cli 0.163 and agy 1.4.0. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
…le state Found with real models: opencode's Glob skipped .squad/ so the coordinator concluded no team existed and re-cast it over the real team; models also tried squad_state_write for team.md/routing.md/charters, which the state tools reject. Add a guarded Init Mode that decides via squad_state_read, never re-casts an existing team, and document static config as ordinary files. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
…tigravity to capability matrix Make removeProjection handle text (TOML) projections and block ids introduced with the codex/antigravity adapters, add both clients to the v0.2 capability matrix fixture, and generalize the all-scenarios projection assertions to every client. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
…e in shared prompt opencode now projects .opencode/agent/squad-<member>.md (mode: subagent); claude/opencode/codex/antigravity member agents accept an optional model from .squad/config.json clientModels (per client, per member slug, '*' wildcard; values validated). Shared coordinator prompt gains host-agnostic Ralph mode (coordinator-driven gh scan/route/PR loop). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
…lot prompt Shared prompt now carries Response Mode Selection, Scribe drop-box protocol, reviewer rejection + strict lockout, Rai traffic light, Fact Checker + devil's advocate, ceremonies, 5-root skill-aware routing, memory/state handshake, GitHub Issues + PRD mode, cross-squad delegation, human/@copilot members, anti-patterns, Ralph mode, and a guarded Init Mode (auto-confirm, no glob on .squad, scratch dir, cast via 'squad cast', never hand-edit the checksummed casting registry, stop after casting). Verified live with Claude Code: headless 'proceed' now casts in one turn, Scribe merges the inbox; hand-written casting registry broke 'squad upgrade', hence the cast-CLI rule. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
…y image name Found in live Claude demos: Ralph ran taskkill /IM node.exe (killed its own proxy) and Claude left embedded worktree repos that broke git add. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
- squad cast --sync registers hand-written team.md members in the checksummed casting registry (idempotent); prompt uses it when 'cast --name' is unavailable (old npx-cached squad). - Antigravity agents declare tools (omitted list = none: agent had no shell, Ralph could not use gh). - Member slugs normalize diacritics consistently in adapters and cast. Found in live Kiro/Antigravity/interactive-Claude (cli-tunnel) runs. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
…idence, claude --mcp-config note Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
…s, explicit fallback From reviewer feedback on live runs: model asked for squad_state_read but hosts expose prefixed names; directory keys read as files (EISDIR); Scribe/Ralph/Rai/Fact Checker subagents missing when team.md was rewritten; silent owner substitution. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
…shed via claude-sonnet-4-6 model, per-model quota) Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
Default is now a single coordinator file per host, like Copilot. Member subagent files are projected only with --member-agents, config.json memberAgents: true, or when clientModels is configured. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
🔴 Impact Analysis — PR #2239Risk tier: 🔴 CRITICAL 📊 Summary
🎯 Risk Factors
📦 Modules Affecteddocs (15 files)
root (7 files)
squad-cli (7 files)
squad-sdk (21 files)
tests (8 files)
|
🏗️ Architectural Review
Automated architectural review — informational only. |
🛫 PR Readiness Check
PR Scope: 📦🔧 Mixed (product + infrastructure)
|
| Status | Check | Details |
|---|---|---|
| ❌ | Single commit | 51 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 merge conflicts | No merge conflicts |
| ✅ | Copilot threads resolved | 3 active Copilot thread(s) resolved (6 outdated skipped) |
| ✅ | CI passing | All checks passing |
Files Changed (58 files, +11771 −15)
| File | +/− |
|---|---|
.changeset/squad-2-0-multi-host-clients.md |
+6 −0 |
CONTRIBUTING.md |
+11 −0 |
README.md |
+13 −2 |
cspell.json |
+3 −0 |
docs/SQUAD-2.0-OVERVIEW.md |
+333 −0 |
docs/proposals/squad-2.0-security-and-isolation.md |
+103 −0 |
docs/specification/README.md |
+6 −0 |
docs/specification/adr-001-client-control-execution-boundary.md |
+59 −0 |
docs/specification/client-backend-decoupling-v0.2.md |
+487 −0 |
docs/specification/client-harness-adapters-v0.2.md |
+481 −0 |
docs/src/content/docs/concepts/squad-2-0-architecture.md |
+145 −0 |
docs/src/content/docs/reference/cli.md |
+2 −0 |
docs/src/content/docs/reference/config.md |
+2 −0 |
docs/src/content/docs/reference/sdk.md |
+9 −0 |
docs/src/content/docs/scenarios/client-compatibility.md |
+2 −0 |
docs/src/content/docs/scenarios/using-squad-across-clients.md |
+127 −0 |
docs/src/navigation.ts |
+2 −0 |
docs/tutorials/durable-backend-and-custom-harness.md |
+390 −0 |
docs/tutorials/multi-client-quickstart.md |
+361 −0 |
packages/squad-cli/src/cli-entry.ts |
+22 −2 |
packages/squad-cli/src/cli/commands/state-mcp.ts |
+20 −5 |
packages/squad-cli/src/cli/core/backend-mcp.ts |
+209 −0 |
packages/squad-cli/src/cli/core/clients.ts |
+102 −0 |
packages/squad-cli/src/cli/core/command-help.ts |
+2 −0 |
packages/squad-cli/src/cli/core/init.ts |
+30 −2 |
packages/squad-cli/src/cli/core/upgrade.ts |
+57 −2 |
packages/squad-sdk/package.json |
+8 −0 |
packages/squad-sdk/src/backend/durable-http-backend.ts |
+232 −0 |
packages/squad-sdk/src/backend/harness-registry.ts |
+47 −0 |
packages/squad-sdk/src/backend/index.ts |
+29 −0 |
packages/squad-sdk/src/backend/local-backend.ts |
+784 −0 |
packages/squad-sdk/src/backend/state-backend-store.ts |
+26 −0 |
packages/squad-sdk/src/backend/types.ts |
+417 −0 |
packages/squad-sdk/src/casting/handwritten-registry.ts |
+308 −0 |
packages/squad-sdk/src/casting/index.ts |
+10 −0 |
packages/squad-sdk/src/client/adapter-contract.ts |
+201 −0 |
packages/squad-sdk/src/client/adapters/adapters.ts |
+334 −0 |
packages/squad-sdk/src/client/adapters/apply.ts |
+379 −0 |
packages/squad-sdk/src/client/adapters/capabilities.ts |
+140 −0 |
packages/squad-sdk/src/client/adapters/coordinator.ts |
+108 −0 |
packages/squad-sdk/src/client/adapters/index.ts |
+6 −0 |
packages/squad-sdk/src/client/adapters/portable.ts |
+49 −0 |
packages/squad-sdk/src/client/adapters/types.ts |
+82 −0 |
packages/squad-sdk/src/client/index.ts |
+5 −0 |
packages/squad-sdk/src/clients/index.ts |
+9 −0 |
packages/squad-sdk/src/config/init.ts |
+4 −1 |
packages/squad-sdk/src/index.ts |
+3 −0 |
test-fixtures/spec/suite-v0.1/index.json |
+38 −0 |
test-fixtures/spec/suite-v0.2/capability-matrix.json |
+155 −0 |
test-fixtures/spec/suite-v0.2/golden-trace.json |
+63 −0 |
| ... | +8 more files |
Total: +11771 −15
This check runs automatically on every push. Fix any ❌ items and push again.
See CONTRIBUTING.md and PR Requirements for details.
There was a problem hiding this comment.
🟡 Changes recommended
Unresolved configuration data loss, casting integrity, containment, and backend integration issues block approval.
9 open issues
Validate projection config path containment · New Avoid genesis normalization for canonical checksum mismatches · New Lock and journal atomic registry pair repairs · New Preserve array-of-table sections during TOML updates · New Honor configured backend state storage · New Integrate registry repair into upgrade preflight recovery · New Retry response-body read failures · New Recognize quoted TOML keys before writing defaults · New Reconcile capability declarations with the baseline matrix · New
What changed in this PR
Introduces Squad 2.0’s shared backend contract and host adapters, allowing one team to work across seven AI clients.
Changes:
- Adds backend interfaces, HTTP transport, harness registration, and MCP integration.
- Adds host projections, capability declarations, and persistent
--clientconfiguration. - Expands specifications, fixtures, integration checks, and documentation.
| File | Description |
|---|---|
vitest.config.ts |
Resolves SDK source and includes SDK tests. |
test/specification-suite.test.ts |
Registers new requirements documents. |
test/docs-build.test.ts |
Checks new documentation pages. |
test/clients-real-cli.test.ts |
Adds host-binary integration checks. |
test-fixtures/spec/suite-v0.2/golden-trace.json |
Defines recovery and cancellation baseline. |
test-fixtures/spec/suite-v0.2/capability-matrix.json |
Defines host capability baseline. |
test-fixtures/spec/suite-v0.1/index.json |
Registers decoupling requirements. |
README.md |
Introduces multi-host commands. |
packages/squad-sdk/src/index.ts |
Exports backend APIs. |
packages/squad-sdk/src/config/init.ts |
Adds runtime ignore entries. |
packages/squad-sdk/src/clients/index.ts |
Provides compatibility re-exports. |
packages/squad-sdk/src/client/index.ts |
Exports client adapter APIs. |
packages/squad-sdk/src/client/adapters/types.ts |
Defines host projection types. |
packages/squad-sdk/src/client/adapters/portable.ts |
Normalizes persisted client IDs. |
packages/squad-sdk/src/client/adapters/index.ts |
Exports projection modules. |
packages/squad-sdk/src/client/adapters/coordinator.ts |
Defines coordinator and dispatch instructions. |
packages/squad-sdk/src/client/adapters/capabilities.ts |
Declares and intersects capabilities. |
packages/squad-sdk/src/client/adapters/apply.ts |
Applies and removes projections. |
packages/squad-sdk/src/client/adapters/adapters.ts |
Implements seven host projections. |
packages/squad-sdk/src/client/adapter-contract.ts |
Adds runtime-bound client facade. |
packages/squad-sdk/src/casting/index.ts |
Exports registry repair helpers. |
packages/squad-sdk/src/casting/handwritten-registry.ts |
Adds registry repair and backfill. |
packages/squad-sdk/src/backend/types.ts |
Defines backend and harness contracts. |
packages/squad-sdk/src/backend/index.ts |
Adds backend factory and exports. |
packages/squad-sdk/src/backend/harness-registry.ts |
Registers harnesses and validates extensions. |
packages/squad-sdk/src/backend/durable-http-backend.ts |
Implements HTTP backend client. |
packages/squad-sdk/package.json |
Exposes new package entrypoints. |
packages/squad-cli/src/cli/core/upgrade.ts |
Refreshes projections and casting state. |
packages/squad-cli/src/cli/core/init.ts |
Projects clients and guards interactive prompts. |
packages/squad-cli/src/cli/core/command-help.ts |
Documents client flags. |
packages/squad-cli/src/cli/core/clients.ts |
Persists and synchronizes client configuration. |
packages/squad-cli/src/cli/core/backend-mcp.ts |
Exposes backend operations as MCP tools. |
packages/squad-cli/src/cli/commands/state-mcp.ts |
Registers backend MCP tools. |
packages/squad-cli/src/cli-entry.ts |
Parses and forwards client flags. |
docs/tutorials/multi-client-quickstart.md |
Provides host setup walkthroughs. |
docs/tutorials/durable-backend-and-custom-harness.md |
Explains backend and harness integration. |
docs/src/navigation.ts |
Links new documentation pages. |
docs/src/content/docs/scenarios/using-squad-across-clients.md |
Documents multi-host workflows. |
docs/src/content/docs/scenarios/client-compatibility.md |
Links multi-host guidance. |
docs/src/content/docs/reference/sdk.md |
Documents adapter APIs. |
docs/src/content/docs/reference/config.md |
Documents persisted client IDs. |
docs/src/content/docs/reference/cli.md |
Documents multi-host CLI usage. |
docs/src/content/docs/concepts/squad-2-0-architecture.md |
Explains architectural boundaries. |
docs/SQUAD-2.0-OVERVIEW.md |
Summarizes architecture and conformance goals. |
docs/specification/README.md |
Registers new specification profiles. |
docs/specification/client-backend-decoupling-v0.2.md |
Defines decoupling requirements. |
docs/specification/adr-001-client-control-execution-boundary.md |
Records architectural decision. |
docs/proposals/squad-2.0-security-and-isolation.md |
Defines proposed security gates. |
cspell.json |
Adds domain vocabulary. |
CONTRIBUTING.md |
Adds adapter contribution guidance. |
.changeset/squad-2-0-multi-host-clients.md |
Declares major SDK and CLI releases. |
Review effort: Balanced
…-rejection audit, stable outbox operationId Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
CI: drop the root SDK source alias from vitest.config.ts (dual module instances), wrap --client help lines to <=80 cols. Backend: normalize legacy outbox ids, recovery-mutex stale-lock handling, persisted admission cursor + payload conflict detection, keep deliveries when the harness is missing, no re-entrant load on synchronous replay, createMcpBackend honors the configured state backend, HTTP body reads retried. Client/casting: TOML [[array_table]] boundaries and quoted keys, capability tokens 1:1 with capability-matrix.json, retired agents preserved and repairs committed through the canonical manifest writer. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
…ox through before delivery, journey + repro tests Restores .github/agents/squad.agent.md (a local test run had stamped it, failing template-sync in CI). Repairs a handwritten casting registry before the strict upgrade preflight and keeps config.json writes inside the squad dir. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
…only when no cast history exists A blanket pre-repair defeated the deliberate fail-closed refusals for registries with real history (test/cli/legacy-casting-upgrade). Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 995eea17-c356-4912-90ea-5e5b144e7ba9
|
Superseded by the 4-PR stack (Stack #2255) addressing all review recommendations and splitting the changes into smaller, focused layers:
|
… repair - Validate each record against its existing map key first in normalizeHandwrittenCastingRegistry so valid provenance records (e.g. agents.belanna named B'Elanna with .squad/agents/belanna/ avatar) preserve their map key - Require valid retired_at on legacy retired records in isAcceptable so retired records missing retired_at reach normalization instead of early-exiting - Resolve snapshot agent values first in normalizeHandwrittenHistory and reject unknown agent values or disagreement with a recognized ID key - Require registry, history, and commit manifest generation metadata (transaction_id and revision) to agree before stripping and recommitting in recommitExistingPair - Reject symlinked handwritten-archive-<sha256> directories and archive target files via assertNotSymlink before creating or writing archives Refs #2239 Refs #2252 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: c854ee92-c40c-4436-8a2c-901b1f781776
- Auto-select a single registered in-process harness in `squad_backend_send_message` when `harness` is omitted, and reject an omitted `harness` when multiple harnesses are registered instead of silently queueing; keep remote routing separate
- Default an omitted `limit` in `squad_backend_read_events` to `MAX_READ_EVENTS_LIMIT` (500)
- Read the response body outside the JSON parse `try/catch` in `DurableHttpSquadBackend.probe` so body timeouts and stream errors fail health checks
- Coordinate in-flight `adapter.submit` dispatches by `(conversationId, runId, seq)` and pass a deterministic `operationId` (`${conversationId}:${runId}:${seq}`) for crash-retry deduplication
- Remove queued approval deliveries for a turn when committing cancellation (`markCancelled` / terminal state) so `flushDeliveries` never retries or blocks on an obsolete approval
- Thread the publishing `harnessId` through `ensureSubscribed`, `applyEvent`, and `applyEventLocked` (including synchronous subscription replay) and verify it matches the turn's routed harness
- Reject a second distinct `approval-requested` event while a turn already has a `pendingApproval`
- Derive `createStateBackendStore` lock identity from the canonical shared storage (`.git` common dir across linked worktrees, resolved via `realpathSync.native`) and the state ref (`refs/heads/<branch>` or `refs/notes/<ref>`), unwrapping `TwoLayerBackend`
- Clear ambient `SQUAD_BACKEND_URL`, `SQUAD_BACKEND_TOKEN`, and `SQUAD_EXPERIMENTAL_BACKEND` before applying explicit test environment values in `McpStdioClient`
Refs #2239, #2253
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5ff02830-3b62-4a0a-8752-bc54a0bc3639
…ions (Layer 1) Carves Layer 1 of #2239 targeting dev and applies all Layer 1 review fixes: - Isolate host coordinator projections so non-Squad sessions are not hijacked: - Codex writes full coordinator prompt to .codex/agents/squad.md and only a short discovery pointer block in AGENTS.md - Kiro sets .kiro/steering/squad.md to inclusion: manual (loaded by .kiro/agents/squad.json) - Cursor sets .cursor/rules/squad.mdc to alwaysApply: false - Make multi-client projection strictly opt-in (no default .claude/worktrees/ or NUL in .gitignore on plain init/upgrade) - Synchronize coordinator.ts with .github/agents/squad.agent.md as the canonical coordinator source of truth - Throw on unclosed or inverted Squad managed block markers in upsertBlock/removeBlock - Normalize inline and dotted squad_state TOML definitions in upsertTomlTable/removeTomlTable without duplicates - Import from @bradygaster/squad-sdk/client, merge repeated --client flags, preserve unknown portable client IDs in config.json with a warning, and reject symlinked .squad directories Refs #2239 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 7a8a1fc8-bd63-4811-920c-7be89c631d5e
…m team.md (Layer 2) Carves Layer 2 of #2239 targeting tamirdresher-microsoft-stack-1-client-adapters and applies all Layer 2 review fixes: - Acquire the casting writer lock (with symlink/lstat guards) BEFORE reading registry.json, history.json, or registry-history.commit.json in repairHandwrittenCastingRegistry and backfillCastingRegistryFromTeam - Do not leave *.handwritten.bak clutter in .squad/casting/ by default (only when options.keepBackup === true is explicitly passed) - Restore the exact in-memory pre-repair snapshot to disk and rethrow if commitCastingRegistryPair fails (never fall back to writing a fresh cast or deleting registry-history.commit.json) - Never touch or rewrite valid canonical registries or registries with existing cast history - Validate handwritten registry repair in memory during `squad upgrade --dry-run` so dry-run previews succeed without mutating disk while still failing closed on corrupt/unrepairable registries - Guard interactive prompts in `squad init` via `isInteractiveSession()` Refs #2239 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: c854ee92-c40c-4436-8a2c-901b1f781776
… repair - Validate each record against its existing map key first in normalizeHandwrittenCastingRegistry so valid provenance records (e.g. agents.belanna named B'Elanna with .squad/agents/belanna/ avatar) preserve their map key - Require valid retired_at on legacy retired records in isAcceptable so retired records missing retired_at reach normalization instead of early-exiting - Resolve snapshot agent values first in normalizeHandwrittenHistory and reject unknown agent values or disagreement with a recognized ID key - Require registry, history, and commit manifest generation metadata (transaction_id and revision) to agree before stripping and recommitting in recommitExistingPair - Reject symlinked handwritten-archive-<sha256> directories and archive target files via assertNotSymlink before creating or writing archives Refs #2239 Refs #2252 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: c854ee92-c40c-4436-8a2c-901b1f781776
…tract (Layer 3) Carves Layer 3 of #2239 targeting tamirdresher-microsoft-stack-2-casting-repair and applies all Layer 3 review fixes: - Export the experimental conversation & harness contract from `@bradygaster/squad-sdk/backend` only (`BACKEND_CONTRACT_STAGE = 'experimental'`) without re-exporting from the root `@bradygaster/squad-sdk` barrel - Gate `squad_backend_*` MCP tools in `squad state-mcp` behind explicit opt-in (`--experimental-backend`, `SQUAD_EXPERIMENTAL_BACKEND=1`, or `SQUAD_BACKEND_URL`) - Fix `createFileStateStore` lock contention `catch` block so persistent `EACCES`/`EPERM` errors respect `lockTimeoutMs` and sleep between polls instead of spinning forever, and reject symlinked `.squad` or store root directories via `lstatSync` - Track pending harness submissions in `LocalSquadBackend.sendMessage` so a failed or interrupted `harness.submit` is recovered on a same-`(runId, seq)` retry and returns the original admission cursor - Implement real cross-process `wx` file locking with stale-lock recovery and symlink guards in `createStateBackendStore` - Add per-attempt `requestTimeoutMs` (default 15_000 ms) via `AbortSignal.timeout` in `DurableHttpSquadBackend` Refs #2239 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5ff02830-3b62-4a0a-8752-bc54a0bc3639
- Auto-select a single registered in-process harness in `squad_backend_send_message` when `harness` is omitted, and reject an omitted `harness` when multiple harnesses are registered instead of silently queueing; keep remote routing separate
- Default an omitted `limit` in `squad_backend_read_events` to `MAX_READ_EVENTS_LIMIT` (500)
- Read the response body outside the JSON parse `try/catch` in `DurableHttpSquadBackend.probe` so body timeouts and stream errors fail health checks
- Coordinate in-flight `adapter.submit` dispatches by `(conversationId, runId, seq)` and pass a deterministic `operationId` (`${conversationId}:${runId}:${seq}`) for crash-retry deduplication
- Remove queued approval deliveries for a turn when committing cancellation (`markCancelled` / terminal state) so `flushDeliveries` never retries or blocks on an obsolete approval
- Thread the publishing `harnessId` through `ensureSubscribed`, `applyEvent`, and `applyEventLocked` (including synchronous subscription replay) and verify it matches the turn's routed harness
- Reject a second distinct `approval-requested` event while a turn already has a `pendingApproval`
- Derive `createStateBackendStore` lock identity from the canonical shared storage (`.git` common dir across linked worktrees, resolved via `realpathSync.native`) and the state ref (`refs/heads/<branch>` or `refs/notes/<ref>`), unwrapping `TwoLayerBackend`
- Clear ambient `SQUAD_BACKEND_URL`, `SQUAD_BACKEND_TOKEN`, and `SQUAD_EXPERIMENTAL_BACKEND` before applying explicit test environment values in `McpStdioClient`
Refs #2239, #2253
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5ff02830-3b62-4a0a-8752-bc54a0bc3639
…osts (Layer 4) Split from #2239 (Layer 4 of 4): - Canonicalize @bradygaster/squad-sdk/client across architecture, overview, quickstart, and SDK docs - Add Experimental Preview / Bring Your Own Server callouts for @bradygaster/squad-sdk/backend and document opt-in --experimental-backend / SQUAD_EXPERIMENTAL_BACKEND=1 MCP tools - Update all 5-host lists to all 7 hosts (copilot, claude, kiro, opencode, cursor, codex, antigravity) and align generated-file tables with Layer 1 projections - Consolidate architecture and multi-client docs into published Astro pages and align v0.2 specs Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3ed7a60c-f40f-40e8-8b56-c39cf1a0ffe9
… Cursor, Codex, and Antigravity [1/4] (#2251) * feat(client): add multi-host --client adapters and opt-in CLI projections (Layer 1) Carves Layer 1 of #2239 targeting dev and applies all Layer 1 review fixes: - Isolate host coordinator projections so non-Squad sessions are not hijacked: - Codex writes full coordinator prompt to .codex/agents/squad.md and only a short discovery pointer block in AGENTS.md - Kiro sets .kiro/steering/squad.md to inclusion: manual (loaded by .kiro/agents/squad.json) - Cursor sets .cursor/rules/squad.mdc to alwaysApply: false - Make multi-client projection strictly opt-in (no default .claude/worktrees/ or NUL in .gitignore on plain init/upgrade) - Synchronize coordinator.ts with .github/agents/squad.agent.md as the canonical coordinator source of truth - Throw on unclosed or inverted Squad managed block markers in upsertBlock/removeBlock - Normalize inline and dotted squad_state TOML definitions in upsertTomlTable/removeTomlTable without duplicates - Import from @bradygaster/squad-sdk/client, merge repeated --client flags, preserve unknown portable client IDs in config.json with a warning, and reject symlinked .squad directories Refs #2239 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 7a8a1fc8-bd63-4811-920c-7be89c631d5e * fix(client): audit fixes for --client adapters (Codex TOML agent, symlink root handling, EOL/indent-preserving merges) - H1: Codex coordinator is now a TOML custom agent (.codex/agents/squad.toml with name/description/developer_instructions, escaped multi-line string); AGENTS.md pointer, ANCHORS, dispatch text and uninstall updated - H2: resolveInsideRoot realpaths the root once and only lstats components below it, so junctioned/symlinked ancestors (OneDrive, ~/code -> /Volumes) work; syncClients returns early with no requested/configured clients before any filesystem checks - M2: symlinked target files inside the root (AGENTS.md -> CLAUDE.md) are written through; symlinks escaping the root are still refused - M1: new 'lines' projection kind for .gitignore (plain lines under a `# squad:<id>` comment, no HTML markers); uninstall removes only the lines Squad added - M3: emitted content follows the existing file's dominant EOL (LF for new files) for blocks, lines, JSON, TOML and removals - M4: JSON merges preserve indentation (tabs/N spaces) and trailing-newline; OpenCode targets opencode.jsonc when it is the only config and reports an error instead of clobbering JSONC with comments - M5: only persist newly requested clients whose projection had no errors (configured ones stay); atomic temp+rename writes; `squad upgrade --dry-run --client` prints the clients it would project (syncClients dryRun option) - M6: real-CLI tests gated behind SQUAD_REAL_CLI_TESTS=1, PATH-only binary discovery, no hardcoded paths, shell:false, cursor-agent check is read-only - changeset wording updated; tests added/updated in test/clients.test.ts Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 92888fd8-c715-4d1d-a60f-893a7a157841 * fix(client): resolve all 6 Copilot PR review threads on #2251 - apply.ts (Thread 1): preserve parsed TOML key segments across sectionHeader, tableHeaderKeys, findTable, stripConflictingDottedAndInline, and removeTomlTable so quoted-dot server names ([mcp_servers."squad_state.env"]) remain untouched - apply.ts (Thread 2): track multiline basic (""") and literal (''') string boundaries in assignmentEnd and advance scanners across multiline assignments so embedded TOML examples in developer_instructions are never rewritten - apply.ts (Thread 3): refuse to extend enclosing ancestor inline/scalar tables (e.g. mcp_servers = { other = ... }) or non-table squad_state assignments - portable.ts (Thread 4): trim before sensitivity checks and redact bare credential prefixes (ghp_, github_pat_, sk-, glpat-, xox*, AKIA, JWT) so they never surface in unknown-ID warnings or persist in config.json - adapters.ts & clients-real-cli.test.ts (Thread 5): project native Codex .codex/agents/squad.toml role and verify real-CLI role discovery + coordinator developer_instructions activation on spawn_agent - clients.ts & clients.test.ts (Thread 6): document the default Copilot bootstrap exception (.github/agents/squad.agent.md + .mcp.json) and test both plain runInit and runUpgrade command pipelines directly Refs #2251 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 7a8a1fc8-bd63-4811-920c-7be89c631d5e --------- Co-authored-by: Copilot <Copilot@users.noreply.github.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 7a8a1fc8-bd63-4811-920c-7be89c631d5e Copilot-Session: 92888fd8-c715-4d1d-a60f-893a7a157841
…ry-run support [2/4] (#2252) * feat(casting): repair handwritten casting registries and backfill from team.md (Layer 2) Carves Layer 2 of #2239 targeting tamirdresher-microsoft-stack-1-client-adapters and applies all Layer 2 review fixes: - Acquire the casting writer lock (with symlink/lstat guards) BEFORE reading registry.json, history.json, or registry-history.commit.json in repairHandwrittenCastingRegistry and backfillCastingRegistryFromTeam - Do not leave *.handwritten.bak clutter in .squad/casting/ by default (only when options.keepBackup === true is explicitly passed) - Restore the exact in-memory pre-repair snapshot to disk and rethrow if commitCastingRegistryPair fails (never fall back to writing a fresh cast or deleting registry-history.commit.json) - Never touch or rewrite valid canonical registries or registries with existing cast history - Validate handwritten registry repair in memory during `squad upgrade --dry-run` so dry-run previews succeed without mutating disk while still failing closed on corrupt/unrepairable registries - Guard interactive prompts in `squad init` via `isInteractiveSession()` Refs #2239 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: c854ee92-c40c-4436-8a2c-901b1f781776 * fix(casting): per-record handwritten registry repair, charter-derived backfill ids, roll-forward-safe rollback - H3: normalize handwritten registries per record — records that already parse as valid provenance records are preserved verbatim (all fields, timestamps, per-record universe); only incomplete records get missing fields synthesized. Preserve and bump the registry revision instead of resetting it. Archive pre-repair originals under handwritten-archive-<sha256>/ by default (keepBackup: false opts out) and report backupPath. - H4: backfillCastingRegistryFromTeam derives agent ids from the team.md Charter column (.squad/agents/<id>/charter.md) or a charter whose ## Identity name matches; rows with no provable folder fail the backfill closed with a dropped list. Fix the test that expected "b-elanna" for the belanna folder. - M8: wrapper-less shapes only accept record values carrying name/persistent_name/display_name/role; bare-string values and non-agent metadata are reported instead of guessed. Non-Latin names, duplicate names and id collisions no longer drop silently — RepairResult.dropped is populated and the repair fails closed; squad upgrade prints the reason and each dropped entry. - M7: commitPairWithRollback only restores the pre-repair snapshot when the commit failed before its journal became durable (never on CastingCommitInDoubtError or after a successful commit), restores via temp+fsync+rename, and attaches restore failures as cause. recoverCastingRegistryTransaction runs under the lock before the snapshot so pending journals roll forward first. - M9: single exported hasExistingCastHistory (empty arrays/objects are not history) replaces the CLI copy; a history.json holding one Init Mode snapshot consistent with the handwritten registry is normalized instead of blocking the repair. squad upgrade --dry-run previews the team.md backfill. - Low: strip UTF-8 BOM before JSON.parse; anchor the team.md universe regex to a line start / table cell and fail the backfill closed instead of inventing one; recommit of a manifest-mismatched pair bumps the revision and requires a readable history object. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 92888fd8-c715-4d1d-a60f-893a7a157841 * fix(casting): address PR #2252 review threads on handwritten registry repair - Validate each record against its existing map key first in normalizeHandwrittenCastingRegistry so valid provenance records (e.g. agents.belanna named B'Elanna with .squad/agents/belanna/ avatar) preserve their map key - Require valid retired_at on legacy retired records in isAcceptable so retired records missing retired_at reach normalization instead of early-exiting - Resolve snapshot agent values first in normalizeHandwrittenHistory and reject unknown agent values or disagreement with a recognized ID key - Require registry, history, and commit manifest generation metadata (transaction_id and revision) to agree before stripping and recommitting in recommitExistingPair - Reject symlinked handwritten-archive-<sha256> directories and archive target files via assertNotSymlink before creating or writing archives Refs #2239 Refs #2252 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: c854ee92-c40c-4436-8a2c-901b1f781776 --------- Co-authored-by: Copilot <Copilot@users.noreply.github.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: c854ee92-c40c-4436-8a2c-901b1f781776 Copilot-Session: 92888fd8-c715-4d1d-a60f-893a7a157841
…tract [3/4] (#2253) * feat(backend): add experimental /backend conversation and harness contract (Layer 3) Carves Layer 3 of #2239 targeting tamirdresher-microsoft-stack-2-casting-repair and applies all Layer 3 review fixes: - Export the experimental conversation & harness contract from `@bradygaster/squad-sdk/backend` only (`BACKEND_CONTRACT_STAGE = 'experimental'`) without re-exporting from the root `@bradygaster/squad-sdk` barrel - Gate `squad_backend_*` MCP tools in `squad state-mcp` behind explicit opt-in (`--experimental-backend`, `SQUAD_EXPERIMENTAL_BACKEND=1`, or `SQUAD_BACKEND_URL`) - Fix `createFileStateStore` lock contention `catch` block so persistent `EACCES`/`EPERM` errors respect `lockTimeoutMs` and sleep between polls instead of spinning forever, and reject symlinked `.squad` or store root directories via `lstatSync` - Track pending harness submissions in `LocalSquadBackend.sendMessage` so a failed or interrupted `harness.submit` is recovered on a same-`(runId, seq)` retry and returns the original admission cursor - Implement real cross-process `wx` file locking with stale-lock recovery and symlink guards in `createStateBackendStore` - Add per-attempt `requestTimeoutMs` (default 15_000 ms) via `AbortSignal.timeout` in `DurableHttpSquadBackend` Refs #2239 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5ff02830-3b62-4a0a-8752-bc54a0bc3639 * fix(backend): align experimental backend docs with implementation; harden durable-http, locks and MCP opt-in - H5: rewrite test/squad-20-security-contracts.test.ts to exercise product code (createFileStateStore/resolveInsideRoot guards, mergeMcpServer/installClients, LocalSquadBackend idempotency/epochs/approvals/cursors, backend-mcp, DurableHttp); delete self-referential reference guards; proposal no longer claims an "executable contract" or CI-blocking gates - H6: proposal, ADR and spec now describe the shipped behavior: opaque harness-supplied approval hash echoed back, cooperative client-asserted epochs (explicitly not a security boundary), unsigned cursors; stronger properties moved to "Future work / not implemented" - H7: replace spec TypeScript contracts with the real signatures from backend/types.ts (SquadBackend, HarnessAdapter, RunState, ...); golden-trace fixture uses real BackendEnvelope.type names and the e2e runner no longer needs a translation table - M10: squad_backend_send_message returns BackendError 'unavailable' when no harness is registered instead of queueing forever; health/negotiate expose harnesses: [] and executionAvailable: false; tool descriptions and specs state the bridge is transcript/event-log only - M11: git-ignore .squad/backend/ in the upgrade scaffold (no merge=union) - M12: SQUAD_BACKEND_URL alone no longer enables the tools; DurableHttp validates baseUrl (https, or http to loopback), uses redirect: 'error' - M13: health probes get AbortSignal.timeout; file-store lock acquisition is async (lockAsync) for backend methods; read() only treats ENOENT as missing; corrupt conversation JSON surfaces as BackendError with the path; temp file is fsync'd before rename; spec documents whole-file snapshot limitation - M14: createStateBackendStore requires a deterministic lock root (no mkdtemp fallback) and no longer prunes lock directories after release - Low: MCP arg validation (role/parts/protocols/limit cap 500), generic message for non-contract errors, Windows reserved device names rejected as conversation ids, misplaced comment fixed, real-binary tests gated behind SQUAD_REAL_CLI_TESTS=1, flaky opt-in test timeout raised Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 92888fd8-c715-4d1d-a60f-893a7a157841 * fix(stack): align e2e scenarios with audited adapter/casting behavior; keep configured state backend out of .squad/backend; fail-closed casting repair reports instead of crashing - e2e expectation updates for the audited stack behavior: Codex agent is `.codex/agents/squad.toml`; `.gitignore` projections are `# squad:claude` plain lines (exact restoration on removal still asserted); `normalizeHandwrittenCastingRegistry` callers use the new `NormalizeHandwrittenResult` shape; repair archives originals under `handwritten-archive-<sha256>/` instead of `.handwritten.bak`; a manifest-only recommit bumps the revision by one and keeps agents/history; team.md backfill resolves ids from charter folders (`belanna`, not `b-elanna`) and `parseTeamRoster` members carry `charterId`; a roster with no provable agent folder fails closed with the dropped row named - role-keyed fixture now uses object entries (`tester: { name }`) since bare strings are rejected by design; a dedicated case asserts the bare-string rejection reason - createStateBackendStore: a configured non-local state backend (git-notes, orphan, or any backend without a `root`) no longer gets its lock root from the team `.squad` dir. Locks live in a deterministic machine-local directory derived from the backend identity (`cwd` or the new `lockAnchor` option); `createMcpBackend` passes `lockAnchor` instead of `squadDir`, so `.squad/backend/` is never created when a non-local backend is configured - squad upgrade: when the handwritten-registry repair fails closed and the pair is not readable as a managed pair, `ensureCastingDefaults` and the pre-preflight repair in `runUpgrade` throw an actionable error (reason, dropped entries, how to fix) instead of the generic "exactly one authoritative file exists" / preflight error Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 92888fd8-c715-4d1d-a60f-893a7a157841 * docs(spec): align Codex anchor and Claude .gitignore lines with projection code Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 92888fd8-c715-4d1d-a60f-893a7a157841 * fix(upgrade): keep legacy casting preflight authoritative; enrich only its generic error with the handwritten-repair reason The fail-closed handwritten-registry path pre-empted preflightCastingRegistryPair, so legacy`entries` registries (and --dry-run) got the new error instead of the legacy migration/refusal they had before. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 92888fd8-c715-4d1d-a60f-893a7a157841 * fix(backend): resolve all 9 PR #2253 Copilot review findings - Auto-select a single registered in-process harness in `squad_backend_send_message` when `harness` is omitted, and reject an omitted `harness` when multiple harnesses are registered instead of silently queueing; keep remote routing separate - Default an omitted `limit` in `squad_backend_read_events` to `MAX_READ_EVENTS_LIMIT` (500) - Read the response body outside the JSON parse `try/catch` in `DurableHttpSquadBackend.probe` so body timeouts and stream errors fail health checks - Coordinate in-flight `adapter.submit` dispatches by `(conversationId, runId, seq)` and pass a deterministic `operationId` (`${conversationId}:${runId}:${seq}`) for crash-retry deduplication - Remove queued approval deliveries for a turn when committing cancellation (`markCancelled` / terminal state) so `flushDeliveries` never retries or blocks on an obsolete approval - Thread the publishing `harnessId` through `ensureSubscribed`, `applyEvent`, and `applyEventLocked` (including synchronous subscription replay) and verify it matches the turn's routed harness - Reject a second distinct `approval-requested` event while a turn already has a `pendingApproval` - Derive `createStateBackendStore` lock identity from the canonical shared storage (`.git` common dir across linked worktrees, resolved via `realpathSync.native`) and the state ref (`refs/heads/<branch>` or `refs/notes/<ref>`), unwrapping `TwoLayerBackend` - Clear ambient `SQUAD_BACKEND_URL`, `SQUAD_BACKEND_TOKEN`, and `SQUAD_EXPERIMENTAL_BACKEND` before applying explicit test environment values in `McpStdioClient` Refs #2239, #2253 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5ff02830-3b62-4a0a-8752-bc54a0bc3639 --------- Co-authored-by: Copilot <Copilot@users.noreply.github.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 5ff02830-3b62-4a0a-8752-bc54a0bc3639 Copilot-Session: 92888fd8-c715-4d1d-a60f-893a7a157841
…umentation [4/4] (#2254) * docs(squad-2.0): consolidate multi-client and backend docs across 7 hosts (Layer 4) Split from #2239 (Layer 4 of 4): - Canonicalize @bradygaster/squad-sdk/client across architecture, overview, quickstart, and SDK docs - Add Experimental Preview / Bring Your Own Server callouts for @bradygaster/squad-sdk/backend and document opt-in --experimental-backend / SQUAD_EXPERIMENTAL_BACKEND=1 MCP tools - Update all 5-host lists to all 7 hosts (copilot, claude, kiro, opencode, cursor, codex, antigravity) and align generated-file tables with Layer 1 projections - Consolidate architecture and multi-client docs into published Astro pages and align v0.2 specs Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3ed7a60c-f40f-40e8-8b56-c39cf1a0ffe9 * docs(squad-2.0): reflect audited behavior (Codex TOML agent, .gitignore lines, backend opt-in and harness caveats, https-only durable-http) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 92888fd8-c715-4d1d-a60f-893a7a157841 * docs(squad-2.0): address #2254 review threads, prepare 2.0.0 release notes & pack smoke test - Clarify in reference/sdk.md, reference/config.md, and reference/cli.md that createSquadBackend / DurableHttpSquadBackend require explicit baseUrl (and optional token), while automatic SQUAD_BACKEND_URL / SQUAD_BACKEND_TOKEN lookup applies only to squad state-mcp when experimental backend tools are enabled - Use canonical BACKEND_CAPABILITIES tokens (cursor-reconnect, approvals, cancel-run, typed-content-parts) in durable-backend-and-custom-harness.md - Give each turn a distinct approvalId and track (runId, seq) per conversation and approvalId in DemoHarnessAdapter - Update .changeset/squad-2-0-multi-host-clients.md with major bumps for @bradygaster/squad, @bradygaster/squad-sdk, and @bradygaster/squad-cli and release-notes summary - Add v2.0.0 release notes to whatsnew.md, Upgrading to Squad 2.0 section to scenarios/upgrading.md and get-started/migration.md, and host capability matrix / Phase 2 limitations to architecture and multi-client docs - Add test/squad-20-pack-smoke.test.ts for npm pack clean-install and v1.1.0 -> 2.0 upgrade/rollback verification Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3ed7a60c-f40f-40e8-8b56-c39cf1a0ffe9 --------- Co-authored-by: Copilot <Copilot@users.noreply.github.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3ed7a60c-f40f-40e8-8b56-c39cf1a0ffe9 Copilot-Session: 92888fd8-c715-4d1d-a60f-893a7a157841


Squad 2.0: decoupled backend + multi-host client adapters
Squad can now run natively in Claude Code, Kiro, OpenCode, Cursor, OpenAI Codex and Google Antigravity (plus Copilot), with the host client decoupled from the state/backend. Hosts own native bootstrap/projection and capability declaration; conversation semantics, routing, durable state and authorization stay in the shared backend contract. MCP (
squad_state) is a local tool transport bridge behind that contract, not the wire contract.This branch is the integrated Squad 2.0 line (over
dev), so it carries the earlier backend/spec work as well as the client adapters.Reviewer map (suggested order: spec → interfaces → backend → projections → CLI → tests → docs)
docs/specification/client-backend-decoupling-v0.2.md,docs/specification/client-harness-adapters-v0.2.md,docs/specification/adr-001-client-control-execution-boundary.md, normative fixturestest-fixtures/spec/suite-v0.2/capability-matrix.jsonandtest-fixtures/spec/suite-v0.2/golden-trace.json.packages/squad-sdk/src/backend/types.ts(SquadBackend, envelope/cursor/error/capability types,HarnessAdapterSPI) andpackages/squad-sdk/src/client/adapter-contract.ts(ClientAdapterfacade,AdapterUnboundError,createClientAdapter).packages/squad-sdk/src/backend/local-backend.ts,durable-http-backend.ts,harness-registry.ts,index.ts(createSquadBackend); the MCP transport adapterpackages/squad-cli/src/cli/core/backend-mcp.tswired throughpackages/squad-cli/src/cli/commands/state-mcp.ts.packages/squad-sdk/src/client/adapters/{types,adapters,capabilities,apply,portable,coordinator}.ts; casting-registry repair/backfill inpackages/squad-sdk/src/casting/handwritten-registry.ts.packages/squad-cli/src/cli/core/clients.ts,init.ts,upgrade.ts,packages/squad-cli/src/cli-entry.ts,packages/squad-cli/src/cli/commands/cast.ts.test/specification-suite.test.ts,test/backend.test.ts,test/clients.test.ts,test/clients-real-cli.test.ts,test/squad-20-security-contracts.test.ts,test/squad-20-all-scenarios.e2e.test.ts,test/squad-20-real-clients-stdio.e2e.test.ts,test/docs-build.test.ts,test/cli-command-wiring.test.ts.docs/SQUAD-2.0-OVERVIEW.md,docs/tutorials/multi-client-quickstart.md,docs/tutorials/durable-backend-and-custom-harness.md,docs/src/content/docs/concepts/squad-2-0-architecture.md,docs/src/content/docs/scenarios/using-squad-across-clients.md,docs/proposals/squad-2.0-security-and-isolation.md.What's in it
packages/squad-sdk/src/backend/): decoupled backend, harness SPI, MCP bridge, security/conformance contracts, RC1-to-stable exit-criteria tests.packages/squad-sdk/src/client/):HostProjection: pure workspace projection forcopilot,claude,kiro,opencode,cursor,codex,antigravity(no runtime dependency).ClientAdapter(adapter-contract.ts): thin spec-compliant facade (describe,projectWorkspace,getCapabilities;submit/subscribe/cancel/respondApprovaldelegate to a bound runtime, otherwiseAdapterUnboundError).string[]capability tokens are authoritative; booleanClientCapabilitiesflags are a derived view (conflicts throw). Advertised vs negotiated (effectiveCapabilities= client ∩ backend ∩ policy) kept separate.@bradygaster/squad-sdk/clientsre-exports the same symbols..mcp.json,.kiro/settings/mcp.json,opencode.json,.cursor/mcp.json,.codex/config.tomlsurvivesquad upgrade.squad init --client <list|all>andsquad upgrade --client, persisted in.squad/config.jsonclients[](portable ids only; credentials/paths rejected). Hosts use only the coordinator file plus.squad/agents/<name>/charter.md(no per-member subagent files).docs/specification/*,docs/SQUAD-2.0-OVERVIEW.md, multi-client tutorials.Verification
npx vitest runovertest/cli-command-wiring.test.ts,test/specification-suite.test.ts,test/backend.test.ts,test/clients.test.ts,test/clients-real-cli.test.ts,test/squad-20-security-contracts.test.ts,test/squad-20-all-scenarios.e2e.test.ts(126 tests),test/squad-20-real-clients-stdio.e2e.test.ts,test/docs-build.test.ts; 17 conditional skips).test/clients-real-cli.test.tsruns the real claude, opencode, kiro, codex, agy and cursor-agent binaries against the generated config (run it alone if the machine is under load);squad-20-real-clients-stdio.e2espawns the realstate-mcpover stdio from each host's generated config.Known issues / caveats
test/cli-command-wiring.test.tsis fixed: the internalbackend-mcphelper moved fromcommands/tocli/core/backend-mcp.ts(it is imported bystate-mcp, not a CLI command). The spec deltas (7 hosts,HostProjection, capability tokens) are now inclient-harness-adapters-v0.2.mdandsuite-v0.2/capability-matrix.json.casting/handwritten-registry.ts), non-TTY-safesquad initprompts, and.gitignoreentries for.claude/worktrees/andNUL.npm run buildreports pre-existing@github/copilot-sdktyping errors insrc/adapter/client.ts;tscstill emits.squad(0.13.x) on PATH has a stubcast --name; the local build must come first on PATH.squad initlinks repos to a personal squad when one exists (existing behaviour; setSQUAD_NO_PERSONAL=1for clean demos).