Skip to content

feat: Coordinator-as-Agent export — compile .squad/ into .github/agents/squad.md#1180

Open
bradygaster wants to merge 4 commits into
devfrom
feature/coordinator-as-agent
Open

feat: Coordinator-as-Agent export — compile .squad/ into .github/agents/squad.md#1180
bradygaster wants to merge 4 commits into
devfrom
feature/coordinator-as-agent

Conversation

@bradygaster

Copy link
Copy Markdown
Owner

Summary

Extends the squad export command family with a new coordinator agent export that compiles .squad/ state into a repository-native Copilot custom agent at .github/agents/squad.md.

This lets Squad teams export their roster, routing rules, ceremony triggers, and dispatch protocol into a format that works across all Copilot surfaces (CLI, VS Code, GitHub Desktop) without requiring runtime changes.

What's new

CLI

# New coordinator export
squad export agent
squad export agent --watch    # live re-export on .squad/ changes
squad export agent --check    # CI-friendly drift detection
squad export agent --dry-run  # preview without writing
squad export agent --compact  # force smaller output

# Existing snapshot export (unchanged)
squad export
squad export snapshot

Architecture

The export pipeline:

  1. Context loader — reads .squad/team.md, routing.md, ceremonies.md, config.json, and agent charters into a typed IR
  2. Prompt compiler — renders a coordinator prompt with token budget management (soft: 14k, hard: 20k)
  3. Frontmatter renderer — emits valid custom-agent YAML frontmatter
  4. File writer — writes .github/agents/squad.md with safety checks (collision detection, generated-file markers, legacy cleanup)

Token budget & compaction

  • Normal teams (≤8 members): full prompt mode
  • When over soft budget: automatic compact mode
  • Large teams (>8 members or >3k roster tokens): lazy-load mode (instructs coordinator to read charters at dispatch time)
  • Hard budget exceeded: fails with actionable diagnostics

Safety

  • Won't overwrite user-owned agent files unless --force
  • Detects legacy squad.agent.md collisions
  • Generated files are marked with a comment header for safe re-export
  • --check mode enables CI enforcement without mutation

Files

New

  • packages/squad-sdk/src/repo-native/ — types, IR loader, prompt compiler, frontmatter renderer, file writer, watch mode
  • packages/squad-cli/src/cli/commands/export-coordinator.ts — CLI entry point for agent export
  • test/repo-native/coordinator-export.test.ts — 15 tests covering the full pipeline

Modified

  • packages/squad-cli/src/cli/commands/export.ts — forked into a snapshot/agent router
  • packages/squad-cli/src/cli-entry.ts — updated help text and arg passing
  • packages/squad-sdk/src/index.ts — re-exports repo-native module
  • packages/squad-sdk/package.json — added ./repo-native subpath export

Testing

  • 15 new tests pass (IR parsing, prompt compilation, frontmatter, file writing, drift detection, collision handling)
  • All existing tests pass (zero regressions)
  • Tested end-to-end against Squad's own .squad/ directory — generates a valid coordinator for a 22-member team

Copilot AI review requested due to automatic review settings May 27, 2026 00:52

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

Note

Copilot was unable to run its full agentic suite in this review.

Adds a new “Coordinator-as-Agent” export mode that compiles .squad/ state into a repo-native Copilot custom agent at .github/agents/squad.md, including watch/check/dry-run safety features.

Changes:

  • Introduces a repo-native export pipeline in squad-sdk (IR loader, prompt compiler with token budget, YAML frontmatter renderer, file writer, watch mode).
  • Adds squad export agent CLI subcommand and routes squad export between snapshot (JSON) and coordinator (agent) exports.
  • Adds Vitest coverage for the coordinator export pipeline (context → prompt → frontmatter → write/check/legacy collision).
