Skip to content

fix(sdk): plumb Fact Checker like Rai — rich charter at init + .squad/fact-checker/ state dir (#1299 deep)#1301

Merged
tamirdresher merged 2 commits into
bradygaster:devfrom
tamirdresher:squad/fact-checker-full-plumbing
Jun 13, 2026
Merged

fix(sdk): plumb Fact Checker like Rai — rich charter at init + .squad/fact-checker/ state dir (#1299 deep)#1301
tamirdresher merged 2 commits into
bradygaster:devfrom
tamirdresher:squad/fact-checker-full-plumbing

Conversation

@tamirdresher

Copy link
Copy Markdown
Collaborator

"@bradygaster/squad-cli": minor
"@bradygaster/squad-sdk": minor

Fix #1299 (deep): Fact Checker gets the same plumbing as Rai — rich charter at init + state directory + policy template

PR #1300 (also #1299) fixed the documentation gap so the coordinator knows to roster Fact Checker. This PR fixes the structural gap behind it. Per user testing on 2026-06-13, even after #1300 the actual agent on disk is still a "name on disk with a 21-line placeholder" — three concrete problems:

Piece Rai before this PR Fact Checker before this PR
charter.md at init Generic 478-byte stub from generateCharter() Generic 523-byte stub from generateCharter()
Rich charter template usage Only used by squad upgrade (never by squad init) Same — never used by squad init
.squad/{name}/policy.md ✅ Seeded from rai-policy.md (4160 bytes) ❌ Directory does not exist
.squad/{name}/audit-trail.md ✅ Seeded with append-only header ❌ Directory does not exist
merge=union in .gitattributes .squad/rai/audit-trail.md ❌ No entry for fact-checker
fact-checker-charter.md distribution n/a Only in packages/squad-cli/templates/ — missing from .squad-templates/ (canonical source) AND packages/squad-sdk/templates/, so the SDK init path could never find it

Fix (4 parts)

Part 1 — Rich charter at init (benefits BOTH Rai and Fact Checker)

packages/squad-sdk/src/config/init.ts agent loop now looks up {templatesDir}/{role}-charter.md for each agent and uses that as charter.md content if it exists. Falls back to generateCharter() for user-defined agents that have no rich template (everyone except the built-ins).

Result: a fresh squad init produces .squad/agents/Rai/charter.md with the full Rai charter (4525 bytes) and .squad/agents/fact-checker/charter.md with the full Fact Checker charter (3024 bytes). Previously both were 478-byte stubs.

Part 2 — .squad/fact-checker/ state dir, mirroring .squad/rai/

Added a new block in init.ts (right after the Rai seeding at lines 879–941) that creates:

  • .squad/fact-checker/policy.md — seeded from templates/fact-checker-policy.md (or a minimal inline fallback if the template is stripped)
  • .squad/fact-checker/audit-trail.md — seeded with an append-only header

The policy template (.squad-templates/fact-checker-policy.md, ~6 KB) is the canonical authority for the dual-mode operating rules per #789 + #1254:

  • Mode 1 Verification: confidence rating taxonomy (✅/⚠️/❌/🔍), what gets checked (URLs, packages, APIs, file paths, signatures, quotes, statistics, cross-references)
  • Mode 2 Devil's Advocate: required brief structure (steelman → assumptions → pre-mortem → alternatives → risk acceptance)
  • Hard rules: anti-fabrication guarantees — never cite unverified URL/package/API, never invent measurement data, never fabricate counter-hypotheses, never block on opinion
  • Advisory by default with two narrow blocking exceptions (❌ at Pre-Ship; coordinator-escalated DA risk)
  • Opt-out model mirroring Rai's
  • Audit trail rules — succinct (verdict + citation, never raw source material)
  • Reviewer Rejection Protocol integration for ❌ Contradicted verdicts

Part 3 — Fix the .squad-templates/ distribution gap

The existing fact-checker-charter.md had been added directly to packages/squad-cli/templates/ only, bypassing the canonical .squad-templates/ source. That meant sync-templates.mjs couldn't propagate it to packages/squad-sdk/templates/ (which getSDKTemplatesDir() resolves at runtime), so the SDK init code path could never find the rich charter even if it tried.

Fix: copied fact-checker-charter.md to .squad-templates/ and re-synced. Now all 4 mirror targets have it. This unblocks Part 1.

Part 4 — Plumbing updates

  • .gitattributes block: added .squad/fact-checker/audit-trail.md merge=union alongside Rai's existing entry
  • packages/squad-cli/src/cli/core/templates.ts: new TEMPLATE_MANIFEST entry for fact-checker-policy.md → templates/fact-checker-policy.md so squad upgrade propagates it
  • .squad-templates/squad.agent.md Files Catalog table: 2 new rows for .squad/fact-checker/policy.md (authoritative) and .squad/fact-checker/audit-trail.md (derived/append-only)

Tests

test/init.test.ts gains 3 regression tests (28/28 pass total):

  1. should seed .squad/fact-checker/{policy,audit-trail}.md (regression: bradygaster/squad#1299) — asserts policy declares both modes + anti-fabrication rules + confidence ratings; audit trail is append-only.
  2. should use the rich fact-checker-charter.md template for built-in agents at init (#1299) — asserts the rendered charter is > 1 KB (not the 478-byte stub) and contains Verification Methodology + Confidence Ratings.
  3. should use the rich Rai-charter.md template at init (companion to fact-checker fix, #1299) — asserts Rai gets the same treatment; charter references .squad/rai/policy.md and .squad/rai/audit-trail.md.

npm run lint clean.

Composability

This PR builds on #1300 (which adds the ## Fact Checker section to squad.agent.md and the "team size" line fix). Both modify .squad-templates/squad.agent.md but in disjoint regions:

They will merge cleanly in either order. The user-facing experience requires BOTH to land for full plumbing.

Closes / refs

Closes #1299 (deep fix; #1300 was the surface fix).

…/fact-checker/ state dir (bradygaster#1299 deep)

PR bradygaster#1300 fixed the documentation gap so the coordinator knows to roster
Fact Checker. This PR fixes the structural gap behind it. Per user
testing 2026-06-13: even after bradygaster#1300 the actual agent on disk was still
"a name on disk with a 21-line placeholder".

Three structural problems:

1. squad init never used the rich {role}-charter.md templates. Both Rai
   and fact-checker got 478-byte generic stubs from generateCharter().
   Rich templates only ran via squad upgrade's ensureBuiltinAgents path.

2. fact-checker had no state dir. Rai gets .squad/rai/{policy.md,
   audit-trail.md} via init.ts lines 879-941. fact-checker had nothing
   equivalent.

3. fact-checker-charter.md was only in packages/squad-cli/templates/ —
   missing from .squad-templates/ (canonical source) AND packages/
   squad-sdk/templates/. SDK init's getSDKTemplatesDir() resolves to the
   SDK templates dir, so even if init tried to read the rich charter,
   the file wasn't there.

Fix (4 parts):

Part 1 - Rich charter at init (benefits BOTH Rai and fact-checker):
* SDK init.ts agent loop now looks up {templatesDir}/{role}-charter.md
  for each agent and uses that as charter.md content if it exists. Falls
  back to generateCharter() for user-defined agents.
* Result: fresh squad init produces .squad/agents/Rai/charter.md at
  4525 bytes (full Rai charter) and fact-checker/charter.md at 3024
  bytes (full FC charter). Previously both were 478-byte stubs.

Part 2 - .squad/fact-checker/ state dir mirroring .squad/rai/:
* New block in init.ts (right after the Rai seeding) creates
  .squad/fact-checker/policy.md (from templates/fact-checker-policy.md
  or inline fallback) and audit-trail.md.
* New .squad-templates/fact-checker-policy.md (~6KB) is the canonical
  authority for dual-mode operating rules per bradygaster#789 + bradygaster#1254:
  - Mode 1 Verification: ✅/⚠️/❌/🔍 confidence rating taxonomy
  - Mode 2 Devil's Advocate: required brief structure
  - Hard anti-fabrication rules
  - Advisory by default with narrow blocking exceptions
  - Audit trail rules (succinct, never raw source)

Part 3 - Fix .squad-templates/ distribution gap:
* Copied fact-checker-charter.md into .squad-templates/ so
  sync-templates.mjs propagates it to all 4 mirror targets including
  packages/squad-sdk/templates/. This unblocks Part 1.

Part 4 - Plumbing:
* .gitattributes: .squad/fact-checker/audit-trail.md merge=union
* TEMPLATE_MANIFEST: fact-checker-policy.md
* squad.agent.md Files Catalog: 2 new rows for FC state files

Tests: 3 new regression tests in test/init.test.ts (28/28 pass total).
npm run lint clean.

Composability: This PR builds on bradygaster#1300 (which adds the ## Fact Checker
section to squad.agent.md and the team-size line fix). Both PRs modify
squad.agent.md in disjoint regions and merge in either order. Full
plumbing requires BOTH to land.

Closes bradygaster#1299 (deep fix; bradygaster#1300 was the surface fix)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings June 13, 2026 10:23
@github-actions

github-actions Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

🏗️ Architectural Review

⚠️ Architectural review: 1 warning(s).

Severity Category Finding Files
🟡 warning bootstrap-area 1 file(s) in the bootstrap area (packages/squad-cli/src/cli/core/) were modified. These files must maintain zero external dependencies. Review carefully. packages/squad-cli/src/cli/core/templates.ts

Automated architectural review — informational only.

@github-actions

github-actions Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

🛫 PR Readiness Check

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

PR Scope: 📦🔧 Mixed (product + infrastructure)

⚠️ 4 item(s) to address before review

Status Check Details
Single commit 2 commits — consider squashing before review
Not in draft Ready for review
Branch up to date Up to date with dev
Copilot review No Copilot review yet — it may still be processing
Changeset present Changeset file found
Scope clean No .squad/ or docs/proposals/ files
No merge conflicts No merge conflicts
Copilot threads resolved 1 unresolved Copilot thread(s) — fix and resolve before merging
CI passing 8 check(s) still running

Files Changed (16 files, +959 −1)

File +/−
.changeset/fix-1299-fact-checker-full-plumbing.md +77 −0
.github/agents/squad.agent.md +2 −0
.squad-templates/fact-checker-charter.md +83 −0
.squad-templates/fact-checker-policy.md +104 −0
.squad-templates/squad.agent.md +2 −0
packages/squad-cli/src/cli/core/templates.ts +6 −0
packages/squad-cli/templates/fact-checker-policy.md +104 −0
packages/squad-cli/templates/squad.agent.md.template +2 −0
packages/squad-sdk/src/config/init.ts +109 −1
packages/squad-sdk/templates/fact-checker-charter.md +83 −0
packages/squad-sdk/templates/fact-checker-policy.md +104 −0
packages/squad-sdk/templates/squad.agent.md.template +2 −0
templates/fact-checker-charter.md +83 −0
templates/fact-checker-policy.md +104 −0
templates/squad.agent.md.template +2 −0
test/init.test.ts +92 −0

Total: +959 −1


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

@github-actions

github-actions Bot commented Jun 13, 2026

Copy link
Copy Markdown
Contributor

🟠 Impact Analysis — PR #1301

Risk tier: 🟠 HIGH

📊 Summary

Metric Count
Files changed 16
Files added 8
Files modified 8
Files deleted 0
Modules touched 6

🎯 Risk Factors

  • 16 files changed (6-20 → MEDIUM)
  • 6 modules touched (5-8 → HIGH)

📦 Modules Affected

ci-workflows (1 file)
  • .github/agents/squad.agent.md
root (4 files)
  • .changeset/fix-1299-fact-checker-full-plumbing.md
  • templates/fact-checker-charter.md
  • templates/fact-checker-policy.md
  • templates/squad.agent.md.template
squad-cli (3 files)
  • packages/squad-cli/src/cli/core/templates.ts
  • packages/squad-cli/templates/fact-checker-policy.md
  • packages/squad-cli/templates/squad.agent.md.template
squad-sdk (4 files)
  • packages/squad-sdk/src/config/init.ts
  • packages/squad-sdk/templates/fact-checker-charter.md
  • packages/squad-sdk/templates/fact-checker-policy.md
  • packages/squad-sdk/templates/squad.agent.md.template
templates (3 files)
  • .squad-templates/fact-checker-charter.md
  • .squad-templates/fact-checker-policy.md
  • .squad-templates/squad.agent.md
tests (1 file)
  • test/init.test.ts

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

tamirdresher pushed a commit to tamirdresher/squad that referenced this pull request Jun 13, 2026
…t init + state dir)

# Conflicts:
#	test/init.test.ts

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR closes the “deep” plumbing gap for the built-in Fact Checker by ensuring squad init seeds rich built-in charters (instead of generic stubs) and creates a dedicated .squad/fact-checker/ state directory (policy + append-only audit trail), mirroring Rai’s structure. It also adds the new Fact Checker policy template to the canonical template source and propagates it through the CLI/SDK template mirrors, with regression tests.

Changes:

  • Update SDK init to (a) seed .squad/fact-checker/{policy,audit-trail}.md and (b) prefer shipped *-charter.md templates when creating agent charter.md.
  • Add new Fact Checker policy and charter templates to .squad-templates/ and mirror them into templates/ + both package template directories.
  • Extend CLI template manifest and add SDK init regression tests for the new seeding/template behavior.

Reviewed changes

Copilot reviewed 15 out of 15 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
packages/squad-sdk/src/config/init.ts Seeds .squad/fact-checker/ files and attempts to load rich *-charter.md templates during init.
test/init.test.ts Adds regressions covering Fact Checker state-dir seeding and rich charter usage for Fact Checker + Rai.
.squad-templates/fact-checker-policy.md Canonical Fact Checker policy template (verification + Devil’s Advocate rules).
.squad-templates/fact-checker-charter.md Canonical Fact Checker charter template.
.squad-templates/squad.agent.md Adds Fact Checker state-dir rows to the Files Catalog table.
templates/fact-checker-policy.md Mirrored Fact Checker policy template (root templates).
templates/fact-checker-charter.md Mirrored Fact Checker charter template (root templates).
templates/squad.agent.md.template Mirrored coordinator template update (Files Catalog rows).
packages/squad-cli/templates/fact-checker-policy.md Mirrored CLI policy template.
packages/squad-cli/templates/squad.agent.md.template Mirrored CLI coordinator template update (Files Catalog rows).
packages/squad-cli/src/cli/core/templates.ts Adds fact-checker-policy.md to the upgrade/init template manifest.
packages/squad-sdk/templates/fact-checker-policy.md Mirrored SDK policy template.
packages/squad-sdk/templates/fact-checker-charter.md Mirrored SDK charter template.
packages/squad-sdk/templates/squad.agent.md.template Mirrored SDK coordinator template update (Files Catalog rows).
.changeset/fix-1299-fact-checker-full-plumbing.md Changeset documenting the SDK/CLI minor changes for this plumbing fix.

Comment thread packages/squad-sdk/src/config/init.ts Outdated
Comment on lines +1121 to +1124
const candidates = [
join(templatesDir, `${agent.role}-charter.md`),
join(templatesDir, `${agent.name}-charter.md`),
];
Comment on lines +712 to +713
| `.squad/fact-checker/policy.md` | **Authoritative verification + Devil's Advocate policy.** Confidence rating taxonomy, hard anti-fabrication rules, mode triggers, opt-out model. | Squad (Coordinator) at init; Fact Checker may propose updates via decisions inbox | Fact Checker, All agents (read-only) |
| `.squad/fact-checker/audit-trail.md` | **Derived / append-only.** Verification verdicts + DA brief evidence log. Succinct — verdict + citation, never raw source material. | Fact Checker (append only) | Fact Checker, Squad (Coordinator) |
….github/agents

Two reviewer follow-ups on bradygaster#1301 (bradygaster#1299 deep):

1. Case-sensitive FS bug in rich-charter lookup
   The lookup tried '\-charter.md' and '\-charter.md'
   only. For Rai (role='Rai', name='Rai') this becomes 'Rai-charter.md', but
   the actual file shipped lowercase ('rai-charter.md'). On Windows the lookup
   succeeded because the filesystem is case-insensitive; on Linux CI it silently
   missed and fell back to the 478-byte generic stub — exactly the regression
   bradygaster#1299 was trying to fix. Reproduced by 'should use the rich Rai-charter.md
   template at init' failing with 'expected 476 to be greater than 1000' on
   GitHub Actions.

   Add toLowerCase() candidates after the exact-case ones. De-dupe via a Set
   so we don't double-stat when role and name are already lowercase
   (fact-checker case). Guard each candidate against blank keys.

2. Template-sync parity
   The canonical .squad-templates/squad.agent.md gained two Fact Checker rows
   in the Files Catalog but the mirrored .github/agents/squad.agent.md copy
   was never re-synced, so the template-sync.test.ts byte-for-byte parity
   check would have fired. Run 'node scripts/sync-templates.mjs --sync' to
   regenerate.

Verified: vitest 'rich Rai-charter' passes locally after the fix
(previously failing on Linux CI run 27464079078).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
tamirdresher added a commit to tamirdresher/squad that referenced this pull request Jun 13, 2026
…rrect on-demand reference path

Reviewer follow-ups on bradygaster#1300:

1. Team-size phrasing — the line read 'typically 4-5 + Scribe + Ralph +
   Rai + Fact Checker' which a model could parse as arithmetic
   (4-5 + 4 = 8-9, but it could also collapse). Rewrote it to make the
   composition explicit: '4-5 cast (user-domain) agents + 4 always-on
   built-ins = 8-9 total roster entries'.

2. Cast-exemption parity — Scribe, Ralph, and Rai each have an
   explicit 'exempt from casting' bullet but Fact Checker did not.
   Added the matching bullet right after Rai's.

3. Bad on-demand reference path — the FC section pointed at
   '.squad/templates/fact-checker-charter.md'. That file IS shipped
   (TEMPLATE_MANIFEST destination 'templates/fact-checker-charter.md')
   but only AFTER 'squad init' or 'squad upgrade' has populated
   .squad/templates/. A reader of squad.agent.md on an
   un-initialized repo (or in .github/agents/ on the cloud agent
   surface) would follow a dead link. Repointed to the
   '.squad/agents/fact-checker/charter.md' instance that
   ensureBuiltinAgents creates as part of the same init/upgrade
   path — that's where the rich charter actually lives at runtime
   per bradygaster#1299 + bradygaster#1301.

All 4 mirrored copies re-synced via scripts/sync-templates.mjs.
fact-checker-role.test.ts: 8/8 pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@tamirdresher

Copy link
Copy Markdown
Collaborator Author

All 3 reviewer threads + the CI failure addressed in commit aec6426:

  • Rich-charter case-sensitivity bug (CI failure root cause) — added agent.role.toLowerCase() / agent.name.toLowerCase() candidates to the lookup list. The shipped file is rai-charter.md (lowercase) but role=Rai (mixed case); on Windows the lookup succeeded because the FS is case-insensitive, on Linux CI it silently fell back to the 478-byte generic stub — exactly the Coordinator's first-time cast omits Fact Checker from team.md ## Members even though .squad/agents/fact-checker/ exists #1299 regression. The Rai test now passes (previously expected >1000, got 476).
  • Template-sync parity — re-synced .github/agents/squad.agent.md from .squad-templates/squad.agent.md (the FC Files Catalog rows hadn't propagated to the mirror).
  • De-dup + null safety — Set-based dedupe so role/name being lowercase already (fact-checker case) doesn't double-stat; skip blank keys.

Linux CI test/init.test.ts should now show 28/28 ✓.

@bradygaster bradygaster left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

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

✅ Flight approves. Fact Checker is now plumbed structurally like Rai, including init templates and durable state wiring.

tamirdresher added a commit that referenced this pull request Jun 13, 2026
…#1299) (#1300)

* fix(docs): tell coordinator to roster Fact Checker on first-time cast (#1299)

squad init correctly creates .squad/agents/fact-checker/ on disk (per
merged PR #1223). But when the user opens copilot --agent squad and the
coordinator runs first-time casting, it OMITS Fact Checker from the
team.md ## Members table while including Scribe, Ralph, and Rai.

Root cause: .squad-templates/squad.agent.md had two gaps:
1. Line 56 said "team size (typically 4-5 + Scribe)" — naming only Scribe
2. Rai had a dedicated ## Rai section with explicit "Rai always appears
   in team.md" instruction — Fact Checker had no equivalent section

So the model added Rai (because instructed to) but had no instruction to
add Fact Checker, even though the agent dir was scaffolded on disk.

Fix:
* Update team-size line to name all 4 always-on built-ins: Scribe + Ralph
  + Rai + Fact Checker
* Add full ## Fact Checker — Verification & Devil's Advocate section
  mirroring the Rai pattern: roster-entry instruction, dual operating
  mode (per #789 + #1254), trigger phrase table, confidence ratings, DA
  brief structure, boundaries, state location

Sync via sync-templates.mjs --sync propagates squad.agent.md changes to
all 4 mirror targets: .squad-templates/, templates/, packages/squad-cli/
templates/, packages/squad-sdk/templates/, .github/agents/.

Tests: new test/squad-agent-roster.test.ts runs against all 4 template
targets and asserts:
* The "Determine team size" line names all 4 built-ins
* A ## Fact Checker section exists with "always appears in team.md"
* The section declares dual operating mode (anchors #789 + #1254 design
  so a future PR can't accidentally split Fact Checker and Devil's
  Advocate again — cf. closed PR #1294)
* Existing Ralph + Rai sections still present
16/16 pass.

Closes #1299

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* doc(squad.agent.md): clarify Fact Checker is exempt from casting + correct on-demand reference path

Reviewer follow-ups on #1300:

1. Team-size phrasing — the line read 'typically 4-5 + Scribe + Ralph +
   Rai + Fact Checker' which a model could parse as arithmetic
   (4-5 + 4 = 8-9, but it could also collapse). Rewrote it to make the
   composition explicit: '4-5 cast (user-domain) agents + 4 always-on
   built-ins = 8-9 total roster entries'.

2. Cast-exemption parity — Scribe, Ralph, and Rai each have an
   explicit 'exempt from casting' bullet but Fact Checker did not.
   Added the matching bullet right after Rai's.

3. Bad on-demand reference path — the FC section pointed at
   '.squad/templates/fact-checker-charter.md'. That file IS shipped
   (TEMPLATE_MANIFEST destination 'templates/fact-checker-charter.md')
   but only AFTER 'squad init' or 'squad upgrade' has populated
   .squad/templates/. A reader of squad.agent.md on an
   un-initialized repo (or in .github/agents/ on the cloud agent
   surface) would follow a dead link. Repointed to the
   '.squad/agents/fact-checker/charter.md' instance that
   ensureBuiltinAgents creates as part of the same init/upgrade
   path — that's where the rich charter actually lives at runtime
   per #1299 + #1301.

All 4 mirrored copies re-synced via scripts/sync-templates.mjs.
fact-checker-role.test.ts: 8/8 pass.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Copilot <Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Tamir Dresher <tamirdresher@users.noreply.github.com>
@tamirdresher tamirdresher merged commit 16c6b25 into bradygaster:dev Jun 13, 2026
14 checks passed
tamirdresher added a commit that referenced this pull request Jun 13, 2026
…ough the cross-squad skill (#1307)

* fix(coordinator): route "spawn a squad" / "another squad" prompts through the cross-squad skill

A coordinator initialised by `squad init` saw prompts like "spawn two
squads of designers and devs" and fanned out raw `task` agents inside
its own context, treating "squad" as generic English for "team / group".
It never invoked the bundled `cross-squad` or `cross-squad-communication`
skills, so the peer-squad delegation protocol (registry / manifest / sync
CLI / git-async / GH-issue patterns) was bypassed entirely.

Two structural holes in squad.agent.md allowed this:

  1. The Routing table had no row mapping "spawn a squad" phrasing to the
     Squad-PRODUCT concept (only "upgrade squad" / "squad commands" rows
     covered Squad-as-a-product vocabulary).
  2. The Skill-aware-routing block was process discipline ("check skill
     directories by domain relevance") with no hard "if the user's word
     matches a skill name, MUST load the skill" trigger.

This fix:

  - Adds a new routing-table row for the squad-spawning vocabulary
    ("spawn a squad", "another squad", "two squads", "second squad",
    "fan out to squads", "delegate to a squad"). Action: invoke the
    skill tool on cross-squad AND cross-squad-communication BEFORE any
    task spawn, then delegate via Pattern 0/1/2/3.

  - Adds a "Hard trigger — keyword-to-skill match" paragraph at the top
    of the Skill-aware-routing block. If any word in the user's request
    matches an installed skill name (squad → cross-squad, reflect →
    reflect, ceremony → matching ceremony skill, fact-check →
    fact-checking, release → release-process), the coordinator MUST
    invoke the skill tool to fully load that skill before designing its
    approach. Includes a "failure mode this rule closes" pointer so the
    guard survives future paraphrasing.

  - Strengthens cross-squad/SKILL.md with a Read-this-FIRST callout
    above the existing Context paragraph, so even a coordinator that
    skips the routing-table row still hits the trigger when it does
    eventually load the skill.

  - Adds a regression test (template-sync.test.ts) that asserts the row
    + the hard-trigger paragraph + the worked example are present in
    every mirrored copy of squad.agent.md (5 locations).

All 4 mirrors re-synced via `scripts/sync-templates.mjs --sync`.
Verified: 223/223 template-sync tests pass.

Composability: disjoint from #1292/#1293/#1295/#1298/#1300/#1301/#1302/
#1303/#1304/#1306 — only touches squad.agent.md mirrors + cross-squad/
SKILL.md + the template-sync test.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

* fix(coordinator): strengthen squad-spawn disambiguation — ask_user on ambiguity + anti-patterns

Real-world failure (2026-06-13): even AFTER the routing-table row and
hard-trigger paragraph from b5d05fb landed, a peer-squad coordinator
*still* did ad-hoc `task` fan-out for "spawn two squads of engineers
and QAs". Self-diagnosis surfaced four contributing failure modes:

  1. Prior-session anchoring (saw earlier `reviews/squad-alpha/` folders
     and matched the pattern without re-evaluating user intent).
  2. Ambiguous wording, lazy interpretation (silently picked the
     cheaper option instead of asking).
  3. Coordinator doctrine biases toward `task` fan-out (the existing
     Eager Execution / Parallel Fan-Out section pulled the coordinator
     back even after it had loaded `cross-squad`).
  4. Cost/overhead instinct ("two real squads for a 30-line app feels
     disproportionate" — judged silently instead of surfacing the
     trade-off).

The original PR #1307 fix closed modes 1 and 3 mechanically (forces
the skill to load) but left modes 2 and 4 open (didn't dictate what
to DO with that knowledge). This commit closes them:

A. squad.agent.md routing row — added two explicit clauses:
   - "**Default = literal Squad install.** Calling `task` sub-agents
     'squad-alpha' / 'squad-beta' does NOT make them squads — that is
     the explicit anti-pattern."
   - "**If the request is ambiguous** ... you MUST `ask_user` with a
     2-choice prompt — and never silently pick the cheaper option."
   No escape hatch. The coordinator can no longer rationalise the
   downgrade as a judgment call.

B. cross-squad/SKILL.md — added a full `## Disambiguation: 'squad' vs
   ad-hoc agents` section with:
   - Default-behaviour table mapping common phrasings to expected
     coordinator actions (real squads vs ad-hoc agents vs ambiguous).
   - ask_user 2-choice protocol verbatim (heavier/persistent vs
     lighter/ephemeral) so the coordinator has the exact prompt shape.
   - Four named anti-patterns drawn directly from the observed failure:
     * Naming task agents "squad-alpha" doesn't make them squads
     * Prior-session anchoring (pattern is a hint, not a contract)
     * Silent cheaper-option pick (judgment call belongs to the user)
     * Loading the skill but doing task fan-out anyway (disambiguation
       rule OVERRIDES generic fan-out doctrine when "squad" was the
       trigger)
   - Sharpened `description:` so the squad skill-aware-router has
     better natural-language hooks.
   - `triggers:` frontmatter array (Copilot CLI ignores `triggers:` per
     sdk/index.js decompile, but the squad coordinator's skill-aware
     routing system uses natural-language matching against frontmatter
     + content, so documenting the phrases here helps that matcher fire).

C. Regression tests in test/template-sync.test.ts:
   - Routing row must mention `ask_user` + "anti-pattern" (new × 5
     mirrors = 5 assertions).
   - cross-squad/SKILL.md must have `## Disambiguation` section,
     default-behaviour rule, ask_user requirement, the squad-alpha
     anti-pattern, and triggers: frontmatter (5 new × 3 mirrors = 15
     assertions).
   - 20 new assertions total; 243/243 template-sync tests pass.

cross-squad/SKILL.md mirrored to packages/squad-cli/templates/skills/
and packages/squad-sdk/templates/skills/ (byte-identical). squad.agent.md
re-synced to all 4 mirrors via scripts/sync-templates.mjs.

Composability: still disjoint from all other open PRs. Pure additions
to two files (squad.agent.md row, cross-squad/SKILL.md content) plus
mirrors + tests.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>

---------

Co-authored-by: Tamir Dresher <tamirdresher@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Coordinator's first-time cast omits Fact Checker from team.md ## Members even though .squad/agents/fact-checker/ exists

3 participants