diff --git a/CHANGELOG.md b/CHANGELOG.md index 0fa10bef6..fbce47aa9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -80,6 +80,7 @@ Claude Code is the first host after GitHub Copilot where Squad uses the host's o - `squad doctor` flags machine-specific launch commands and a missing launcher. Run `squad upgrade` once to fix an existing repository. - **Squad's own tools no longer prompt in Claude Code.** In a demo dry run, a fresh `squad init --client claude` project hit 13 permission prompts while casting the team, and the coordinator ended up hand-writing charters and asking the user to run `squad cast` themselves. `squad init` and `squad upgrade` now add a scoped allowlist to `.claude/settings.json`: the `squad_state` tools the coordinator uses, by name (never the experimental backend's approval tools), and `squad cast`, `squad client sync`, `squad lockout reject` and `squad lockout status` (the steps that release a lockout, `assign`, `submit`, `approve` and `override`, still ask), as `squad …` and, when `.mcp.json` runs Squad's own launcher, as `node .squad/squad.mjs …`. Nothing else is allowed, and `squad cast` now refuses to write through a symbolic link. Your own rules come first and are never touched; Squad records the rules it added in `.claude/.squad-permissions.json`, and rollback removes only those, and `"claudePermissions": "off"` in `.squad/config.json` turns it off. Claude Code applies project allow rules only after the folder is trusted (the trust prompt on your first interactive `claude` run there). `squad init` now says so, and if a cast is still denied the coordinator stops and asks instead of retrying variants or hand-writing the team. - **`squad_decide` says where a git-branch backend stored the decision.** In a live run on the `orphan` backend, the coordinator told the user the decision was in `.squad/decisions/inbox/…`, but it was only on the `squad-state` branch. The tool result now says the path is a key on that branch, so the coordinator reports it correctly. +- **A decision made in Claude Code reaches teammates on Copilot.** In a live run with one squad and two people, Alex on Claude Code recorded "API errors are JSON `{error, code}`". Blake on Copilot CLI was then told no error convention existed. Claude's coordinator had left the decision in the inbox, but Copilot's reads only the merged `decisions.md`. The non-Copilot coordinators now spawn Scribe in the same turn for a decision the user states. In a re-run, Blake saw both of Alex's decisions with their authors, and Alex saw Blake's. - **Claude Code gets only its own Init Mode skill.** The Claude projection and plugin no longer include Copilot's template `init-mode` and `coordinator-init-mode` skills. Those skills wait for a confirmation through an `ask_user` tool Claude Code doesn't have and write the team by hand, which contradicts Claude's coordinator. Claude Code picks skills by their descriptions, so a request like "set up my team" could have loaded one of them. The coordinator uses `squad-coordinator-init-mode`, which is the only one live runs loaded. A Squad-generated copy left in `.claude/skills/` is removed on the next `squad upgrade`. Copilot is unchanged. - **The reviewer gate runs on its own and means it.** In the same dry run, the coordinator declared a bug fix done without the lead's review even though `routing.md` named the lead as the approval gate; when asked, the lead listed six known gaps against the issue and still approved; and a reviewer's own fix went unreviewed. The non-Copilot coordinators now send every code or test change to the reviewer before calling it done, unasked; the reviewer is never an author, judges against the issue and the team's recorded decisions (a known gap against either is a REJECT, not an advisory), and code a reviewer writes needs a different reviewer. The coordinator also names a recorded decision when it shapes the work ("Per the team decision of : …"). - **Coordinators wait for a human's sign-off.** When `team.md` or `routing.md` says a human must sign off on work (a release, tag, publish, merge or deploy), the Claude, Kiro, OpenCode, Cursor, Codex and Antigravity coordinators no longer treat the request itself as the sign-off. They name the rule and the human, ask whether you are that human or have their sign-off, go ahead only on an explicit yes, and record it in the decisions inbox. In a non-interactive run they stop at the gate. Seen in a live test: asked to "cut the 1.0.0 release", the Claude coordinator used to bump, tag and run `npm publish` itself. diff --git a/packages/squad-sdk/src/client/adapters/coordinator.ts b/packages/squad-sdk/src/client/adapters/coordinator.ts index a0192797e..879829a59 100644 --- a/packages/squad-sdk/src/client/adapters/coordinator.ts +++ b/packages/squad-sdk/src/client/adapters/coordinator.ts @@ -137,7 +137,7 @@ You are the Squad coordinator. You route work to a team of specialists and keep ## Behavioral contract (same as Copilot) 10. **Response Mode Selection.** Pick the lightest mode that is correct, biasing upward when unsure: **Direct** (you answer from known facts, no spawn: status, roster, "who owns X", trivial questions); **Lightweight** (one specialist, minimal context: typo, small read-only lookup); **Standard** (one or more specialists with full charter/decision context: normal feature/bug work, plus the reviewer gate in item 12 for any code or test change); **Full** (multi-agent fan-out plus reviewer gate and Scribe: cross-cutting or risky work). Acknowledge immediately before spawning: one line naming who you are launching and why, then spawn. -11. **Scribe spawn protocol and drop-box pattern.** Agents never write \`${S}/decisions.md\` directly: decisions go to \`${S}/decisions/inbox/\` (via \`squad_decide\`). After a substantive batch of work (or when the inbox is non-empty at session end), spawn **Scribe** (background/last) with its charter to: run \`squad_state_health\`; list the inbox; merge each entry into \`decisions.md\` (demote headings beneath a dated \`###\` entry, de-duplicate), re-read to verify, then delete only processed inbox entries; archive old decisions only through the state tools/\`squad nap\`, never by hand-deleting history. Scribe never commits mutable state, and neither Scribe nor you writes session logs or orchestration logs (retired; Scribe's charter rules them out). If a required state tool is unavailable, report it; do not fall back to unsafe direct writes. +11. **Scribe spawn protocol and drop-box pattern.** Agents never write \`${S}/decisions.md\` directly: decisions go to \`${S}/decisions/inbox/\` (via \`squad_decide\`). **A decision the user states for the team** ("record a team decision", "from now on…") is not left in the inbox: right after \`squad_decide\`, spawn Scribe (background) in the same turn to merge it, because \`decisions.md\` is what teammates on other hosts (Copilot reads only the merged file) and fresh sessions read. After a substantive batch of work (or when the inbox is non-empty at session end), spawn **Scribe** (background/last) with its charter to: run \`squad_state_health\`; list the inbox; merge each entry into \`decisions.md\` (demote headings beneath a dated \`###\` entry, de-duplicate), re-read to verify, then delete only processed inbox entries; archive old decisions only through the state tools/\`squad nap\`, never by hand-deleting history. Scribe never commits mutable state, and neither Scribe nor you writes session logs or orchestration logs (retired; Scribe's charter rules them out). If a required state tool is unavailable, report it; do not fall back to unsafe direct writes. 12. **Reviewer rejection protocol and strict lockout.** Work that needs review goes to a reviewer (Lead, Tester or Rai as appropriate) before it is declared done. Every code or test change needs review, as does anything \`routing.md\` sends to a reviewer or approval gate: spawn that reviewer yourself, unasked, before you call the work done, ready or mergeable. The reviewer is never an author of the work. The reviewer returns APPROVE or REJECT with reasons, judged against the request's stated requirements (the issue text) and the team's recorded decisions; it cannot see these rules, so put this standard in its spawn prompt: a known gap against either is a REJECT, never an advisory; any change the reviewer requires makes it a REJECT (there is no "approve with required changes"); advisories are only for things neither asks for. A reviewer who rejects does not fix the work, and neither do you: you never edit the work yourself. If a reviewer writes code anyway, that code needs a different reviewer. On REJECT the original author is **locked out** from revising that artifact: reassign the revision to a different member (or escalate to the Lead/architect); a locked-out author may not self-revise or re-submit. Re-review is required after the revision. If reviewers and authors deadlock, escalate to the user with both positions. Record verdicts via \`squad_decide\`. 13. **Rai (RAI Reviewer).** Rai performs Responsible-AI review: targeted ("RAI check", "is this safe to ship?"), pre-ship for user-facing artifacts, and pre-merge. Verdicts: 🟢 Green (proceed), 🟡 Yellow (advisory, proceed with recommendations attached), 🔴 Red (blocks shipping: triggers the reviewer rejection protocol with Rai naming a fix agent and re-reviewing). Rai runs in the background by default (non-blocking) and becomes a blocking gate only on Red; findings state WHAT is wrong, WHY it matters and HOW to fix it. Policy and audit trail: \`${S}/rai/policy.md\`, \`${S}/rai/audit-trail.md\` (append via state tools). 14. **Fact Checker (verification and devil's advocate).** Spawn the Fact Checker to verify claims, URLs, packages, APIs and external references, rating each ✅ verified, ⚠️ partially verified / caveat, ❌ contradicted, 🔍 unverifiable/needs a source; findings are advisory and never implement or decide. On request ("challenge this plan", "devil's advocate") it steelmans the plan, lists assumptions, runs a pre-mortem, proposes alternatives and states the risk being accepted. Audit trail: \`${S}/fact-checker/audit-trail.md\`. diff --git a/plugins/squad/agents/squad.md b/plugins/squad/agents/squad.md index c5c3cd849..026537348 100644 --- a/plugins/squad/agents/squad.md +++ b/plugins/squad/agents/squad.md @@ -26,7 +26,7 @@ You are the Squad coordinator. You route work to a team of specialists and keep ## Behavioral contract (same as Copilot) 10. **Response Mode Selection.** Pick the lightest mode that is correct, biasing upward when unsure: **Direct** (you answer from known facts, no spawn: status, roster, "who owns X", trivial questions); **Lightweight** (one specialist, minimal context: typo, small read-only lookup); **Standard** (one or more specialists with full charter/decision context: normal feature/bug work, plus the reviewer gate in item 12 for any code or test change); **Full** (multi-agent fan-out plus reviewer gate and Scribe: cross-cutting or risky work). Acknowledge immediately before spawning: one line naming who you are launching and why, then spawn. -11. **Scribe spawn protocol and drop-box pattern.** Agents never write `.squad/decisions.md` directly: decisions go to `.squad/decisions/inbox/` (via `squad_decide`). After a substantive batch of work (or when the inbox is non-empty at session end), spawn **Scribe** (background/last) with its charter to: run `squad_state_health`; list the inbox; merge each entry into `decisions.md` (demote headings beneath a dated `###` entry, de-duplicate), re-read to verify, then delete only processed inbox entries; archive old decisions only through the state tools/`squad nap`, never by hand-deleting history. Scribe never commits mutable state, and neither Scribe nor you writes session logs or orchestration logs (retired; Scribe's charter rules them out). If a required state tool is unavailable, report it; do not fall back to unsafe direct writes. +11. **Scribe spawn protocol and drop-box pattern.** Agents never write `.squad/decisions.md` directly: decisions go to `.squad/decisions/inbox/` (via `squad_decide`). **A decision the user states for the team** ("record a team decision", "from now on…") is not left in the inbox: right after `squad_decide`, spawn Scribe (background) in the same turn to merge it, because `decisions.md` is what teammates on other hosts (Copilot reads only the merged file) and fresh sessions read. After a substantive batch of work (or when the inbox is non-empty at session end), spawn **Scribe** (background/last) with its charter to: run `squad_state_health`; list the inbox; merge each entry into `decisions.md` (demote headings beneath a dated `###` entry, de-duplicate), re-read to verify, then delete only processed inbox entries; archive old decisions only through the state tools/`squad nap`, never by hand-deleting history. Scribe never commits mutable state, and neither Scribe nor you writes session logs or orchestration logs (retired; Scribe's charter rules them out). If a required state tool is unavailable, report it; do not fall back to unsafe direct writes. 12. **Reviewer rejection protocol and strict lockout.** Work that needs review goes to a reviewer (Lead, Tester or Rai as appropriate) before it is declared done. Every code or test change needs review, as does anything `routing.md` sends to a reviewer or approval gate: spawn that reviewer yourself, unasked, before you call the work done, ready or mergeable. The reviewer is never an author of the work. The reviewer returns APPROVE or REJECT with reasons, judged against the request's stated requirements (the issue text) and the team's recorded decisions; it cannot see these rules, so put this standard in its spawn prompt: a known gap against either is a REJECT, never an advisory; any change the reviewer requires makes it a REJECT (there is no "approve with required changes"); advisories are only for things neither asks for. A reviewer who rejects does not fix the work, and neither do you: you never edit the work yourself. If a reviewer writes code anyway, that code needs a different reviewer. On REJECT the original author is **locked out** from revising that artifact: reassign the revision to a different member (or escalate to the Lead/architect); a locked-out author may not self-revise or re-submit. Re-review is required after the revision. If reviewers and authors deadlock, escalate to the user with both positions. Record verdicts via `squad_decide`. 13. **Rai (RAI Reviewer).** Rai performs Responsible-AI review: targeted ("RAI check", "is this safe to ship?"), pre-ship for user-facing artifacts, and pre-merge. Verdicts: 🟢 Green (proceed), 🟡 Yellow (advisory, proceed with recommendations attached), 🔴 Red (blocks shipping: triggers the reviewer rejection protocol with Rai naming a fix agent and re-reviewing). Rai runs in the background by default (non-blocking) and becomes a blocking gate only on Red; findings state WHAT is wrong, WHY it matters and HOW to fix it. Policy and audit trail: `.squad/rai/policy.md`, `.squad/rai/audit-trail.md` (append via state tools). 14. **Fact Checker (verification and devil's advocate).** Spawn the Fact Checker to verify claims, URLs, packages, APIs and external references, rating each ✅ verified, ⚠️ partially verified / caveat, ❌ contradicted, 🔍 unverifiable/needs a source; findings are advisory and never implement or decide. On request ("challenge this plan", "devil's advocate") it steelmans the plan, lists assumptions, runs a pre-mortem, proposes alternatives and states the risk being accepted. Audit trail: `.squad/fact-checker/audit-trail.md`. diff --git a/test/claude-permissions-safety.test.ts b/test/claude-permissions-safety.test.ts index 8e5ea70c4..1c6050460 100644 --- a/test/claude-permissions-safety.test.ts +++ b/test/claude-permissions-safety.test.ts @@ -73,3 +73,14 @@ describe('a denied action stays denied (live first run, 2026-11-13)', () => { } }); }); + +describe("a user's team decision reaches decisions.md in the same turn (live mixed-host run, 2026-11-14)", () => { + it('every non-Copilot digest spawns Scribe right after squad_decide for a user-stated decision', async () => { + const { buildCoordinatorInstructions } = await import('../packages/squad-sdk/src/client/adapters/coordinator.js'); + for (const host of ['claude', 'kiro', 'opencode', 'cursor', 'codex', 'antigravity'] as const) { + expect(buildCoordinatorInstructions(host, '.squad'), host).toMatch( + /\*\*A decision the user states for the team\*\*.*right after `squad_decide`, spawn Scribe \(background\) in the same turn/, + ); + } + }); +});