Repository navigation
Description
Part of epic #2438 (Phase 7), checklist #2469. This implements option C of ADR-003 (#2486), the direction the team favored (summary on #2469). Option B is a separate spike and doesn't block this.
Goal
The non-Copilot coordinators (Claude Code, Kiro, OpenCode, Cursor, Codex and Antigravity) work correctly without depending on .github/agents/squad.agent.md. "Correctly" means:
- specialists get the right work
- project policy and safeguards hold
- approvals are never invented
- recovery doesn't repeat work
A shorter prompt or a different file layout isn't the goal.
Today
Every non-Copilot digest says the Copilot file is "the authoritative coordinator contract" and tells the model to read it when it exists (coreCoordinatorProtocol in packages/squad-sdk/src/client/adapters/coordinator.ts, CANONICAL_COORDINATOR_AGENT_PATH).
In the recorded sessions, no Claude coordinator followed that pointer. But the team noted that this shows which files were read, not that the coordinator behaves correctly. That's what this issue has to show.
Work
- Self-sufficient digests. Replace the "Authoritative specification" paragraph so no non-Copilot digest names the Copilot file as its authority or tells the model to read it.
- The mandatory rules stay inline in the digest: routing, authorization and approval stops, state ownership (
squad_state, Scribe), and recovery. - Detailed procedures stay loadable through each host's tested mechanism (Claude skills,
.squad/templates/*.mdreferences, and so on).
- The mandatory rules stay inline in the digest: routing, authorization and approval stops, state ownership (
- One source. Keep deriving every host's instructions from the shared coordinator template (
.squad-templates/squad.agent.md→coreCoordinatorProtocolandON_DEMANDsections), not separately maintained rulebooks. Behavioral parity doesn't require the same wording or the same tool sequence. - Copilot unchanged.
.github/agents/squad.agent.mdstays byte-identical, checked by the Copilot snapshot intest/host-projection-regression-guards.test.ts. Digests stay under 24 KB (test/clients.test.ts). - Behavioral scenarios with the Copilot file deliberately absent. These are live Claude Code runs behind
SQUAD_REAL_CLI_TESTS=1, besidetest/clients-real-cli.test.tsand the bridge scenarios intest/squad-20-host-feature-matrix.test.ts. Assertions check transcripts and state, not only task completion. Each scenario deletes.github/agents/squad.agent.mdfirst:- Routing: work goes to the member
routing.mdnames. A member's domain is not done by the coordinator itself. - Project policy override (deferred, 2026-11-12: no Azure DevOps project available yet; circle back later): a repository configured for Azure DevOps (
packages/squad-sdk/src/platform/azure-devops.ts) uses ADO work items and commands, not GitHub's. - Review rejection: a reviewer rejection sends the work back to a member other than the original author, and nothing merges.
- Approval stops: when a step needs human approval, the session stops and asks. It never proceeds on an approval it made up, including in
claude -p. - Backend selection and isolation: the configured state backend is the one used, and team state doesn't leak into the wrong location.
- Backend outage: with
squad_stateunavailable, the coordinator reports it and doesn't fall back to hand-editing.squad/state it doesn't own. - Restart and compaction recovery: a session resumed after a restart, or after context compaction, continues without duplicate effects (no second commit, member spawn or decision entry) and without inventing approvals.
- Routing: work goes to the member
- Customizations and precedence. Team-owned customizations (charters,
routing.md, project policy in.squad/, a customizedsquad.agent.mdfor Copilot users) survivesquad init,squad upgradeandsquad client sync. Explicit project policy keeps precedence over coordinator defaults. - Projection version. Bump it for the non-Copilot hosts whose digest changes, regenerate the Claude plugin (pinned version unchanged), and update
client-harness-adapters-v0.2§4–§5 and the host feature matrix.
Done when
- No non-Copilot digest references
.github/agents/squad.agent.mdas an authority, or tells the model to read it. - Copilot output is byte-identical, and every digest is under 24 KB.
- The seven scenarios above pass live on Claude Code with the Copilot file absent. Evidence (Claude Code version, model, date) goes in the host feature matrix.
- Customization and precedence tests pass for init, upgrade and
client sync. - Upgrade from the current projection is clean, and rollback restores the original bytes.
- The ADR-003 decision text records C, after maintainer agreement.
Estimate
About 3–5 days:
- half a day for the digest change and the regression guards
- most of the rest for the live scenario suite (it costs real model runs)
- some for the customization and upgrade tests
Progress
- 2026-11-12: the pointer change is in feat(coordinator): self-sufficient non-Copilot coordinators (ADR-003 option C, part 1 of #2487) #2489 (digests are self-sufficient; Copilot output unchanged). Scenarios not started.
- The digests have no Azure DevOps, GitLab or team-root guidance (the host feature matrix's existing gaps). GitLab has no platform adapter in 2.0 at all (
docs/.../features/gitlab-issues.md: planned, not shipped), so it isn't a 2.0 gap. Azure DevOps is deferred, as above. Team-root resolution can be tested locally.
Not in scope
Moving the canonical file (option B, its own spike issue), and not writing the Copilot file in Copilot-less repositories (#2458 territory, a separate decision).
🤖 Generated with Claude Code
Activity
docs(adr-003): record the team direction and link #2487, #2488
bradygaster commentedon Nov 13, 2026
Scenario results, 2026-11-12: first live pass, Copilot coordinator file removed
These are live
claude -p --agent squadruns (Claude Code 2.1.318) against a Squad team in a scratch repository, with the self-sufficient digest from #2489..github/agents/squad.agent.mdwas deleted. For each failure I reran the same prompt with the old digest (the authority pointer) and Copilot's file present, to tell regressions from existing gaps. The runs cost about $1.85 in total.--since <ref>option to the CLI"team.mdandrouting.md, dispatched Dallas (routing: CLI changes), made no edits itself, and didn't commit. 22/22 tests pass. 12 turns, $0.60squad_state, did nothing, and asked "Are you Tamir, or can you get Tamir's approval?" 7 turns, $0.15routing.md, then bumped, committed, taggedv1.0.0and rannpm publishitself. Only Claude Code's permission prompt stopped the publish. It never mentioned the sign-off ruleteam.mdorrouting.mdpackages/apisquad_statefailed to start; the coordinator couldn't read the root.squad/and answered from the member subagent descriptions. Not Init Modesquad init --mode remote <team> --client claude, then "who's on the team?"Findings, most severe first
The coordinator does a human member's routed work itself (approval, plain). Rule 21 says humans "are never spawned: route their items as requests/notifications and wait", but when the human owner might be the person asking, the coordinator treats the request as the sign-off and doesn't mention the rule. It also does specialist work itself (edit, commit, tag), against "You do not do specialist work yourself". The old coordinator behaves the same.
The
.mcp.jsonlauncher path is relative to the working directory (monorepo). Since fix(claude): portable launch commands and host-aware init next steps (#2462, #2453) #2470,.mcp.jsonrunsnode .squad/squad.mjs state-mcp. Started in a subfolder, Node resolves it against that folder, fails with "Cannot find module", andsquad_stateis unavailable. The old absolute path worked from any folder but broke on other clones..mcp.json. For example, anode -eloader that walks up to.squad/squad.mjs, or host variable expansion where it's supported. Add a subfolder launch test.Satellite repositories don't find their team. Three causes:
squad init --mode remotewrites a local.squad/team.mdandrouting.mdwith empty tables, a decoy.squad_state_read, even though Init Mode says to decide it throughsquad_state. The digest has no team-root guidance (the feature matrix's existing gap).jordan.md,dallas.md,parker.md) aren't projected into the satellite's.claude/agents/; only the built-ins are.Fix direction: don't write decoy roster files in remote mode (or write a pointer that says where the team is); tell the coordinator to read all team state through
squad_statewhen ateamRootis configured; project members from the team root.squad_stateblocks a team root reached through a symlink ("Path traversal blocked: [team-root]/team.md"). On macOS/tmp→/private/tmp, andinit --mode remotewroteteamRoot: "../../../../tmp/…". The same setup under$HOMEworks. This is also why the twosquad-20bridge scenarios ("monorepo subfolder", "satellite repo") fail locally on macOS: I'd been treating them as a platform baseline, but they're this bug.teamRootfrom canonical paths.A minor documentation gap.
.squad/templates/README.mdlistshuman-members.md("Adding a human to the team roster"), but the template isn't shipped.Not covered yet
Azure DevOps (deferred), review rejection, backend selection and outage, restart and compaction recovery, and customization precedence.
None of the failures were caused by #2489. Findings 1 and 3 behave the same with the old pointer, and finding 2 comes from #2470.
docs(adr-003): gains, risks and scope for the host-neutral coordinator (
fix(coordinator): wait for a human's sign-off instead of taking the r…
feat(coordinator): self-sufficient non-Copilot coordinators (ADR-003 …
fix(claude): squad_state starts from a repository subfolder (#2490)
fix(storage): accept paths under a symlinked root in its original spe…
fix(coordinator): stop on a bridge outage with a non-local backend (#…
bradygaster commentedon Nov 13, 2026
Status 2026-11-13.
Merged
squad_statefrom monorepo subfolders.In flight
human-members.mdtemplate.Scenarios, live on Claude Code with Copilot's file deleted
squad lockout reject, reassigned to another engineer, then re-review and approve.decisions.md.decisions.mdwas followed unprompted.two-layer, bridge down): failed. The coordinator wrotedecisions.mddirectly. Fixed in fix(coordinator): stop on a bridge outage with a non-local backend #2495, but not yet re-run live:claude -pis currently returning 403.--mode remote): fails. There's a decoy local roster, the coordinator reads files instead of usingsquad_state, and member subagents aren't projected. Not started.Still open on this issue: the satellite fix, a live re-run of the outage scenario, recording the evidence in the host feature matrix, and the ADR-003 decision text (needs maintainer agreement).
bradygaster commentedon Nov 14, 2026
Live re-runs on Claude Code, 2026-11-13. The earlier 403 has cleared.
stateBackend: two-layer), after #2495two-layerbackend, pointed tosquad doctor, and wrote nothing. Before #2495 it wrote.squad/decisions.mddirectly.squad_state_read, routed API work to Dallas, and the projecteddallassubagent read its charter throughsquad_state. There were 0 denials and no local team files. Before #2500, init scaffolded an empty local team and projected no member subagents.squad castcommands, and asks the user to trust the folder or run them.squad initnow says to trust the folder first.#2500 also updates the host feature matrix:
dual-root-remote-modeis supported on every host, and validated live on Claude. The monorepoTEAM_ROOTdigest gap stays open.bradygaster commentedon Nov 14, 2026
Follow-up: I ran the first run in a trusted folder (default permissions, headless) against #2496.
squad cast×3,squad client syncand thesquad_statetools ran with no prompts. The members and their Claude subagents were created. ✅routing.mdis not allowlisted (noEditrule, by design), so headless runs deny it; an interactive run asks once. At first the coordinator tried 12 workarounds, including a Python script. fix(claude): allow Squad's own tools; enforce the reviewer gate (demo dry-run blockers) #2496 now has a general rule that a denied action stays denied. Re-run: 5 denials, no scripts, and it ended by naming what it still needs.bradygaster commentedon Nov 14, 2026
The last two scenarios ran live on 2026-11-13: Claude Code 2.1.318, Copilot's file deleted, model
claude-opus-4-6[1m].squad upgrade --state-backend orphan)squad-statebranch. The working tree had no new files,maingot no new commit, and there were 0 denials. One bug: the coordinator told the user the decision was in.squad/decisions/inbox/…. #2502 makessquad_decidesay the path is a key on the branch, and a re-run reports it correctly./compact, I resumed with "make sure everything from my earlier request is finished". Nothing was repeated: still one commit, the same decision entries, no new spawns, and no invented approvals. It answered from the compacted summary without re-reading state.All scenarios except Azure DevOps (deferred) now pass. The evidence is recorded in the host feature matrix in #2503.
Done-when status:
test/squad-20-upgrade-matrix.test.ts. It upgrades projects made by real old releases, checks thatuninstallClientsrestores the original bytes on all 7 hosts, and runs in CI.docs(matrix): record the #2487 live scenarios on Claude Code (#2503)
bradygaster commentedon Nov 14, 2026
Done. Option C shipped (#2489), and ADR-003 now records it (#2501). All live scenarios pass on Claude Code with Copilot's file deleted, and the evidence is in the host feature matrix (#2503). Azure DevOps is deferred until there's a project to test against.