Show a summary per file
File Description
test/repo-native/coordinator-export.test.ts New end-to-end-ish tests for loading context, compiling prompts, rendering frontmatter, and writing/checking output.
packages/squad-sdk/src/repo-native/load-export-context.ts Loads .squad/ files into a typed IR, resolves skills/model/description, and summarizes charters.
packages/squad-sdk/src/repo-native/compile-coordinator-prompt.ts Builds coordinator prompt markdown with soft/hard token budgets and compaction modes.
packages/squad-sdk/src/repo-native/render-frontmatter.ts Renders Copilot custom-agent YAML frontmatter from coordinator metadata.
packages/squad-sdk/src/repo-native/write-coordinator-agent.ts Writes/checks the generated agent file with safety and legacy collision handling.
packages/squad-sdk/src/repo-native/watch-export.ts Implements --watch rebuild triggers for .squad/ (and skills) file changes.
packages/squad-sdk/src/repo-native/types.ts Adds repo-native export types and public API contracts.
packages/squad-sdk/src/repo-native/index.ts Exposes the repo-native export API.
packages/squad-sdk/src/index.ts Re-exports the repo-native module from the SDK top-level entry.
packages/squad-sdk/package.json Adds ./repo-native subpath export and updates package version.
packages/squad-cli/src/cli/commands/export.ts Routes squad export to either snapshot export or coordinator agent export.
packages/squad-cli/src/cli/commands/export-coordinator.ts New CLI entry point for generating .github/agents/squad.md (check/watch/dry-run/force/etc.).
packages/squad-cli/src/cli-entry.ts Updates help text and forwards args to the new export router.

Copilot's findings

  • Files reviewed: 13/13 changed files
  • Comments generated: 9

Comment on lines +250 to +253
const slug = row.name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');
const charterPath = row.charterPath || `.squad/agents/${slug}/charter.md`;
const charterFullPath = path.join(root, charterPath);
const charterContent = readIfExists(charterFullPath);
Comment on lines +14 to +15
lines.push(`name: ${coordinator.displayName}`);
lines.push(`description: "${escapeYamlString(coordinator.description)}"`);
Comment on lines +26 to +28
if (coordinator.model) {
lines.push(`model: ${coordinator.model}`);
}
Comment on lines +62 to +66
function renderDispatchRules(context: SquadExportContext): string {
const lines: string[] = [];

for (const rule of context.routing.rules) {
lines.push(`- If the request is mainly about ${rule.workType.toLowerCase()}, route to \`${rule.routeTo.toLowerCase()}\`.`);
Comment on lines +46 to +56
// Watch top-level squad files
for (const file of WATCH_PATTERNS) {
const filePath = path.join(squadRoot, file);
try {
const watcher = fs.watch(filePath, { persistent: true }, () => {
scheduleRebuild();
});
watchers.push(watcher);
} catch {
// File may not exist; that's fine
}
Comment on lines +63 to +65
const watcher = fs.watch(agentsDir, { recursive: true, persistent: true }, () => {
scheduleRebuild();
});
Comment on lines +80 to +84
if (cleanLegacyAgent) {
const backupPath = legacyPath + '.bak';
fs.renameSync(legacyPath, backupPath);
result.legacyCleaned = true;
}
Comment on lines +87 to +97
// Check mode: compare without writing
if (check) {
try {
const existing = fs.readFileSync(fullOutputPath, 'utf-8');
result.driftDetected = existing !== output;
} catch {
// File doesn't exist = drift
result.driftDetected = true;
}
return result;
}
* Start watching .squad/ source files for changes.
* Returns a cleanup function to stop watching.
*/
export function startWatchExport(options: WatchExportOptions): () => void {
bradygaster added a commit that referenced this pull request May 27, 2026
- Path traversal: validate charter paths stay within repo root
- YAML safety: quote all frontmatter scalar values to prevent injection
- Route resolution: resolve routeTo against team members by slug/name
- Watch mode: watch directories (not files) for creation/rename detection
- Cross-platform: replace recursive fs.watch with manual subdirectory enumeration
- Backup safety: use timestamped backup names to prevent data loss
- Check mode: distinguish user-owned files from drift with actionable errors
- Tests: add coverage for path safety, YAML escaping, watch behavior

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

Copy link
Copy Markdown
Owner Author

@copilot resolve the merge conflicts in this pull request

Copilot AI commented May 27, 2026

Copy link
Copy Markdown
Contributor

@copilot resolve the merge conflicts in this pull request

Resolved. I merged origin/main into this branch and fixed the conflicts in the affected files in commit ebcdef16.

@bradygaster

Copy link
Copy Markdown
Owner Author

@copilot you should have resolved the conflicts from dev, not from main

Copilot AI commented May 27, 2026

Copy link
Copy Markdown
Contributor

@copilot you should have resolved the conflicts from dev, not from main

Addressed in 54349e42 by reverting the previous merge from main. I also attempted to merge origin/dev, but this branch currently has no merge-base with origin/dev (Git reports unrelated histories). If you want, I can proceed with an --allow-unrelated-histories reconciliation, but it creates a very large full-repo conflict set.

bradygaster and others added 2 commits May 27, 2026 10:39
Extends the existing `squad export` command with a new `agent` branch
that compiles .squad/ state into a repository-native Copilot custom agent
at .github/agents/squad.md.

The export family now supports two modes:
- `squad export` / `squad export snapshot` — existing JSON snapshot (unchanged)
- `squad export agent` — new coordinator agent export

The coordinator export pipeline:
1. Reads .squad/team.md, routing.md, ceremonies.md, config.json, and agent charters
2. Parses into a typed intermediate representation (IR)
3. Compiles a coordinator prompt with token budget management
4. Renders YAML frontmatter + markdown body
5. Writes .github/agents/squad.md with safety checks

Features:
- Token budget with soft (14k) and hard (20k) limits
- Automatic compaction passes for large teams
- Lazy-load mode for teams > 8 members
- --check mode for CI drift detection
- --watch mode for live re-export on file changes
- --dry-run for preview without writing
- Legacy squad.agent.md collision detection
- Deterministic, regenerable output

New CLI flags for agent export:
  --out, --model, --description, --skills, --check, --watch,
  --dry-run, --force, --clean-legacy-agent, --max-prompt-tokens, --compact

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Path traversal: validate charter paths stay within repo root
- YAML safety: quote all frontmatter scalar values to prevent injection
- Route resolution: resolve routeTo against team members by slug/name
- Watch mode: watch directories (not files) for creation/rename detection
- Cross-platform: replace recursive fs.watch with manual subdirectory enumeration
- Backup safety: use timestamped backup names to prevent data loss
- Check mode: distinguish user-owned files from drift with actionable errors
- Tests: add coverage for path safety, YAML escaping, watch behavior

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@bradygaster bradygaster force-pushed the feature/coordinator-as-agent branch from 54349e4 to c1bcadf Compare May 27, 2026 17:40
bradygaster and others added 2 commits May 27, 2026 10:55
- Add changeset for coordinator-as-agent-export (minor for SDK + CLI)
- Remove 'coordinator' from user-facing help text (repl-ux-e2e test)
- Condense export help to stay within 130-line limit (speed-gates test)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
All code paths that write squad.agent.md now check for an existing
exported coordinator (squad.md with generated marker) first. If one
exists, squad.agent.md is skipped — the exported file supersedes it.

Previously only the export direction was guarded (export renames legacy
to .bak). This closes the reverse vectors: init, upgrade, and consult
could blindly write squad.agent.md alongside an already-exported
squad.md, causing a collision.

Vectors fixed:
- squad init: skips squad.agent.md when exported coordinator present
- squad upgrade: skips refresh when exported coordinator present
- squad consult: skips agent file creation when exported coordinator present

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

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

👋 Friendly nudge — this PR has had no activity for 11 days.

What needs attention:

  • 🔴 2 CI check(s) failing: Pre-publish dependency validation, Pre-publish dependency validation. Fix these first.
  • 💬 5 unresolved review thread(s) (5 from Copilot). Address and resolve them.
  • 👀 No approving reviews yet. Request a review from a teammate.

If this PR is abandoned, please close it. If it's blocked on something external, leave a comment so the team knows.
This is an automated check that runs on weekdays. It won't nudge the same PR more than once per week.

@tamirdresher tamirdresher left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Review summary

Read this PR end-to-end on a local checkout — architecture, file writer, prompt compiler, tests, end-to-end build. Code quality is strong but there are two concerns that need attention before merge.

✅ What's solid

  • Clean architecture. Typed IR (SquadExportContext) → loader → prompt compiler → frontmatter renderer → file writer. Each stage testable in isolation.
  • Token budget management. Three-tier degradation works correctly: full → compact → lazy-load → hard-fail with diagnostics. The diagnostics include top-5 largest sections and applied compactions, which is exactly what an author needs when hitting the cap.
  • Test coverage. 30 tests pass on the new code (25 for the export pipeline + 5 for agent-collision). All paths exercised: IR parsing, frontmatter, drift detection, collision handling, watch debouncing, large-team lazy-load.
  • Build clean. npm run build from this branch produces no errors, no new warnings.
  • Generated-file safety. <!-- generated by squad export: do not edit by hand --> marker + check for it before overwrite is the right pattern — won't clobber user-owned files unless --force.
  • Collision detection (#1212 followup). agent-collision.ts is exactly the right shape — checks for squad.md (exported) vs squad.agent.md (canonical) and prevents both from coexisting silently.

⚠️ Blocker 1 — Branch is stale; would revert recently-merged code

The branch was last updated 2026-05-27 and is now 13 commits behind dev. Three of those merged-after-this-PR commits change the same files this PR touches:

Change on dev Files Risk
#1251 (memory MCP fix, merged 2026-06-11) init.ts, upgrade.ts Removes ensureSquadStateMcpInUserConfig imports/calls. Without those, agents won't get governed memory tools at user-MCP scope — defeats the whole MCP-fix work.
#1262 (@copilot init prompt, merged 2026-06-11) init.ts Removes readTeamMd/writeTeamMd/hasCopilot/insertCopilotSection imports + the @copilot prompt code. UX regression.
#1222 (Rai + Fact Checker auto-scaffold, merged earlier) init.ts Removes the fact-checker roster entry that squad upgrade auto-scaffolds.

If merged as-is via squash or 3-way merge, GitHub's auto-resolver will likely produce a working tree that's missing those imports → build will fail OR ship a regression silently.

Action: rebase onto current dev (or merge dev in), resolve the conflicts (keep the dev side — those PRs are now canonical), re-run tests, force-push.

⚠️ Blocker 2 — --clean-legacy-agent flag renames .github/agents/squad.agent.md

The flag, when invoked, renames .github/agents/squad.agent.md to .bak.{timestamp} (write-coordinator-agent.ts:79-89).

This file is the canonical Coordinator source. It's the authoritative governance file that defines coordinator behavior, ships in the repo as documented at the top of squad.agent.md itself ("Source of Truth Hierarchy"), and is committed to every Squad-enabled repo. Renaming it removes the source of truth for the entire coordinator system.

The intent of the flag — "you exported the new squad.md and you don't need the legacy one anymore" — is reasonable, but the implementation is dangerous:

  1. The flag treats the legacy file as obsolete, but the new squad.md is a compiled artifact of the legacy squad.agent.md (plus team config). The source can't be removed once the artifact exists.
  2. If a user runs --clean-legacy-agent, then later runs squad upgrade (which re-writes squad.agent.md), they'd hit the collision detection from agent-collision.ts and be confused why two files now exist.
  3. Cleanly removing the legacy file should be a separate, explicit migration command (e.g., squad migrate-to-exported-coordinator) with strong warnings, not a flag on the export command.

Action: Recommend removing --clean-legacy-agent from this PR. Track it as a separate "migration to exported coordinator" concern that needs its own design + warnings + tests.

💡 Minor (non-blocking) observations

  1. Doc gap. squad.md vs squad.agent.md will confuse users. Worth a short doc explaining: squad.agent.md is the runtime source of truth, squad.md is an exported compiled artifact for cross-surface compatibility.

  2. buildMcpServerSpecs integration question. The exported squad.md doesn't mention MCP tools — but a coordinator on Copilot CLI without the user-MCP setup (#1251) would silently degrade. Should the export include a "you need squad init first" guardrail in the generated agent's frontmatter or preamble?

  3. renderFrontmatter skill list--skills baseline is the default but I didn't see what "baseline" resolves to. A quick comment in the docstring would help.

  4. Watch mode is debounced (good!) but startWatchExport doesn't expose a stop mechanism — await new Promise(() => {}) keeps the process alive forever. Fine for CLI usage but if SDK consumers wrap this, they'd be stuck. Minor — file an issue for follow-up if needed.

Recommendation

Not approving yet — please rebase to resolve Blocker 1, and either remove --clean-legacy-agent or add explicit guarantees that it cannot touch .github/agents/squad.agent.md.

After both are addressed, the architecture and test coverage are strong enough for a quick re-review and approve.

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.

4 participants