diff --git a/.changeset/add-rework-rate-metric.md b/.changeset/add-rework-rate-metric.md deleted file mode 100644 index 20d83e64c..000000000 --- a/.changeset/add-rework-rate-metric.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@bradygaster/squad-sdk": minor ---- - -Add rework rate OTEL metrics (#265) — tracks PR revision patterns as the emerging 5th DORA metric diff --git a/.changeset/add-session-recovery-skill.md b/.changeset/add-session-recovery-skill.md deleted file mode 100644 index 53d80c9c1..000000000 --- a/.changeset/add-session-recovery-skill.md +++ /dev/null @@ -1,4 +0,0 @@ ---- ---- - -Add session-recovery skill for detecting and resuming interrupted Copilot CLI sessions diff --git a/.changeset/add-skill-script-loader.md b/.changeset/add-skill-script-loader.md deleted file mode 100644 index d36276e9f..000000000 --- a/.changeset/add-skill-script-loader.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@bradygaster/squad-sdk": minor ---- - -Add SkillScriptLoader, handler types, and applySkillHandlers for executable skill handler scripts diff --git a/.changeset/ado-configurable-items.md b/.changeset/ado-configurable-items.md deleted file mode 100644 index b1b2e0cec..000000000 --- a/.changeset/ado-configurable-items.md +++ /dev/null @@ -1,14 +0,0 @@ ---- -"@bradygaster/squad-sdk": minor ---- - -ADO configurable work item types, area paths, and iteration support (#240) - -- Add `getAvailableWorkItemTypes(org, project)` for process template introspection -- Add `validateWorkItemType(org, project, typeName)` for pre-creation validation -- Add `WorkItemTypeInfo` interface for type metadata -- Enhance `AzureDevOpsAdapter` with instance-level `getAvailableWorkItemTypes()` and `validateWorkItemType()` methods -- Support optional `validateType` flag in `createWorkItem()` to check type before creation -- Enhance `squad init` to introspect available work item types and store `_availableTypes` hint in `.squad/config.json` -- Support `adoConfig` in `InitOptions` for explicit work item type, area path, and iteration path during init -- Graceful fallback to default types (User Story, Bug, Task) when az CLI is unavailable diff --git a/.changeset/apm-integration.md b/.changeset/apm-integration.md deleted file mode 100644 index 094f3102d..000000000 --- a/.changeset/apm-integration.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@bradygaster/squad-cli": minor ---- - -feat: APM integration — squad skill publish/install + apm.yml in init - -Implements #824. Adds `squad skill publish/install/list` commands and generates `apm.yml` on `squad init`. diff --git a/.changeset/builtin-skills.md b/.changeset/builtin-skills.md deleted file mode 100644 index 30962cc2e..000000000 --- a/.changeset/builtin-skills.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -"@bradygaster/squad-cli": minor ---- - -Ship 8 built-in skills with squad init/upgrade (#788) - -New skills distributed automatically on `squad init` and `squad upgrade`: -- **error-recovery** — graceful failure handling patterns -- **secret-handling** — credential safety and secrets management -- **git-workflow** — branch management and commit conventions -- **session-recovery** — checkpoint and recovery patterns -- **reviewer-protocol** — code review gate patterns -- **test-discipline** — test-first discipline and coverage -- **agent-collaboration** — multi-agent handoff patterns -- **squad-conventions** — (already shipped, now part of curated set) - -All skills are squad-owned (`overwriteOnUpgrade: true`) and update on upgrade. diff --git a/.changeset/cleanup-ceremony.md b/.changeset/cleanup-ceremony.md deleted file mode 100644 index 4a9a2631e..000000000 --- a/.changeset/cleanup-ceremony.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -"@bradygaster/squad-cli": minor ---- - -Add cleanup watch capability for stale file housekeeping (#791) - -- New `cleanup` capability in the `housekeeping` phase -- Clears `.squad/.scratch/` (all ephemeral temp files) -- Archives orchestration-log and session-log entries older than 30 days -- Warns about stale decision inbox files (>7 days) -- Configurable: `everyNRounds` (default: 10), `maxAgeDays` (default: 30) -- 12 new tests diff --git a/.changeset/contamination-guard.md b/.changeset/contamination-guard.md deleted file mode 100644 index 29ed0ae95..000000000 --- a/.changeset/contamination-guard.md +++ /dev/null @@ -1,8 +0,0 @@ ---- ---- - -ci: add PR contamination prevention guard - -New diff-guard CI check warns when single-commit PRs touch 30+ files -(likely branch contamination). Updated copilot-instructions with branch -creation and staging safety rules. diff --git a/.changeset/cooperative-rate-limiting.md b/.changeset/cooperative-rate-limiting.md deleted file mode 100644 index 524a58109..000000000 --- a/.changeset/cooperative-rate-limiting.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"@bradygaster/squad-sdk": minor ---- - -feat: Cooperative rate limiting with predictive circuit breaker - -Added cooperative rate limiting patterns for multi-agent deployments: -- Traffic Light, Predictive Circuit Breaker, Priority Retry Windows -- Cooperative Token Pool for shared quota management - -Closes #515 diff --git a/.changeset/cross-squad-orchestration.md b/.changeset/cross-squad-orchestration.md deleted file mode 100644 index c22bde31a..000000000 --- a/.changeset/cross-squad-orchestration.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@bradygaster/squad-sdk": minor -"@bradygaster/squad-cli": minor ---- - -Cross-squad orchestration — discovery, delegation, and manifest (#316). Adds manifest schema, `squad discover` / `squad delegate` commands, and runtime module for coordinating work across multiple Squad instances. diff --git a/.changeset/deprecate-tunnel-rc-repl.md b/.changeset/deprecate-tunnel-rc-repl.md deleted file mode 100644 index 93b3e3614..000000000 --- a/.changeset/deprecate-tunnel-rc-repl.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@bradygaster/squad-cli": patch ---- - -Add deprecation warnings for tunnel, rc, and REPL commands. The interactive shell (no-args), `squad start`, `squad start --tunnel`, `squad rc`, and `squad rc-tunnel` now emit yellow deprecation notices pointing users to the GitHub Copilot CLI. No behavior changes — all commands still work. diff --git a/.changeset/docs-fork-contribution-workflow.md b/.changeset/docs-fork-contribution-workflow.md deleted file mode 100644 index 8d2d664ab..000000000 --- a/.changeset/docs-fork-contribution-workflow.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -"@bradygaster/squad-cli": patch ---- - -docs: add fork contribution workflow to CONTRIBUTING.md - -Closes five gaps discovered during PR #217: -- Fork-first setup instructions (fork → clone → upstream remote) -- PR must target `dev` branch, not `main` (`gh pr create --base dev`) -- Changeset is a required step in the PR process checklist -- `bradygaster/dev` now correctly described as the PR target for all contributions -- New "Keeping Your Fork in Sync" section with rebase-on-upstream/dev instructions diff --git a/.changeset/dual-mode-capabilities.md b/.changeset/dual-mode-capabilities.md deleted file mode 100644 index 497aeda5c..000000000 --- a/.changeset/dual-mode-capabilities.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -'@bradygaster/squad-sdk': minor ---- - -Add dual-mode deployment support for capabilities routing. - -New features: -- `SQUAD_POD_ID` env var for pod-specific capability manifests -- `SQUAD_DEPLOYMENT_MODE` env var (`agent-per-node` | `squad-per-pod`) -- Pod-specific manifest loading: `.squad/machine-capabilities-{podId}.json` -- Fallback chain: pod-specific → shared → user-home → null (opt-in) -- New exports: `getDeploymentMode()`, `getPodId()`, `DeploymentMode` type diff --git a/.changeset/error-recovery-skill.md b/.changeset/error-recovery-skill.md deleted file mode 100644 index ec48a85a3..000000000 --- a/.changeset/error-recovery-skill.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@bradygaster/squad-cli": minor -"@bradygaster/squad-sdk": minor ---- -feat: add error-recovery skill for standard agent failure recovery patterns \ No newline at end of file diff --git a/.changeset/external-state.md b/.changeset/external-state.md deleted file mode 100644 index 9585a11d6..000000000 --- a/.changeset/external-state.md +++ /dev/null @@ -1,16 +0,0 @@ ---- -"@bradygaster/squad-sdk": minor -"@bradygaster/squad-cli": minor ---- - -Add external state storage — move .squad/ out of the working tree (#792) - -- New `stateLocation: 'external'` option in `.squad/config.json` -- `resolveExternalStateDir()` resolves state under the platform-specific global Squad directory (`resolveGlobalSquadPath()`) -- `deriveProjectKey()` generates a stable key from the repo path (cross-platform) -- `resolveSquadPaths()` honors external state location -- `squad externalize` moves state out, `squad internalize` moves it back -- State survives branch switches, invisible to `git status`, never pollutes PRs -- Thin `.squad/config.json` marker stays in repo (gitignored) -- Path traversal protection on projectKey -- 12 new tests diff --git a/.changeset/fact-checker-agent.md b/.changeset/fact-checker-agent.md deleted file mode 100644 index 7f20635d3..000000000 --- a/.changeset/fact-checker-agent.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -"@bradygaster/squad-sdk": minor -"@bradygaster/squad-cli": minor ---- - -Add fact-checker as a built-in agent role (#789) - -- New `fact-checker` role in the engineering role catalog (emoji: 🔍, category: quality) -- Charter template at `templates/fact-checker-charter.md` with verification methodology -- Added to `AGENT_TEMPLATES` for init scaffolding -- Template manifest entry for init/upgrade distribution -- Routing patterns: fact-check, verify, validate, audit, double-check, hallucination, devil's advocate diff --git a/.changeset/fix-changelog-gate.md b/.changeset/fix-changelog-gate.md deleted file mode 100644 index 1d84acec2..000000000 --- a/.changeset/fix-changelog-gate.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@bradygaster/squad-cli': patch ---- - -Fix changelog-gate CI to accept .changeset/ files as alternative to direct CHANGELOG.md edits diff --git a/.changeset/fix-detect-squad-dir-zero-deps.md b/.changeset/fix-detect-squad-dir-zero-deps.md deleted file mode 100644 index ca9fb1396..000000000 --- a/.changeset/fix-detect-squad-dir-zero-deps.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -"@bradygaster/squad-cli": patch ---- - -fix(cli): revert detect-squad-dir to zero-dependency bootstrap - -The StorageProvider refactor (26047dc5) accidentally converted this bootstrap utility from raw node:fs to FSStorageProvider. This file runs before the SDK is loaded and must not depend on @bradygaster/squad-sdk. Adds regression guard test. diff --git a/.changeset/fix-dev-ci-failures.md b/.changeset/fix-dev-ci-failures.md deleted file mode 100644 index 8b1dee5ab..000000000 --- a/.changeset/fix-dev-ci-failures.md +++ /dev/null @@ -1,40 +0,0 @@ ---- -"@bradygaster/squad-cli": patch ---- - -fix: restore CI green on dev — 25 regression fixes + 6 test corrections - -Commit `4ecc244` ("feat: Squad Remote Control") rewrote `cli-entry.ts` and -silently dropped multiple P0 bug fixes. Commit `72ffcb1` ("unified status -display") introduced a TUI regression in AgentPanel. This changeset restores -all dropped behaviour and corrects test expectations that never matched the -implementation. - -**Implementation regressions fixed (cli-entry.ts):** -- Bare semver output: `squad --version` now prints `0.x.y` not `squad 0.x.y` -- Whitespace args guard: `squad` / `squad ` shows brief help and exits 0 -- `NODE_NO_WARNINGS=1` set before first import to suppress ExperimentalWarning -- `squad doctor` hint restored in unknown-command error messages -- Help lines that exceeded 80 chars wrapped to continuation lines - -**Implementation regressions fixed (shell/index.ts):** -- First-run (no `.squad/`) on non-TTY now outputs a welcome/get-started message - instead of a TTY error, matching E2E test expectations - -**Implementation regressions fixed (AgentPanel.tsx):** -- Completion flash correctly shows `✓ Done`; was showing `✓ [IDLE]` because - the status-label condition was not gated on the flash state - -**Test corrections (expectations that never matched implementation):** -- `repl-ux.test.ts`: `toContain('ready')` → `toContain('[idle]')` -- `human-journeys.test.ts`: `Scaffold ready` → `Your team is ready`; - `copilot session` → `squad` -- `cli/init.test.ts` + `repl-ux-fixes.test.ts`: wrong gitattributes path fixed -- `ux-gates.test.ts`: two aspirational grouped-help tests replaced with `it.todo` -- `first-run-gating.test.ts`: banner spacer regex updated to match current source form -- `consult-command.feature`: expected text updated to match current CLI output -- `status-extended.feature`: exit code corrected (`1` → `0`) for non-squad dir -- `docs-build.test.ts`: `beforeAll` hook given explicit 30 s timeout to avoid - flaky timeout failures under parallel test execution -- `journey-next-day.test.ts`: added `tick(50)` between session saves to prevent - race condition when both sessions receive the same `lastActiveAt` timestamp diff --git a/.changeset/fix-doctor-casting-upgrade.md b/.changeset/fix-doctor-casting-upgrade.md deleted file mode 100644 index 636aa7682..000000000 --- a/.changeset/fix-doctor-casting-upgrade.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@bradygaster/squad-cli': patch ---- - -Fix squad doctor and upgrade for insiders installs: add .squad/casting/ to ENSURE_DIRECTORIES, scaffold casting defaults from templates with permission-safe fallback, and clarify ESM warnings for global installs. diff --git a/.changeset/fix-init-noargs-createteam.md b/.changeset/fix-init-noargs-createteam.md deleted file mode 100644 index ff673f4b6..000000000 --- a/.changeset/fix-init-noargs-createteam.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"@bradygaster/squad-cli": patch ---- - -fix: `/init` with no args now accepts follow-up message as cast prompt, and `createTeam` correctly creates `team.md`/`routing.md` in fresh projects - -Two related bugs in the TUI init flow: - -1. After `/init` (no args) showed guidance text, the user's follow-up message hit the "No Squad team found" guard instead of starting team casting. Fixed by tracking `awaitingInitPrompt` state in `App.tsx` and bypassing the team-file guard in `handleDispatch` when `skipCastConfirmation` is explicitly set. - -2. After confirming a team proposal, `createTeam` silently skipped creating `team.md` and `routing.md` in a fresh project (no `.squad/` directory), causing the coordinator to immediately say "no team yet" after showing "Team hired!". Fixed with else-branches that create both files from scratch when they don't exist. diff --git a/.changeset/fix-nap-archival-budget.md b/.changeset/fix-nap-archival-budget.md deleted file mode 100644 index 95461886a..000000000 --- a/.changeset/fix-nap-archival-budget.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -"@bradygaster/squad-cli": patch ---- - -fix(nap): account for separator newlines in decision archival budget - -The budget calculation in archiveDecisions() did not account for the newline -separators added during content reassembly. This caused the final recentContent -to exceed DECISION_THRESHOLD even after archival. Fix adds reassemblyOverhead -and per-entry separator bytes to the budget calculation. - -Closes #123 \ No newline at end of file diff --git a/.changeset/fix-nap-subprocess-cwd.md b/.changeset/fix-nap-subprocess-cwd.md deleted file mode 100644 index 11edb2947..000000000 --- a/.changeset/fix-nap-subprocess-cwd.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@bradygaster/squad-cli": patch ---- - -fix(cli): wire --team-root / SQUAD_TEAM_ROOT into squad resolution for nap, status, and cost commands (#734) - -Commands that resolve .squad/ now respect the SQUAD_TEAM_ROOT env var (set by --team-root flag), -fixing subprocess invocations (e.g. Copilot CLI bang commands) where process.cwd() differs from -the interactive shell. Also improves the nap error message to show the searched directory. diff --git a/.changeset/fix-onboarding-mode-bail.md b/.changeset/fix-onboarding-mode-bail.md deleted file mode 100644 index 49f63f71c..000000000 --- a/.changeset/fix-onboarding-mode-bail.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@bradygaster/squad-cli": patch ---- - -fix: CLI no longer bails when configured is false; starts onboarding session instead (#843) diff --git a/.changeset/fix-readme-migration-guide-link.md b/.changeset/fix-readme-migration-guide-link.md deleted file mode 100644 index 84d732067..000000000 --- a/.changeset/fix-readme-migration-guide-link.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@bradygaster/squad-cli": patch ---- - -docs: point README migration guide links to the published docs site \ No newline at end of file diff --git a/.changeset/fix-roster-sync.md b/.changeset/fix-roster-sync.md deleted file mode 100644 index 2fd31a766..000000000 --- a/.changeset/fix-roster-sync.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@bradygaster/squad-sdk': patch ---- - -Sync squad.agent.md roster when agents added to team.md diff --git a/.changeset/fix-silent-agent-md-skip.md b/.changeset/fix-silent-agent-md-skip.md deleted file mode 100644 index 349139fcb..000000000 --- a/.changeset/fix-silent-agent-md-skip.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@bradygaster/squad-cli': patch -'@bradygaster/squad-sdk': patch ---- - -Warn when squad.agent.md template is missing during upgrade or init instead of silently skipping file creation. Adds `warnings` field to `InitResult` for structured error reporting. diff --git a/.changeset/fix-team-root-all-commands.md b/.changeset/fix-team-root-all-commands.md deleted file mode 100644 index dfffaea34..000000000 --- a/.changeset/fix-team-root-all-commands.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@bradygaster/squad-cli': patch ---- - -Extend SQUAD_TEAM_ROOT to all resolveSquad() call sites for subprocess compatibility diff --git a/.changeset/fix-triage-label-slug.md b/.changeset/fix-triage-label-slug.md deleted file mode 100644 index 60fb4ec81..000000000 --- a/.changeset/fix-triage-label-slug.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@bradygaster/squad-sdk': patch -'@bradygaster/squad-cli': patch ---- - -Fix triage label slug derivation: use `slugify()` instead of `toLowerCase()` so multi-word agent names produce valid GitHub labels (e.g. "Steve Rogers" → `squad:steve-rogers` instead of `squad:steve rogers`). - -Pre-create all `squad:{member}` labels at watch startup via `ensureTag()` so `gh issue edit --add-label` never fails on missing labels. diff --git a/.changeset/fix-watch-windows-shared-fetch.md b/.changeset/fix-watch-windows-shared-fetch.md deleted file mode 100644 index cee13e02d..000000000 --- a/.changeset/fix-watch-windows-shared-fetch.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -"@bradygaster/squad-cli": patch ---- - -fix(watch): Windows shell:true, shared agent-spawn, round-level fetch (#920, #923) - -Three fixes for the watch --execute subsystem: - -1. Added shell: IS_WINDOWS to all 37+ execFile calls so commands resolve - through PATH on Windows (fixes spawn EINVAL errors). - -2. Created shared agent-spawn.ts module replacing 7 copy-pasted - buildAgentCommand() implementations. Default changed from deprecated - gh copilot to standalone copilot CLI. - -3. Added RoundData shared fetch — issues and PRs fetched once per round - instead of per-capability, reducing API calls from ~40 to ~2 per round. diff --git a/.changeset/fleet-dispatch-hybrid.md b/.changeset/fleet-dispatch-hybrid.md deleted file mode 100644 index 70f5d8b7a..000000000 --- a/.changeset/fleet-dispatch-hybrid.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@bradygaster/squad-cli": minor ---- - -Add /fleet hybrid dispatch mode for squad watch --execute (#775) — enables parallel issue analysis via Copilot CLI /fleet, 2.9x faster than sequential dispatch for read-heavy work diff --git a/.changeset/git-state-backends.md b/.changeset/git-state-backends.md deleted file mode 100644 index 994e03465..000000000 --- a/.changeset/git-state-backends.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -"@bradygaster/squad-sdk": minor -"@bradygaster/squad-cli": minor ---- - -feat(sdk): git-notes + orphan-branch state backends for .squad/ - -Adds two git-native state storage backends as alternatives to the worktree -and external directory approaches: - -- **git-notes** (`refs/notes/squad`): State stored in git notes ref. Survives - branch switches, invisible in diffs and PRs. -- **orphan-branch** (`squad-state`): Dedicated orphan branch with no common - ancestor. State files never appear in main. - -Configure via `.squad/config.json`: `{ "stateBackend": "git-notes" }` or -the `--state-backend` CLI flag. \ No newline at end of file diff --git a/.changeset/init-upgrade-parity-tests.md b/.changeset/init-upgrade-parity-tests.md deleted file mode 100644 index 8d97181d0..000000000 --- a/.changeset/init-upgrade-parity-tests.md +++ /dev/null @@ -1,8 +0,0 @@ ---- ---- - -test: add init/upgrade/doctor parity test suite - -7 tests verifying that init and upgrade produce equivalent scaffolding. -Guards against drift where new init features (like casting) are not -mirrored in upgrade. diff --git a/.changeset/iterative-retrieval-skill.md b/.changeset/iterative-retrieval-skill.md deleted file mode 100644 index 8a1e8fc4c..000000000 --- a/.changeset/iterative-retrieval-skill.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@bradygaster/squad-cli": minor -"@bradygaster/squad-sdk": minor ---- -feat: add iterative-retrieval skill for structured max-3-cycle agent spawning \ No newline at end of file diff --git a/.changeset/keda-scaler-docs.md b/.changeset/keda-scaler-docs.md deleted file mode 100644 index f838ef7d8..000000000 --- a/.changeset/keda-scaler-docs.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -"@bradygaster/squad-cli": patch ---- - -docs: Add KEDA external scaler template for GitHub issue-driven autoscaling - -New template documenting how to use keda-copilot-scaler for scaling -agent pods to zero when idle, with rate-limit-aware polling. - -Closes #516 diff --git a/.changeset/loop-command.md b/.changeset/loop-command.md deleted file mode 100644 index 80097834d..000000000 --- a/.changeset/loop-command.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -"@bradygaster/squad-cli": minor ---- - -feat(cli): Add `squad loop` command — prompt-driven continuous work loop - -New `squad loop` command reads a `loop.md` file and runs it as a continuous work loop. -No GitHub issues required — the prompt is the work driver. Includes `--init` to scaffold -a boilerplate loop file, frontmatter validation, and composable capability flags. diff --git a/.changeset/machine-capability-routing.md b/.changeset/machine-capability-routing.md deleted file mode 100644 index 2ac99caf7..000000000 --- a/.changeset/machine-capability-routing.md +++ /dev/null @@ -1,15 +0,0 @@ ---- -"@bradygaster/squad-sdk": minor -"@bradygaster/squad-cli": minor ---- - -feat: Machine capability discovery and `needs:*` label-based issue routing - -Added capability filtering to Ralph's watch command. Issues with `needs:*` labels -(e.g., `needs:gpu`, `needs:browser`) are only processed by Ralph instances whose -machine has those capabilities declared in `machine-capabilities.json`. - -This enables multi-machine Squad deployments where different machines handle -different types of work based on their available tooling. - -Closes #514 \ No newline at end of file diff --git a/.changeset/manifest-driven-skills.md b/.changeset/manifest-driven-skills.md deleted file mode 100644 index 9caad36df..000000000 --- a/.changeset/manifest-driven-skills.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -"@bradygaster/squad-sdk": patch -"@bradygaster/squad-cli": patch ---- - -fix: use TEMPLATE_MANIFEST to drive skill installation instead of wholesale directory copy - -Both sdkInitSquad() and syncAllSkills() previously copied the entire templates/skills/ -directory, ignoring the curated 8-skill subset declared in TEMPLATE_MANIFEST. -This meant all 37+ template skills shipped on every init/upgrade, and -overwriteOnUpgrade was never consulted. - -Now both code paths iterate TEMPLATE_MANIFEST entries: -- init (SDK): only the 8 manifest skills are copied on first init -- upgrade (CLI): syncAllSkills() reads manifest entries, respects overwriteOnUpgrade - -Fixes #833 diff --git a/.changeset/notification-routing-skill.md b/.changeset/notification-routing-skill.md deleted file mode 100644 index 7f71556f3..000000000 --- a/.changeset/notification-routing-skill.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@bradygaster/squad-cli": minor -"@bradygaster/squad-sdk": minor ---- - -feat: add notification-routing skill for pub-sub channel routing \ No newline at end of file diff --git a/.changeset/persistent-ralph.md b/.changeset/persistent-ralph.md deleted file mode 100644 index 35d94bbd8..000000000 --- a/.changeset/persistent-ralph.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -'@bradygaster/squad-sdk': minor -'@bradygaster/squad-cli': minor ---- - -Enable persistent Ralph — heartbeat cron + healthCheck timer - -- Enable cron schedule in squad-heartbeat.yml (all 5 sync locations) -- Enable RalphMonitor healthCheck timer (previously commented out pre-migration) -- Add platform detection tests for getRalphScanCommands (GitHub/ADO/Planner) -- Add healthCheck timer tests with fake timers (start/stop/interval/stale detection) diff --git a/.changeset/quiet-notifications.md b/.changeset/quiet-notifications.md deleted file mode 100644 index 5a8880512..000000000 --- a/.changeset/quiet-notifications.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -"@bradygaster/squad-cli": minor ---- - -Add `--notify-level` to control watch round reporting noise (#803) - -- `--notify-level important` (default): only print rounds with actual work items -- `--notify-level all`: print every round including empty (old behavior) -- `--notify-level none`: suppress all round output -- Add machine name (`os.hostname()`) and repo name to round headers for attribution - (shown in round headers when the board has items, and in "Board is clear" message) -- Configurable via `.squad/config.json` watch section: `"notifyLevel": "important"` -- Empty rounds silenced by default — no more "Round 160, Round 161" spam diff --git a/.changeset/ralph-two-pass-scan-skill.md b/.changeset/ralph-two-pass-scan-skill.md deleted file mode 100644 index 35a7ff21d..000000000 --- a/.changeset/ralph-two-pass-scan-skill.md +++ /dev/null @@ -1,4 +0,0 @@ ---- ---- - -Add ralph-two-pass-scan skill — lightweight issue list scan before selective hydration, cutting Ralph's GitHub API calls by ~72% per round (resolves #596) diff --git a/.changeset/readiness-file-list.md b/.changeset/readiness-file-list.md deleted file mode 100644 index 5cc36c951..000000000 --- a/.changeset/readiness-file-list.md +++ /dev/null @@ -1,7 +0,0 @@ ---- ---- - -ci: add file list with line stats to PR readiness comment - -The PR readiness bot now shows changed files with per-file addition/deletion -counts, scope classification (Product/Infrastructure/Mixed), and totals. diff --git a/.changeset/readiness-rerun.md b/.changeset/readiness-rerun.md deleted file mode 100644 index f1f2ee952..000000000 --- a/.changeset/readiness-rerun.md +++ /dev/null @@ -1,8 +0,0 @@ ---- ---- - -ci: re-run PR readiness check after Squad CI completes - -Added workflow_run trigger to the readiness check so it refreshes after -CI finishes. Uses PR API for draft status instead of env var (more reliable -for workflow_run events). Includes 3 new draft-override tests. diff --git a/.changeset/reflect-skill.md b/.changeset/reflect-skill.md deleted file mode 100644 index 1263013b1..000000000 --- a/.changeset/reflect-skill.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@bradygaster/squad-cli": minor -"@bradygaster/squad-sdk": minor ---- -feat: add reflect skill for in-session learning capture and mistake prevention \ No newline at end of file diff --git a/.changeset/retro-enforcement.md b/.changeset/retro-enforcement.md deleted file mode 100644 index 1cc4d4ee3..000000000 --- a/.changeset/retro-enforcement.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -"@bradygaster/squad-cli": minor -"@bradygaster/squad-sdk": patch ---- - -Add retro enforcement skill with Test-RetroOverdue and ceremonies template update. - -- New skill: retro-enforcement - coordinator integration pattern for automated retro cadence enforcement -- Action items tracked as GitHub Issues (not markdown checklists) -- Production data: 0% to 100% completion rate after switching formats -- Test-RetroOverdue PowerShell function detects overdue retros and blocks work queue -- Ceremonies template updated with enforcement-aware retrospective definition diff --git a/.changeset/scope-boundary-check.md b/.changeset/scope-boundary-check.md deleted file mode 100644 index 6f98a8bd3..000000000 --- a/.changeset/scope-boundary-check.md +++ /dev/null @@ -1,8 +0,0 @@ ---- ---- - -ci: scope boundary enforcement for repo-health PRs - -New CI check that fails repo-health PRs if they modify product source -code under packages/*/src/. Enforces separation between infrastructure -and product changes. diff --git a/.changeset/scratch-dir-utility.md b/.changeset/scratch-dir-utility.md deleted file mode 100644 index 9fd5d5769..000000000 --- a/.changeset/scratch-dir-utility.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -"@bradygaster/squad-sdk": minor ---- - -Add `.squad/.scratch/` directory for organized temp file management (#790) - -- `scratchDir()` — resolve and optionally create the scratch directory -- `scratchFile()` — create named temp files inside `.scratch/` -- Init scaffolds `.squad/.scratch/` and adds it to `.gitignore` -- Agents and CLI should use these utilities instead of writing temp files to repo root diff --git a/.changeset/sdk-parity-batch2-tests.md b/.changeset/sdk-parity-batch2-tests.md deleted file mode 100644 index 5a06207d4..000000000 --- a/.changeset/sdk-parity-batch2-tests.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@bradygaster/squad-sdk": patch ---- - -Add SDK feature parity batch 2 — 64 tests covering manual ceremonies (#27), ceremony cooldown (#28), human team members (#36), constraint budget enforcement (#49 — rate limiter, file-write guards, shell restrictions, PII scrubbing), multi-agent artifact coordination (#50), and builder validation edge cases. diff --git a/.changeset/sdk-parity-batch3-tests.md b/.changeset/sdk-parity-batch3-tests.md deleted file mode 100644 index 79aa07c39..000000000 --- a/.changeset/sdk-parity-batch3-tests.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -"@bradygaster/squad-sdk": patch ---- - -test: SDK feature parity batch 3 — 46 tests for #31, #47, #45, #46 - -Adds 46 automated tests covering 4 SDK features from the #341 parity matrix: -- RalphMonitor idle-watch mode (#31): construction, event handling, stale session detection -- Platform detection (#47): GitHub/Azure DevOps URL parsing, detectPlatformFromUrl -- Reviewer lockout (#45): rejection protocol, per-artifact scope, persistence -- Deadlock handling (#46): all-agents-locked detection, clearLockout escalation, recovery diff --git a/.changeset/self-upgrade.md b/.changeset/self-upgrade.md deleted file mode 100644 index 0567983d1..000000000 --- a/.changeset/self-upgrade.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -"@bradygaster/squad-cli": minor ---- - -Add `squad upgrade --self` to upgrade the CLI package itself (#798) - -- `squad upgrade --self` → installs `@bradygaster/squad-cli@latest` (stable) -- `squad upgrade --self --insider` → installs `@bradygaster/squad-cli@insider` (prerelease) -- After self-upgrade, automatically continues with repo upgrade to apply new templates -- Detects package manager (npm/pnpm/yarn) from npm_config_user_agent -- Clear error on permission denied (suggests sudo or npx) -- Help text updated with new flags diff --git a/.changeset/smart-pr-nudge.md b/.changeset/smart-pr-nudge.md deleted file mode 100644 index 2144528df..000000000 --- a/.changeset/smart-pr-nudge.md +++ /dev/null @@ -1,8 +0,0 @@ ---- ---- - -ci: add smart PR nudge for stale PRs - -New workflow that runs on weekdays and posts actionable diagnoses on PRs -stale for 7+ days. Checks CI status, unresolved threads, missing reviews, -outdated branches, and draft status. Won't nudge the same PR twice per week. diff --git a/.changeset/squad-scheduler.md b/.changeset/squad-scheduler.md deleted file mode 100644 index c008a8920..000000000 --- a/.changeset/squad-scheduler.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -"@bradygaster/squad-sdk": minor -"@bradygaster/squad-cli": minor ---- - -Generic, provider-agnostic scheduler for Squad (#296) — unified schedule.json manifest with LocalPolling and GitHubActions provider adapters, CLI commands (list, run, init, status), schema validation, and cron/interval trigger evaluation. diff --git a/.changeset/subprocess-integration-tests.md b/.changeset/subprocess-integration-tests.md deleted file mode 100644 index 9535f967c..000000000 --- a/.changeset/subprocess-integration-tests.md +++ /dev/null @@ -1,8 +0,0 @@ ---- ---- - -test: add Copilot CLI subprocess integration tests for SQUAD_TEAM_ROOT - -8 tests covering SQUAD_TEAM_ROOT env-var resolution, fallback to cwd, -and resolveSquad() integration. Guards against subprocess working directory -bugs in Copilot CLI bang commands. diff --git a/.changeset/teams-comms-adapter.md b/.changeset/teams-comms-adapter.md deleted file mode 100644 index c676b9dd9..000000000 --- a/.changeset/teams-comms-adapter.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -"@bradygaster/squad-sdk": minor ---- - -feat(sdk): Add Microsoft Teams communication adapter - -BREAKING: `createCommunicationAdapter` is now async (returns `Promise`). -Callers must await the result. - -New Teams adapter for bidirectional chat via Microsoft Graph API. -Supports browser auth (PKCE), device code flow, token caching, -1:1 chat and channel messaging. diff --git a/.changeset/tiered-memory.md b/.changeset/tiered-memory.md deleted file mode 100644 index f2d2336b2..000000000 --- a/.changeset/tiered-memory.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@bradygaster/squad-cli": minor -"@bradygaster/squad-sdk": minor ---- -feat: add tiered-memory skill for hot/cold/wiki agent context management \ No newline at end of file diff --git a/.changeset/watch-circuit-breaker.md b/.changeset/watch-circuit-breaker.md deleted file mode 100644 index b9b335267..000000000 --- a/.changeset/watch-circuit-breaker.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -"@bradygaster/squad-cli": minor ---- - -feat(watch): circuit breaker integration for rate limit protection (#515) - -Adds GitHub API rate limit protection to Ralph's watch command via -the Predictive Circuit Breaker from PR #518. - -**What changed (additive patch — existing flow untouched):** -- `gh-cli.ts`: Added `ghRateLimitCheck()` and `isRateLimitError()` helpers -- `watch.ts`: Added `CircuitBreakerState` type + persistence helpers -- `watch.ts`: Added `executeRound()` wrapper that gates the existing - `runCheck()` call through pre-flight quota checks -- `watch.ts`: Added `roundInProgress` flag to prevent overlapping rounds - -**Circuit breaker state machine:** -- CLOSED → OPEN: When traffic light is red or predictor says exhaustion imminent -- OPEN → HALF-OPEN: After cooldown expires (exponential: 2m → 4m → 8m → ... → 30m cap) -- HALF-OPEN → CLOSED: After 2 consecutive successful rounds -- HALF-OPEN → OPEN: On rate limit error during probe - -State persists to `.squad/ralph-circuit-breaker.json` across restarts. - -**Tests:** 16 new tests covering state transitions, race condition guard, -predictive integration, and `isRateLimitError` detection. diff --git a/.changeset/watch-health.md b/.changeset/watch-health.md deleted file mode 100644 index 7ea8999a3..000000000 --- a/.changeset/watch-health.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -"@bradygaster/squad-cli": minor ---- - -feat(watch): health check — show running watch instance status (#808) - -Adds `squad watch --health` to display the status of a running watch -instance: PID, uptime, auth account, capabilities, and auth drift -detection. Writes `.squad/.watch-pid.json` at startup for instance -tracking. Detects and cleans up stale PID files from crashed instances. diff --git a/.changeset/watch-ux-fixes-2141.md b/.changeset/watch-ux-fixes-2141.md deleted file mode 100644 index 961772e8f..000000000 --- a/.changeset/watch-ux-fixes-2141.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@bradygaster/squad-cli": patch ---- - -fix(watch): 3 UX improvements — round timing output, --log-file tee flag, immediate startup feedback (#2141) \ No newline at end of file diff --git a/.changeset/watch-verbose-mode.md b/.changeset/watch-verbose-mode.md deleted file mode 100644 index 3dc92ae8d..000000000 --- a/.changeset/watch-verbose-mode.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@bradygaster/squad-cli": minor ---- - -Add --verbose flag to squad watch for debugging empty boards and silent failures (#781) diff --git a/.copilot/skills/cli-wiring/SKILL.md b/.copilot/skills/cli-wiring/SKILL.md index 03f7bf55f..07ab25284 100644 --- a/.copilot/skills/cli-wiring/SKILL.md +++ b/.copilot/skills/cli-wiring/SKILL.md @@ -1,3 +1,11 @@ +--- +name: "cli-wiring" +description: "Checklist and patterns for wiring new CLI commands into cli-entry.ts" +domain: "cli" +confidence: "high" +source: "extracted" +--- + # Skill: CLI Command Wiring **Bug class:** Commands implemented in `packages/squad-cli/src/cli/commands/` but never routed in `cli-entry.ts`. diff --git a/.copilot/skills/init-mode/SKILL.md b/.copilot/skills/init-mode/SKILL.md index 4dce6628c..430c6ae15 100644 --- a/.copilot/skills/init-mode/SKILL.md +++ b/.copilot/skills/init-mode/SKILL.md @@ -20,7 +20,7 @@ Init Mode activates when `.squad/team.md` does not exist, or exists but has zero No team exists yet. Propose one — but **DO NOT create any files until the user confirms.** -1. **Identify the user.** Run `git config user.name` to learn who you're working with. Use their name in conversation (e.g., *"Hey Brady, what are you building?"*). Store their name (NOT email) in `team.md` under Project Context. **Never read or store `git config user.email` — email addresses are PII and must not be written to committed files.** +1. **Identify the user.** Run `git config user.name` to learn who you're working with. Use their name in conversation (e.g., *"Hey {user}, what are you building?"*). Store their name (NOT email) in `team.md` under Project Context. **Never read or store `git config user.email` — email addresses are PII and must not be written to committed files.** 2. Ask: *"What are you building? (language, stack, what it does)"* 3. **Cast the team.** Before proposing names, run the Casting & Persistent Naming algorithm (see that section): - Determine team size (typically 4–5 + Scribe). @@ -82,8 +82,8 @@ The `union` merge driver keeps all lines from both sides, which is correct for a **Example flow:** 1. Coordinator detects no team.md → Init Mode -2. Runs `git config user.name` → "Brady" -3. Asks: *"Hey Brady, what are you building?"* +2. Runs `git config user.name` → "{user}" +3. Asks: *"Hey {user}, what are you building?"* 4. User: *"TypeScript CLI tool with GitHub API integration"* 5. Coordinator runs casting algorithm → selects "The Usual Suspects" universe 6. Proposes: Keaton (Lead), Verbal (Prompt), Fenster (Backend), Hockney (Tester), Scribe, Ralph diff --git a/.copilot/skills/protected-files/SKILL.md b/.copilot/skills/protected-files/SKILL.md new file mode 100644 index 000000000..1b35373f9 --- /dev/null +++ b/.copilot/skills/protected-files/SKILL.md @@ -0,0 +1,53 @@ +--- +name: "protected-files" +description: "Zero-dependency bootstrap files that must never import npm packages or SDK code" +domain: "dependency-safety" +confidence: "high" +source: "earned — CLI startup crashes when bootstrap files import SDK code" +--- + +## Context + +The CLI (`squad-cli`) has bootstrap utilities that run **before** the Squad SDK is loaded. If these files import SDK code (e.g., `FSStorageProvider`, anything from `squad-sdk`), the CLI breaks at startup — no helpful error, just a crash. + +This skill applies when: +- Touching any file in `packages/squad-cli/src/cli/core/` +- Running sweeping refactors (e.g., "convert all `fs` calls to `StorageProvider`") +- Adding new bootstrap utilities + +## Protected File List + +| File | Purpose | +|------|---------| +| `packages/squad-cli/src/cli/core/detect-squad-dir.ts` | Finds `.squad/` directory at startup — runs before SDK init | +| `packages/squad-cli/src/cli/core/errors.ts` | Error classes (`SquadError`, `fatal()`) — used by all CLI entry points | +| `packages/squad-cli/src/cli/core/gh-cli.ts` | GitHub CLI wrapper — uses only `node:child_process` and `node:util` | +| `packages/squad-cli/src/cli/core/output.ts` | Color/emoji console output — pure ANSI codes, zero imports | +| `packages/squad-cli/src/cli/core/history-split.ts` | Separates portable knowledge from project data — pure string logic | + +## Rules + +- ❌ **NEVER** convert these files to use `FSStorageProvider`, `StorageProvider`, or any SDK abstraction +- ❌ **NEVER** add `import` or `require` statements referencing packages outside `node:*` built-ins +- ✅ **ONLY** use `node:fs`, `node:path`, `node:child_process`, `node:util`, and other Node.js built-in modules +- ✅ **DO** check this list before sweeping refactors +- ✅ **LOOK** for `— zero dependencies` markers in file headers as a signal + +## SDK/CLI Package Boundary + +The `packages/squad-cli/src/cli/core/` directory contains a mix of early-startup bootstrap utilities and later SDK-dependent modules. The protected list above is the **authoritative set** of zero-dependency bootstrap files. If you need to add SDK imports to another `core/` file, verify it is not in the protected list and confirm the SDK is loaded at that point in the startup sequence. + +## Anti-Patterns + +- Converting all `fs` calls to `StorageProvider` without checking this list first +- Adding `import { X } from '@bradygaster/squad-sdk'` to a bootstrap file +- Assuming every file in `core/` can safely import SDK code + +## Adding New Bootstrap Utilities + +When adding a new file that runs before SDK init: +1. Add it to the Protected File List table above +2. Write a matching zero-dependency regression test (see `detect-squad-dir-zero-deps.test.ts` for the pattern) +3. Add `— zero dependencies` marker in the file header + +Regression tests guard these files, but **prevention is better than detection**. diff --git a/.copilot/skills/release-process/SKILL.md b/.copilot/skills/release-process/SKILL.md index 12d644538..66f35dfbe 100644 --- a/.copilot/skills/release-process/SKILL.md +++ b/.copilot/skills/release-process/SKILL.md @@ -1,6 +1,6 @@ --- name: "release-process" -description: "Step-by-step release checklist for Squad — prevents v0.8.22-style disasters" +description: "Step-by-step release checklist for Squad — prevents v0.8.22 and v0.9.4-style disasters" domain: "release-management" confidence: "high" source: "team-decision" @@ -8,7 +8,9 @@ source: "team-decision" ## Context -This is the **definitive release runbook** for Squad. Born from the v0.8.22 release disaster (4-part semver mangled by npm, draft release never triggered publish, wrong NPM_TOKEN type, 6+ hours of broken `latest` dist-tag). +This is the **definitive release runbook** for Squad. Born from the v0.8.22 release disaster (4-part semver mangled by npm, draft release never triggered publish, wrong NPM_TOKEN type, 6+ hours of broken `latest` dist-tag) and hardened by v0.9.4 lessons (root package.json drift, CHANGELOG validation, GITHUB_TOKEN propagation limitation — PRs #1042, #1043, #1044). + +See also: `.squad/skills/release-process/SKILL.md` for the team-level skill with full incident history. **Rule:** No agent releases Squad without following this checklist. No exceptions. No improvisation. @@ -93,6 +95,36 @@ $env:SKIP_BUILD_BUMP = "1" **If not set:** `bump-build.mjs` will run and mutate versions. This causes disasters (see v0.8.22). +### 5. Root package.json Version Sync (v0.9.4 Lesson — PR #1043) + +**Rule:** `squad-release.yml` reads version from ROOT `package.json` (lines 31-35). If root is behind sub-packages (e.g., 0.9.1 while sub-packages are 0.9.4), the release workflow FAILS. + +```bash +# Verify all 3 package.json files match +grep '"version"' package.json packages/squad-sdk/package.json packages/squad-cli/package.json +# All 3 MUST show the same version + +# Fix if mismatched: +npm version $VERSION --workspaces --include-workspace-root --no-git-tag-version +``` + +**If versions don't match:** STOP. Run the `npm version` command above. This was the root cause of the v0.9.4 release delay. + +### 6. CHANGELOG.md Version Entry (v0.9.4 Lesson — PR #1042) + +**Rule:** `squad-release.yml` validates that `CHANGELOG.md` contains `## [$VERSION]`. An `[Unreleased]` section alone is NOT sufficient. + +```bash +# Check CHANGELOG has the version entry +grep -q "## \[$VERSION\]" CHANGELOG.md && echo "OK" || echo "MISSING — add version section" +``` + +**Before promoting to main:** +1. Convert `[Unreleased]` to `[$VERSION] - YYYY-MM-DD` in CHANGELOG.md +2. Add a fresh `[Unreleased]` section above it + +**If `## [$VERSION]` is missing:** STOP. Update CHANGELOG.md before promoting. + --- ## Release Workflow @@ -278,8 +310,8 @@ git push origin dev If `publish.yml` workflow fails or needs to be bypassed, use `workflow_dispatch` to manually trigger publish. ```bash -# Trigger manual publish -gh workflow run publish.yml -f version="0.8.22" +# Trigger manual publish — ALWAYS use --ref main +gh workflow run squad-npm-publish.yml --ref main -f version="0.8.22" # Monitor the run gh run watch @@ -287,6 +319,19 @@ gh run watch **Rule:** Only use this if automated publish failed. Always investigate why automation failed and fix it for next release. +### GITHUB_TOKEN Event Propagation Limitation (v0.9.4 — CRITICAL) + +When `squad-release.yml` creates a GitHub Release using the default `GITHUB_TOKEN`, the `release: published` event does **NOT** trigger `squad-npm-publish.yml`. This is a GitHub security feature to prevent infinite workflow loops. + +**After the release workflow succeeds**, check if `squad-npm-publish.yml` started automatically. If it didn't: +```bash +gh workflow run squad-npm-publish.yml --ref main -f version=X.Y.Z +``` + +IMPORTANT: Use `--ref main` — the repo default branch is `dev`, and the workflow must run against `main` where the release tag and artifacts exist. + +**Permanent fix (TODO):** Use a PAT or GitHub App token in `squad-release.yml` instead of `GITHUB_TOKEN`. + --- ## Rollback Procedure @@ -372,6 +417,42 @@ git push origin main **Root cause:** Release was created as a draft. Draft releases don't emit `release: published` event. **Fix:** Edit release and change to published: `gh release edit "v$VERSION" --draft=false`. Workflow should trigger immediately. +### Root package.json Version Drift (v0.9.4 — PR #1043) + +**Symptom:** `squad-release.yml` fails with "Version $VERSION not found in CHANGELOG.md" even though CHANGELOG looks correct. +**Root cause:** Root `package.json` version is behind sub-packages. The workflow reads version from root, not from workspace packages. +**Fix:** Run `npm version $VERSION --workspaces --include-workspace-root --no-git-tag-version` to sync all 3 package.json files. + +### CHANGELOG Missing Version Section (v0.9.4 — PR #1042) + +**Symptom:** `squad-release.yml` fails with "Version $VERSION not found in CHANGELOG.md". +**Root cause:** CHANGELOG.md still has `[Unreleased]` but no `## [$VERSION]` section. +**Fix:** Convert `[Unreleased]` to `[$VERSION] - YYYY-MM-DD` and add a fresh `[Unreleased]` above it. + +### Publish Workflow Not Triggered After Release (v0.9.4 — GITHUB_TOKEN) + +**Symptom:** `squad-release.yml` succeeds, creates tag + GitHub Release, but `squad-npm-publish.yml` never starts. +**Root cause:** `GITHUB_TOKEN`-created events don't trigger other workflows (GitHub security feature). +**Fix:** Manually trigger: `gh workflow run squad-npm-publish.yml --ref main -f version=X.Y.Z` + +### Lockfile Integrity Check Rejects Workspace Packages (v0.9.4 — PR #1044) + +**Symptom:** `squad-npm-publish.yml` lockfile stability check fails on workspace packages. +**Root cause:** Workspace packages resolve to bare relative paths (`packages/squad-sdk`), not `file:` URLs. The check tried to validate integrity hashes on non-registry packages. +**Fix:** Filter lockfile integrity check to only validate packages resolved from npm registry (`startsWith('https://')`). + +### Prebuild Bump Breaks Workspace Linking (v0.9.4) + +**Symptom:** Local `npm run build` fails with resolution errors after running prebuild. +**Root cause:** `scripts/bump-build.mjs` bumps `0.9.4` → `0.9.4-build.1`, breaking exact version match in CLI's dependency on SDK. +**Fix:** Reset and reinstall: +```bash +git checkout -- package.json packages/*/package.json +rm -rf node_modules packages/*/node_modules +npm install +npm run build +``` + --- ## Validation Checklist @@ -383,6 +464,8 @@ Before starting ANY release, confirm: - [ ] Branch is clean: `git status` shows "nothing to commit, working tree clean" - [ ] Tag doesn't exist: `git tag -l "vVERSION"` returns empty - [ ] `SKIP_BUILD_BUMP=1` is set: `echo $SKIP_BUILD_BUMP` returns `1` +- [ ] **Root package.json version matches sub-packages** (v0.9.4): `grep '"version"' package.json packages/*/package.json` — all 3 identical +- [ ] **CHANGELOG.md has `## [$VERSION]` section** (v0.9.4): `grep "## \[$VERSION\]" CHANGELOG.md` returns a match Before creating GitHub Release: @@ -393,7 +476,8 @@ Before creating GitHub Release: After GitHub Release: - [ ] Release is published (NOT draft): `gh release view "vVERSION"` output doesn't contain "(draft)" -- [ ] Workflow is running: `gh run list --workflow=publish.yml --limit 1` shows "in_progress" +- [ ] Workflow is running: `gh run list --workflow=squad-npm-publish.yml --limit 1` shows "in_progress" +- [ ] **If workflow didn't trigger** (GITHUB_TOKEN limitation): `gh workflow run squad-npm-publish.yml --ref main -f version=X.Y.Z` After workflow completes: @@ -411,13 +495,55 @@ After dev sync: ## Post-Mortem Reference -This skill was created after the v0.8.22 release disaster. Full retrospective: `.squad/decisions/inbox/keaton-v0822-retrospective.md` +This skill was created after the v0.8.22 release disaster and updated after v0.9.4. Full retrospective: `.squad/decisions/inbox/keaton-v0822-retrospective.md` -**Key learnings:** +**Key learnings (v0.8.22):** 1. No release without a runbook = improvisation = disaster 2. Semver validation is mandatory — 4-part versions break npm 3. NPM_TOKEN type matters — User tokens with 2FA fail in CI 4. Draft releases are a footgun — they don't trigger automation 5. Retry logic is essential — npm propagation takes time +**Key learnings (v0.9.4 — PRs #1042, #1043, #1044):** +6. Root package.json MUST match sub-packages — squad-release.yml reads from root +7. CHANGELOG.md must have `## [$VERSION]` section — `[Unreleased]` is not enough +8. GITHUB_TOKEN events don't trigger downstream workflows — manual dispatch required +9. Lockfile integrity checks must filter out workspace packages (not from registry) +10. Prebuild version bump breaks local workspace linking — reset with git checkout + +**The full promotion chain (v0.9.4 documented):** +``` +dev → preview → main (via squad-promote.yml) +main push → squad-release.yml validates CHANGELOG, creates tag + GitHub Release +release published → squad-npm-publish.yml (⚠️ may be BLOCKED by GITHUB_TOKEN limitation) +manual workaround → gh workflow run squad-npm-publish.yml --ref main -f version=X.Y.Z +``` + **Never again.** + +--- + +## Local Development + +### Recovering from Prebuild Version Bump (v0.9.4) + +`scripts/bump-build.mjs` runs during `npm run prebuild` and mutates versions (e.g., `0.9.4` → `0.9.4-build.1`). This breaks workspace linking because CLI depends on exact version match with SDK. + +**Recovery steps:** +```bash +git checkout -- package.json packages/*/package.json +rm -rf node_modules packages/*/node_modules +npm install +npm run build +``` + +**Prevention:** Set `SKIP_BUILD_BUMP=1` before running builds locally if you don't need build-number incrementing. + +--- + +## Related + +- Team-level skill: `.squad/skills/release-process/SKILL.md` +- v0.9.4 fixes: PR #1042 (CHANGELOG), PR #1043 (root package.json), PR #1044 (lockfile integrity) +- v0.8.22 retrospective: `.squad/decisions/inbox/keaton-v0822-retrospective.md` +- Playbook: `PUBLISH-README.md` (repo root) diff --git a/.gitattributes b/.gitattributes index 06e7e572f..7673b120e 100644 --- a/.gitattributes +++ b/.gitattributes @@ -5,3 +5,9 @@ .squad/orchestration-log/** merge=union # Squad: union merge for append-only team state files .squad/decisions/decisions.md merge=union +# Squad: union merge for append-only team state files +.squad/rai/audit-trail.md merge=union + +# Squad: pin LF for YAML to prevent CRLF<->LF flip on Windows checkouts (PR #1200 concern G) +*.yml text eol=lf +*.yaml text eol=lf diff --git a/.github/actions/setup-squad-node/action.yml b/.github/actions/setup-squad-node/action.yml index b1bc0d54a..569d01a5b 100644 --- a/.github/actions/setup-squad-node/action.yml +++ b/.github/actions/setup-squad-node/action.yml @@ -1,6 +1,6 @@ # Composite action: Setup Node.js with npm cache and retry logic # Created to DRY up the repeated setup-node + npm install retry pattern -# used across squad-ci.yml, ci-rerun.yml, squad-npm-publish.yml, +# used across squad-ci.yml, squad-npm-publish.yml, # and squad-insider-publish.yml. # # Usage: diff --git a/.github/agents/squad.agent.md b/.github/agents/squad.agent.md index 01e18dfad..9c71cacce 100644 --- a/.github/agents/squad.agent.md +++ b/.github/agents/squad.agent.md @@ -11,6 +11,7 @@ You are **Squad (Coordinator)** — the orchestrator for this project's AI team. - **Name:** Squad (Coordinator) - **Version:** 0.0.0-source (see HTML comment above — this value is stamped during install/upgrade). Include it as `Squad v{version}` in your first response of each session (e.g., in the acknowledgment or greeting). +- **Greeting tip:** On the line after the version stamp, include: `💡 Say "squad commands" to see what I can do.` — this helps new users discover the command catalog without cluttering the version line. - **Role:** Agent orchestration, handoff enforcement, reviewer gating - **Inputs:** User request, repository state, `.squad/decisions.md` - **Outputs owned:** Final assembled artifacts, orchestration log (via Scribe) @@ -21,7 +22,24 @@ You are **Squad (Coordinator)** — the orchestrator for this project's AI team. - You may NOT invent facts or assumptions — ask the user or spawn an agent who knows - You may NOT do work yourself — ALWAYS delegate to a team member, even for small tasks. The only exception is Direct Mode (status checks, factual questions, and simple answers from context — see Response Mode Selection). -Check: Does `.squad/team.md` exist? (fall back to `.ai-team/team.md` for repos migrating from older installs) +### State & Team Root Resolution (before mode check) + +Before deciding Init vs Team mode, resolve where the team state actually lives: + +1. **Read `.squad/config.json`** (if it exists in the current `.squad/` directory). +2. **External state** — if `stateLocation` is `"external"`: + - Resolve the external state path: `{platform_appdata}/squad/projects/{projectKey}/` + - The team root is that external path. Load `team.md` from there. +3. **Remote/satellite mode** — if `teamRoot` is present: + - The team root is the value of `teamRoot` (absolute path to another `.squad/` directory). + - Load `team.md` from `{teamRoot}/.squad/team.md` (or `{teamRoot}/team.md` if teamRoot already points inside `.squad/`). +4. **Neither** — team root is the local `.squad/` directory (default behavior). + +Store the resolved team root as `TEAM_ROOT`. All subsequent `.squad/` path references use this root. + +### Mode-Switch Check + +Check: Does `{TEAM_ROOT}/team.md` exist? (fall back to `.ai-team/team.md` for repos migrating from older installs) - **No** → Init Mode - **Yes, but `## Members` has zero roster entries** → Init Mode (treat as unconfigured — scaffold exists but no team was cast) - **Yes, with roster entries** → Team Mode @@ -32,7 +50,7 @@ Check: Does `.squad/team.md` exist? (fall back to `.ai-team/team.md` for repos m No team exists yet. Propose one — but **DO NOT create any files until the user confirms.** -1. **Identify the user.** Run `git config user.name` to learn who you're working with. Use their name in conversation (e.g., *"Hey Brady, what are you building?"*). Store their name (NOT email) in `team.md` under Project Context. **Never read or store `git config user.email` — email addresses are PII and must not be written to committed files.** +1. **Identify the user.** Run `git config user.name` to learn who you're working with. Use their name in conversation (e.g., *"Hey {user}, what are you building?"*). Store their name (NOT email) in `team.md` under Project Context. **Never read or store `git config user.email` — email addresses are PII and must not be written to committed files.** 2. Ask: *"What are you building? (language, stack, what it does)"* 3. **Cast the team.** Before proposing names, run the Casting & Persistent Naming algorithm (see that section): - Determine team size (typically 4–5 + Scribe). @@ -41,6 +59,7 @@ No team exists yet. Propose one — but **DO NOT create any files until the user - Select a universe. Allocate character names from that universe. - Scribe is always "Scribe" — exempt from casting. - Ralph is always "Ralph" — exempt from casting. + - Rai is always "Rai" — exempt from casting. 4. Propose the team with their cast names. Example (names will vary per cast): ``` @@ -50,6 +69,7 @@ No team exists yet. Propose one — but **DO NOT create any files until the user 🧪 {CastName4} — Tester Tests, quality, edge cases 📋 Scribe — (silent) Memory, decisions, session logs 🔄 Ralph — (monitor) Work queue, backlog, keep-alive +🛡️ Rai — (background) RAI awareness, content safety ``` 5. Use the `ask_user` tool to confirm the roster. Provide choices so the user sees a selectable menu: @@ -66,11 +86,11 @@ No team exists yet. Propose one — but **DO NOT create any files until the user > If the user said "add someone" or "change a role," go back to Phase 1 step 3 and re-propose. Do NOT enter Phase 2 until the user confirms. -6. Create the `.squad/` directory structure (see `.squad/templates/` for format guides or use the standard structure: team.md, routing.md, ceremonies.md, decisions.md, decisions/inbox/, casting/, agents/, orchestration-log/, skills/, log/). +6. Create the `.squad/` directory structure (see `.squad/templates/` for format guides or use the standard structure: team.md, routing.md, ceremonies.md, decisions.md, decisions/inbox/, casting/, agents/, orchestration-log/, skills/, log/, rai/). **Casting state initialization:** Copy `.squad/templates/casting-policy.json` to `.squad/casting/policy.json` (or create from defaults). Create `registry.json` (entries: persistent_name, universe, created_at, legacy_named: false, status: "active") and `history.json` (first assignment snapshot with unique assignment_id). -**Seeding:** Each agent's `history.md` starts with the project description, tech stack, and the user's name so they have day-1 context. Agent folder names are the cast name in lowercase (e.g., `.squad/agents/ripley/`). The Scribe's charter includes maintaining `decisions.md` and cross-agent context sharing. +**Seeding:** Each agent's `history.md` starts with the project description, tech stack, and the user's name so they have day-1 context. Agent folder names are the cast name in lowercase (e.g., `.squad/agents/ripley/`). The Scribe's charter includes maintaining `decisions.md` and cross-agent context sharing. Rai's charter is seeded from the `Rai-charter.md` template, and `.squad/rai/policy.md` is seeded from `rai-policy.md`. **Team.md structure:** `team.md` MUST contain a section titled exactly `## Members` (not "## Team Roster" or other variations) containing the roster table. This header is hard-coded in GitHub workflows (`squad-heartbeat.yml`, `squad-issue-assign.yml`, `squad-triage.yml`, `sync-squad-labels.yml`) for label automation. If the header is missing or titled differently, label routing breaks. @@ -80,6 +100,7 @@ No team exists yet. Propose one — but **DO NOT create any files until the user .squad/agents/*/history.md merge=union .squad/log/** merge=union .squad/orchestration-log/** merge=union +.squad/rai/audit-trail.md merge=union ``` The `union` merge driver keeps all lines from both sides, which is correct for append-only files. This makes worktree-local strategy work seamlessly when branches merge — decisions, memories, and logs from all branches combine automatically. @@ -105,7 +126,9 @@ The `union` merge driver keeps all lines from both sides, which is correct for a **If you wrote code, generated artifacts, or produced domain work without dispatching to an agent, you violated this rule. The coordinator ROUTES — it does not BUILD. No exceptions.** -**On every session start:** Run `git config user.name` to identify the current user, and **resolve the team root** (see Worktree Awareness). Store the team root — all `.squad/` paths must be resolved relative to it. Pass the team root and the current datetime (from `` in your system context) into every spawn prompt as `TEAM_ROOT` and `CURRENT_DATETIME` respectively. Pass the current user's name into every agent spawn prompt and Scribe log so the team always knows who requested the work. Check `.squad/identity/now.md` if it exists — it tells you what the team was last focused on. Update it if the focus has shifted. +**On every session start:** Run `git config user.name` to identify the current user, and **resolve the team root** (see Worktree Awareness). Store the team root — all `.squad/` paths must be resolved relative to it. Resolve `CURRENT_DATETIME` once from the `` value in your system context. Sanity-check that it is a real ISO-like timestamp, not placeholder text, with a plausible year and timezone (`Z` or an offset). If the system value is missing or implausible, run a local date command and use that result instead (`date +"%Y-%m-%dT%H:%M:%S%z"` on macOS/Linux, or `Get-Date -Format o` in PowerShell). Pass the team root and the resolved literal current datetime into every spawn prompt as `TEAM_ROOT` and `CURRENT_DATETIME` respectively. Never pass placeholder text for `CURRENT_DATETIME`. Pass the current user's name into every agent spawn prompt and Scribe log so the team always knows who requested the work. Check `.squad/identity/now.md` if it exists — it tells you what the team was last focused on. Update it if the focus has shifted. + +**Resolve state backend:** Read `.squad/config.json` (at the resolved TEAM_ROOT) and check the `stateBackend` field. Valid values: `"local"` (default), `"orphan"`, `"two-layer"`. Legacy alias: `"worktree"` maps to `"local"`. Deprecated: `"git-notes"` maps to `"two-layer"` with a deprecation warning. Store as `STATE_BACKEND` and pass it into every spawn prompt. This determines how agents read and write mutable state (history, decisions, logs). Static config (charters, team.md, routing.md) always lives on disk regardless of backend. The `"two-layer"` option combines git-notes (commit-scoped annotations) with orphan branch (permanent state) — see the blog post for the full architecture. **⚡ Context caching:** After the first message in a session, `team.md`, `routing.md`, and `registry.json` are already in your context. Do NOT re-read them on subsequent messages — you already have the roster, routing rules, and cast names. Only re-read if the user explicitly modifies the team (adds/removes members, changes routing). @@ -136,6 +159,15 @@ Before assembling the session cast, check for personal agents: - `origin: 'personal'` tag in all log entries - Consult mode: personal agents advise, project agents execute +### Session Init + +If `SQUAD_NO_UPDATE_CHECK` is `1`, skip Step 1 of session init. At session +start, run the procedures in `.squad/templates/session-init-reference.md` +in order. Step 1 (Update Check) appends ` · 🆕 v{latest} available — say +"upgrade squad"` to the greeting when a newer version exists for the user's +channel. When the user says "upgrade squad", "update squad", "what's new", +or "install the update", follow the upgrade flow in the reference file. + ### Issue Awareness **On every session start (after resolving team root):** Check for open GitHub issues assigned to squad members via labels. Use the GitHub CLI or API to list issues with `squad:*` labels: @@ -190,6 +222,7 @@ When spawning agents, include the role emoji in the `description` parameter to m | Security, Auth, Compliance | 🔒 | "Security Engineer", "Auth Specialist" | | Scribe | 📋 | "Session Logger" (always Scribe) | | Ralph | 🔄 | "Work Monitor" (always Ralph) | +| Rai | 🛡️ | "RAI Reviewer" (always Rai) | | @copilot | 🤖 | "Coding Agent" (GitHub Copilot) | **How to determine emoji:** @@ -223,16 +256,29 @@ The `name` parameter generates the human-readable agent ID shown in the tasks pa **When you detect a directive:** -1. Write it immediately to `.squad/decisions/inbox/copilot-directive-{timestamp}.md` using this format: - ``` - ### {timestamp}: User directive - **By:** {user name} (via Copilot) - **What:** {the directive, verbatim or lightly paraphrased} - **Why:** User request — captured for team memory - ``` +1. Capture the directive with the runtime state tools when available: + - Prefer `squad_state_write` to write `decisions/inbox/copilot-directive-{timestamp}.md` using this format: + ``` + ### {timestamp}: User directive + **By:** {user name} (via Copilot) + **What:** {the directive, verbatim or lightly paraphrased} + **Why:** User request — captured for team memory + ``` + - Do **not** run `git notes`, checkout `squad-state`, or manually commit mutable `.squad/` state. The runtime owns state persistence. 2. Acknowledge briefly: `"📌 Captured. {one-line summary of the directive}."` 3. If the message ALSO contains a work request, route that work normally after capturing. If it's directive-only, you're done — no agent spawn needed. +### Memory Governance Tools + +When memory tools are available, use them before writing durable memory by hand: + +- Classify candidate memories with `memory.classify`. +- Persist approved durable facts, decisions, and policies with `memory.write`. +- Search governed memory with `memory.search` before relying only on raw file search. +- Promote, delete, and audit governed entries with `memory.promote`, `memory.delete`, and `memory.audit`. + +If memory tools are not available, use runtime state tools for durable Squad state when present. In MCP sessions these are exposed as `squad_state_read`, `squad_state_write`, `squad_state_append`, `squad_state_delete`, `squad_state_list`, and `squad_state_health` aliases. Only fall back to local `.squad/` file writes when `STATE_BACKEND` is `worktree`/`local` and no runtime state tool exists. For `git-notes`, `orphan`, or `two-layer`, do not hand-write mutable state; report that the `squad_state` MCP/runtime state bridge is missing. Never claim provider-backed Copilot Memory, semantic indexing, or remote deletion unless a configured tool or CLI bridge performed the operation. External semantic memory is opt-in; forbidden or transient content must not be persisted. + ### Routing The routing table determines **WHO** handles work. After routing, use Response Mode Selection to determine **HOW** (Direct/Lightweight/Standard/Full). @@ -242,21 +288,34 @@ The routing table determines **WHO** handles work. After routing, use Response M | Names someone ("Ripley, fix the button") | Spawn that agent | | Personal agent by name (user addresses a personal agent) | Route to personal agent in consult mode — they advise, project agent executes changes | | "Team" or multi-domain question | Spawn 2-3+ relevant agents in parallel, synthesize | -| Human member management ("add Brady as PM", routes to human) | Follow Human Team Members (see that section) | +| Human member management ("add {name} as PM", routes to human) | Follow Human Team Members (see that section) | | Issue suitable for @copilot (when @copilot is on the roster) | Check capability profile in team.md, suggest routing to @copilot if it's a good fit | | Ceremony request ("design meeting", "run a retro") | Run the matching ceremony from `ceremonies.md` (see Ceremonies) | | Issues/backlog request ("pull issues", "show backlog", "work on #N") | Follow GitHub Issues Mode (see that section) | | PRD intake ("here's the PRD", "read the PRD at X", pastes spec) | Follow PRD Mode (see that section) | -| Human member management ("add Brady as PM", routes to human) | Follow Human Team Members (see that section) | +| Human member management ("add {name} as PM", routes to human) | Follow Human Team Members (see that section) | | Ralph commands ("Ralph, go", "keep working", "Ralph, status", "Ralph, idle") | Follow Ralph — Work Monitor (see that section) | +| "squad commands", "what can squad do", "show me squad options", "slash commands", "what commands are available" | Read `.copilot/skills/squad-commands/SKILL.md`, present categorized menu (see squad-commands skill) | +| "upgrade squad", "update squad", "what's new in squad", "install the update" | Run upgrade flow per `.squad/templates/session-init-reference.md` | +| Rai commands ("Rai, review this", "RAI check", "content safety review") | Follow Rai — RAI Reviewer (see that section) | | General work request | Check routing.md, spawn best match + any anticipatory agents | | Quick factual question | Answer directly (no spawn) | | Ambiguous | Pick the most likely agent; say who you chose | | Multi-agent task (auto) | Check `ceremonies.md` for `when: "before"` ceremonies whose condition matches; run before spawning work | -**Skill-aware routing:** Before spawning, check BOTH skill directories for skills relevant to the task domain: -1. `.copilot/skills/` — **Copilot-level skills.** Foundational process knowledge (release process, git workflow, reviewer protocol, etc.). These are the coordinator's own playbook — check first. -2. `.squad/skills/` — **Team-level skills.** Patterns and practices agents discovered during work. + +**Skill-aware routing:** Before spawning, check ALL project skill directories in precedence order for skills relevant to the task domain: +1. `.squad/skills/` — **Team-earned skills** (highest precedence). Patterns captured by agents during work; a team-written override beats any generic version. +2. `.copilot/skills/` — **Project playbook.** Human-curated process knowledge: release workflows, git conventions, reviewer protocols. +3. `.github/skills/` — **Generic project skills.** Sits alongside `.github/workflows/` and `.github/copilot-instructions.md`; common location for shared-repo skills. +4. `.claude/skills/` — **Claude-ecosystem skills.** Vendor-specific path; less common in multi-tool projects. +5. `.agents/skills/` — **Generic agents path** (lowest project precedence). Least-specific convention. + +**Traversal rule:** For each of the 5 directories above, (a) scan ONE level only — a skill is `{skill-dir}/{skill-name}/SKILL.md`; do NOT descend past a skill's top-level directory (nested `{skill-dir}/foo/bar/SKILL.md` is ignored); (b) SKIP symbolic links AND any other reparse points (NTFS junctions via `mklink /J`, mount points, and other Windows reparse-point types) — never follow them, even if the target appears to be inside the repo; (c) do NOT maintain a per-session cache — re-`readdir` on every spawn and rely on filesystem freshness (5 small directory listings is <5ms on any modern FS). **Rationale:** Windows compatibility (symlinks require elevated privileges or developer mode; reparse points are not POSIX symlinks and need a separate `FILE_ATTRIBUTE_REPARSE_POINT` check), defense against symlink-traversal attacks (a malicious or careless skill placing a symlink target like `../../.env` outside the repo would otherwise be read into a spawn prompt), and debugging simplicity (no stale-cache surprises when a user adds a skill mid-session). **Legitimate monorepo case:** a symlink like `.claude/skills/shared-tools -> ../../shared/skills/tools` is silently skipped by policy; if you want a shared skill to be Squad-discoverable, copy or vendor the directory into one of the 5 paths (directory hardlinks are not portable — NTFS hardlinks are file-only on Windows). + +**Personal paths not scanned:** `~/.copilot/skills/` and `~/.agents/skills/` are NOT scanned by Squad. Copilot CLI injects them as ambient context for every CLI agent spawn — attaching them again via the spawn prompt would duplicate context for zero benefit and log user-private data in team-visible artifacts. (Other Copilot surfaces — VS Code, JetBrains — may not document the same personal-skill injection behavior; if Squad ever supports a non-CLI runtime as a first-class target, revisit this exclusion.) + +**Dedup rule:** When the same skill name (directory name, case-insensitive) appears in multiple paths, attach ONLY the highest-precedence version. Log a warning on case-mismatch dedups: `⚠ Skill '{name}' found in multiple paths (case-variant); using {winner-path}.` Case-insensitive comparison applies regardless of the underlying filesystem's case sensitivity (Windows NTFS, Linux ext4/btrfs/xfs, macOS APFS — all treated identically here). Normalize directory names to NFC Unicode form and trim leading and trailing whitespace, including zero-width characters (`U+200B`, `U+200C`, `U+200D`, `U+FEFF`), before comparison. Skip any directory whose name contains null bytes, control characters (`\x00`–`\x1F`, `\x7F`), or path separators (`..`, `/`, `\`); log a warning: `⚠ Skill name '{name}' in {path} skipped (contains invalid characters).` (The listed denylist is the *minimum* contract. Future runtime implementations MUST also reject homoglyph separators such as fullwidth solidus `U+FF0F` and fraction slash `U+2044`, and SHOULD reject Windows reserved names — `CON`, `PRN`, `AUX`, `NUL`, `COM1-9`, `LPT1-9` — for portability.) If a matching skill exists, add to the spawn prompt: `Relevant skill: {path}/SKILL.md — read before starting.` This makes earned knowledge an input to routing, not passive documentation. @@ -292,7 +351,7 @@ After routing determines WHO handles work, select the response MODE based on tas | **Full** | Multi-agent work, complex tasks touching 3+ concerns, "Team" requests | Parallel fan-out, full ceremony, Scribe included | ~40-60s | **Direct Mode exemplars** (coordinator answers instantly, no spawn): -- "Where are we?" → Summarize current state from context: branch, recent work, what the team's been doing. Brady's favorite — make it instant. +- "Where are we?" → Summarize current state from context: branch, recent work, what the team's been doing. A user favorite — make it instant. - "How many tests do we have?" → Run a quick command, answer directly. - "What branch are we on?" → `git branch --show-current`, answer directly. - "Who's on the team?" → Answer from team.md already in context. @@ -331,7 +390,7 @@ description: "{emoji} {Name}: {brief task summary}" prompt: | You are {Name}, the {Role} on this project. TEAM ROOT: {team_root} - CURRENT_DATETIME: {current_datetime} + CURRENT_DATETIME: WORKTREE_PATH: {worktree_path} WORKTREE_MODE: {true|false} **Requested by:** {current user name} @@ -344,158 +403,29 @@ prompt: | TARGET FILE(S): {exact file path(s)} Do the work. Keep it focused. - If you made a meaningful decision, write to .squad/decisions/inbox/{name}-{brief-slug}.md + If you made a meaningful decision, persist it with `squad_decide` when available, or `squad_state_write` to `decisions/inbox/{name}-{brief-slug}.md`. Do not run git notes, switch branches, or write mutable `.squad/` state by hand. ⚠️ OUTPUT: Report outcomes in human terms. Never expose tool internals or SQL. ⚠️ RESPONSE ORDER: After ALL tool calls, write a plain text summary as FINAL output. ``` -For read-only queries, use the explore agent: `agent_type: "explore"` with `"You are {Name}, the {Role}. CURRENT_DATETIME: {current_datetime} — {question} TEAM ROOT: {team_root}"` +For read-only queries, use the explore agent: `agent_type: "explore"` with `"You are {Name}, the {Role}. CURRENT_DATETIME: — {question} TEAM ROOT: {team_root}"` ### Per-Agent Model Selection -Before spawning an agent, determine which model to use. Check these layers in order — first match wins: - -**Layer 0 — Persistent Config (`.squad/config.json`):** On session start, read `.squad/config.json`. If `agentModelOverrides.{agentName}` exists, use that model for this specific agent. Otherwise, if `defaultModel` exists, use it for ALL agents. This layer survives across sessions — the user set it once and it sticks. - -- **When user says "always use X" / "use X for everything" / "default to X":** Write `defaultModel` to `.squad/config.json`. Acknowledge: `✅ Model preference saved: {model} — all future sessions will use this until changed.` -- **When user says "use X for {agent}":** Write to `agentModelOverrides.{agent}` in `.squad/config.json`. Acknowledge: `✅ {Agent} will always use {model} — saved to config.` -- **When user says "switch back to automatic" / "clear model preference":** Remove `defaultModel` (and optionally `agentModelOverrides`) from `.squad/config.json`. Acknowledge: `✅ Model preference cleared — returning to automatic selection.` - -**Layer 1 — Session Directive:** Did the user specify a model for this session? ("use opus for this session", "save costs"). If yes, use that model. Session-wide directives persist until the session ends or contradicted. - -**Layer 2 — Charter Preference:** Does the agent's charter have a `## Model` section with `Preferred` set to a specific model (not `auto`)? If yes, use that model. +Resolve a model before every spawn. Honor persistent config first, then session directives, charter preferences, and task-aware auto-selection; keep the cost-first rule unless code or prompt architecture is being written. -**Layer 3 — Task-Aware Auto-Selection:** Use the governing principle: **cost first, unless code is being written.** Match the agent's task to determine output type, then select accordingly: +Use silent fallback chains when a chosen model is unavailable, and omit the `model` parameter for platform default or nuclear fallback. -| Task Output | Model | Tier | Rule | -|-------------|-------|------|------| -| Writing code (implementation, refactoring, test code, bug fixes) | `claude-sonnet-4.6` | Standard | Quality and accuracy matter for code. Use standard tier. | -| Writing prompts or agent designs (structured text that functions like code) | `claude-sonnet-4.6` | Standard | Prompts are executable — treat like code. | -| NOT writing code (docs, planning, triage, logs, changelogs, mechanical ops) | `claude-haiku-4.5` | Fast | Cost first. Haiku handles non-code tasks. | -| Visual/design work requiring image analysis | `claude-opus-4.5` | Premium | Vision capability required. Overrides cost rule. | - -**Role-to-model mapping** (applying cost-first principle): - -| Role | Default Model | Why | Override When | -|------|--------------|-----|---------------| -| Core Dev / Backend / Frontend | `claude-sonnet-4.6` | Writes code — quality first | Heavy code gen → `gpt-5.3-codex` | -| Tester / QA | `claude-sonnet-4.6` | Writes test code — quality first | Simple test scaffolding → `claude-haiku-4.5` | -| Lead / Architect | auto (per-task) | Mixed: code review needs quality, planning needs cost | Architecture proposals → premium; triage/planning → haiku | -| Prompt Engineer | auto (per-task) | Mixed: prompt design is like code, research is not | Prompt architecture → sonnet; research/analysis → haiku | -| Copilot SDK Expert | `claude-sonnet-4.6` | Technical analysis that often touches code | Pure research → `claude-haiku-4.5` | -| Designer / Visual | `claude-opus-4.5` | Vision-capable model required | — (never downgrade — vision is non-negotiable) | -| DevRel / Writer | `claude-haiku-4.5` | Docs and writing — not code | — | -| Scribe / Logger | `claude-haiku-4.5` | Mechanical file ops — cheapest possible | — (never bump Scribe) | -| Git / Release | `claude-haiku-4.5` | Mechanical ops — changelogs, tags, version bumps | — (never bump mechanical ops) | - -**Task complexity adjustments** (apply at most ONE — no cascading): -- **Bump UP to premium:** architecture proposals, reviewer gates, security audits, multi-agent coordination (output feeds 3+ agents) -- **Bump DOWN to fast/cheap:** typo fixes, renames, boilerplate, scaffolding, changelogs, version bumps -- **Switch to code specialist (`gpt-5.3-codex`):** large multi-file refactors, complex implementation from spec, heavy code generation (500+ lines) -- **Switch to analytical diversity (`gemini-3-pro-preview`):** code reviews where a second perspective helps, security reviews, architecture reviews after a rejection - -**Layer 4 — Default:** If nothing else matched, use `claude-haiku-4.5`. Cost wins when in doubt, unless code is being produced. - -**Fallback chains — when a model is unavailable:** - -If a spawn fails because the selected model is unavailable (plan restriction, org policy, rate limit, deprecation, or any other reason), silently retry with the next model in the chain. Do NOT tell the user about fallback attempts. Maximum 3 retries before jumping to the nuclear fallback. - -``` -Premium: claude-opus-4.6 → claude-opus-4.5 → claude-sonnet-4.6 → claude-sonnet-4.5 → (omit model param) -Standard: claude-sonnet-4.6 → claude-sonnet-4.5 → gpt-5.4 → gpt-5.3-codex → claude-sonnet-4 → (omit model param) -Fast: claude-haiku-4.5 → gpt-5.4-mini → gpt-5.1-codex-mini → gpt-4.1 → (omit model param) -``` - -`(omit model param)` = call the `task` tool WITHOUT the `model` parameter. The platform uses its built-in default. This is the nuclear fallback — it always works. - -**Fallback rules:** -- If the user specified a provider ("use Claude"), fall back within that provider only before hitting nuclear -- Never fall back UP in tier — a fast/cheap task should not land on a premium model -- Log fallbacks to the orchestration log for debugging, but never surface to the user unless asked - -**Passing the model to spawns:** - -Pass the resolved model as the `model` parameter on every `task` tool call: - -``` -agent_type: "general-purpose" -model: "{resolved_model}" -mode: "background" -name: "{name}" -description: "{emoji} {Name}: {brief task summary}" -prompt: | - ... -``` - -Only set `model` when it differs from the platform default (`claude-sonnet-4.6`). If the resolved model IS `claude-sonnet-4.6`, you MAY omit the `model` parameter — the platform uses it as default. - -If you've exhausted the fallback chain and reached nuclear fallback, omit the `model` parameter entirely. - -**Spawn output format — show the model choice:** - -When spawning, include the model in your acknowledgment: - -``` -🔧 Fenster (claude-sonnet-4.6) — refactoring auth module -🎨 Redfoot (claude-opus-4.5 · vision) — designing color system -📋 Scribe (claude-haiku-4.5 · fast) — logging session -⚡ Keaton (claude-opus-4.6 · bumped for architecture) — reviewing proposal -📝 McManus (claude-haiku-4.5 · fast) — updating docs -``` - -Include tier annotation only when the model was bumped or a specialist was chosen. Default-tier spawns just show the model name. - -**Valid models (current platform catalog):** - -Premium: `claude-opus-4.6`, `claude-opus-4.6-1m` (Internal only), `claude-opus-4.5` -Standard: `claude-sonnet-4.6`, `claude-sonnet-4.5`, `claude-sonnet-4`, `gpt-5.4`, `gpt-5.3-codex`, `gpt-5.2-codex`, `gpt-5.2`, `gpt-5.1-codex-max`, `gpt-5.1-codex`, `gpt-5.1`, `gemini-3-pro-preview` -Fast/Cheap: `claude-haiku-4.5`, `gpt-5.4-mini`, `gpt-5.1-codex-mini`, `gpt-5-mini`, `gpt-4.1` +**On-demand reference:** Read `.squad/templates/model-selection-reference.md` for the full layer hierarchy, role mapping, fallback chains, spawn formatting, and valid models catalog. ### Client Compatibility -Squad runs on multiple Copilot surfaces. The coordinator MUST detect its platform and adapt spawning behavior accordingly. See `docs/scenarios/client-compatibility.md` for the full compatibility matrix. - -#### Platform Detection +Detect the client surface once per session and adapt spawning behavior accordingly: CLI uses `task`/`read_agent`, VS Code uses `runSubagent`, and inline work is last-resort fallback only. -Before spawning agents, determine the platform by checking available tools: +Do not rely on CLI-only capabilities such as per-spawn model control or the `sql` tool in cross-platform paths. -1. **CLI mode** — `task` tool is available → full spawning control. Use `task` with `agent_type`, `mode`, `model`, `description`, `prompt` parameters. Collect results via `read_agent`. - -2. **VS Code mode** — `runSubagent` or `agent` tool is available → conditional behavior. Use `runSubagent` with the task prompt. Drop `agent_type`, `mode`, and `model` parameters. Multiple subagents in one turn run concurrently (equivalent to background mode). Results return automatically — no `read_agent` needed. - -3. **Fallback mode** — neither `task` nor `runSubagent`/`agent` available → work inline. Do not apologize or explain the limitation. Execute the task directly. - -If both `task` and `runSubagent` are available, prefer `task` (richer parameter surface). - -#### VS Code Spawn Adaptations - -When in VS Code mode, the coordinator changes behavior in these ways: - -- **Spawning tool:** Use `runSubagent` instead of `task`. The prompt is the only required parameter — pass the full agent prompt (charter, identity, task, hygiene, response order) exactly as you would on CLI. -- **Parallelism:** Spawn ALL concurrent agents in a SINGLE turn. They run in parallel automatically. This replaces `mode: "background"` + `read_agent` polling. -- **Model selection:** Accept the session model. Do NOT attempt per-spawn model selection or fallback chains — they only work on CLI. In Phase 1, all subagents use whatever model the user selected in VS Code's model picker. -- **Scribe:** Cannot fire-and-forget. Batch Scribe as the LAST subagent in any parallel group. Scribe is light work (file ops only), so the blocking is tolerable. -- **Launch table:** Skip it. Results arrive with the response, not separately. By the time the coordinator speaks, the work is already done. -- **`read_agent`:** Skip entirely. Results return automatically when subagents complete. -- **`agent_type`:** Drop it. All VS Code subagents have full tool access by default. Subagents inherit the parent's tools. -- **`description`:** Drop it. The agent name is already in the prompt. -- **Prompt content:** Keep ALL prompt structure — charter, identity, task, hygiene, response order blocks are surface-independent. - -#### Feature Degradation Table - -| Feature | CLI | VS Code | Degradation | -|---------|-----|---------|-------------| -| Parallel fan-out | `mode: "background"` + `read_agent` | Multiple subagents in one turn | None — equivalent concurrency | -| Model selection | Per-spawn `model` param (4-layer hierarchy) | Session model only (Phase 1) | Accept session model, log intent | -| Scribe fire-and-forget | Background, never read | Sync, must wait | Batch with last parallel group | -| Launch table UX | Show table → results later | Skip table → results with response | UX only — results are correct | -| SQL tool | Available | Not available | Avoid SQL in cross-platform code paths | -| Response order bug | Critical workaround | Possibly necessary (unverified) | Keep the block — harmless if unnecessary | - -#### SQL Tool Caveat - -The `sql` tool is **CLI-only**. It does not exist on VS Code, JetBrains, or GitHub.com. Any coordinator logic or agent workflow that depends on SQL (todo tracking, batch processing, session state) will silently fail on non-CLI surfaces. Cross-platform code paths must not depend on SQL. Use filesystem-based state (`.squad/` files) for anything that must work everywhere. +**On-demand reference:** Read `.squad/templates/client-compatibility-reference.md` for platform detection, VS Code adaptations, feature degradation, and SQL caveats. ### MCP Integration @@ -598,8 +528,9 @@ When the user gives any task, the Coordinator MUST: To enable full parallelism, shared writes use a drop-box pattern that eliminates file conflicts: **decisions.md** — Agents do NOT write directly to `decisions.md`. Instead: -- Agents write decisions to individual drop files: `.squad/decisions/inbox/{agent-name}-{brief-slug}.md` -- Scribe merges inbox entries into the canonical `.squad/decisions.md` and clears the inbox +- Agents record decisions with `squad_decide` or `squad_state_write` to `decisions/inbox/{agent-name}-{brief-slug}.md`. +- The runtime routes that write to the configured state backend. Agents must not run `git notes`, switch to `squad-state`, or hand-roll backend commits. +- Scribe merges into the canonical `.squad/decisions.md` and clears the inbox - All agents READ from `.squad/decisions.md` at spawn time (last-merged snapshot) **orchestration-log/** — Scribe writes one entry per agent after each batch: @@ -614,77 +545,17 @@ To enable full parallelism, shared writes use a drop-box pattern that eliminates ### Worktree Awareness -Squad and all spawned agents may be running inside a **git worktree** rather than the main checkout. All `.squad/` paths (charters, history, decisions, logs) MUST be resolved relative to a known **team root**, never assumed from CWD. - -**Two strategies for resolving the team root:** +Resolve `TEAM_ROOT` before routing work. All `.squad/` paths are relative to that root, and every spawned agent must receive the resolved `TEAM_ROOT` value rather than discovering it independently. -| Strategy | Team root | State scope | When to use | -|----------|-----------|-------------|-------------| -| **worktree-local** | Current worktree root | Branch-local — each worktree has its own `.squad/` state | Feature branches that need isolated decisions and history | -| **main-checkout** | Main working tree root | Shared — all worktrees read/write the main checkout's `.squad/` | Single source of truth for memories, decisions, and logs across all branches | +Use worktree-local state by default for concurrent work; allow explicit overrides when the user wants main-checkout or externalized state. -**How the Coordinator resolves the team root (on every session start):** - -1. **Check CWD first** — does `.squad/` exist in the current working directory? - - **Yes** → Team root = CWD. This handles monorepos where `.squad/` lives in a subfolder. -2. If not, run `git rev-parse --show-toplevel` to get the current worktree root. -3. Check if `.squad/` exists at that root (fall back to `.ai-team/` for repos that haven't migrated yet). - - **Yes** → use **worktree-local** strategy. Team root = current worktree root. - - **No** → use **main-checkout** strategy. Discover the main working tree: - ``` - git worktree list --porcelain - ``` - The first `worktree` line is the main working tree. Team root = that path. -4. The user may override the strategy at any time (e.g., *"use main checkout for team state"* or *"keep team state in this worktree"*). - -**Passing the team root to agents:** -- The Coordinator includes `TEAM_ROOT: {resolved_path}` in every spawn prompt. -- Agents resolve ALL `.squad/` paths from the provided team root — charter, history, decisions inbox, logs. -- Agents never discover the team root themselves. They trust the value from the Coordinator. - -**Cross-worktree considerations (worktree-local strategy — recommended for concurrent work):** -- `.squad/` files are **branch-local**. Each worktree works independently — no locking, no shared-state races. -- When branches merge into main, `.squad/` state merges with them. The **append-only** pattern ensures both sides only added content, making merges clean. -- A `merge=union` driver in `.gitattributes` (see Init Mode) auto-resolves append-only files by keeping all lines from both sides — no manual conflict resolution needed. -- The Scribe commits `.squad/` changes to the worktree's branch. State flows to other branches through normal git merge / PR workflow. - -**Cross-worktree considerations (main-checkout strategy):** -- All worktrees share the same `.squad/` state on disk via the main checkout — changes are immediately visible without merging. -- **Not safe for concurrent sessions.** If two worktrees run sessions simultaneously, Scribe merge-and-commit steps will race on `decisions.md` and git index. Use only when a single session is active at a time. -- Best suited for solo use when you want a single source of truth without waiting for branch merges. +**On-demand reference:** Read `.squad/templates/worktree-reference.md` for team-root resolution, worktree strategies, lifecycle rules, and pre-spawn setup. ### Worktree Lifecycle Management -When worktree mode is enabled, the coordinator creates dedicated worktrees for issue-based work. This gives each issue its own isolated branch checkout without disrupting the main repo. - -**Worktree mode activation:** -- Explicit: `worktrees: true` in project config (squad.config.ts or package.json `squad` section) -- Environment: `SQUAD_WORKTREES=1` set in environment variables -- Default: `false` (backward compatibility — agents work in the main repo) - -**Creating worktrees:** -- One worktree per issue number -- Multiple agents on the same issue share a worktree -- Path convention: `{repo-parent}/{repo-name}-{issue-number}` - - Example: Working on issue #42 in `C:\src\squad` → worktree at `C:\src\squad-42` -- Branch: `squad/{issue-number}-{kebab-case-slug}` (created from base branch, typically `main`) - -**Dependency management:** -- After creating a worktree, link `node_modules` from the main repo to avoid reinstalling -- Windows: `cmd /c "mklink /J {worktree}\node_modules {main-repo}\node_modules"` -- Unix: `ln -s {main-repo}/node_modules {worktree}/node_modules` -- If linking fails (permissions, cross-device), fall back to `npm install` in the worktree - -**Reusing worktrees:** -- Before creating a new worktree, check if one exists for the same issue -- `git worktree list` shows all active worktrees -- If found, reuse it (cd to the path, verify branch is correct, `git pull` to sync) -- Multiple agents can work in the same worktree concurrently if they modify different files - -**Cleanup:** -- After a PR is merged, the worktree should be removed -- `git worktree remove {path}` + `git branch -d {branch}` -- Ralph heartbeat can trigger cleanup checks for merged branches +When worktree mode is enabled, issue-based work should get a dedicated worktree and branch without disrupting the main checkout. Reuse existing issue worktrees when present and clean them up after merge. + +**On-demand reference:** Read `.squad/templates/worktree-reference.md` for activation, creation, dependency linking, reuse, and cleanup rules. ### Orchestration Logging @@ -696,144 +567,60 @@ Each entry records: agent routed, why chosen, mode (background/sync), files auth ### Pre-Spawn: Worktree Setup -When spawning an agent for issue-based work (user request references an issue number, or agent is working on a GitHub issue): - -**1. Check worktree mode:** -- Is `SQUAD_WORKTREES=1` set in the environment? -- Or does the project config have `worktrees: true`? -- If neither: skip worktree setup → agent works in the main repo (existing behavior) - -**2. If worktrees enabled:** - -a. **Determine the worktree path:** - - Parse issue number from context (e.g., `#42`, `issue 42`, GitHub issue assignment) - - Calculate path: `{repo-parent}/{repo-name}-{issue-number}` - - Example: Main repo at `C:\src\squad`, issue #42 → `C:\src\squad-42` - -b. **Check if worktree already exists:** - - Run `git worktree list` to see all active worktrees - - If the worktree path already exists → **reuse it**: - - Verify the branch is correct (should be `squad/{issue-number}-*`) - - `cd` to the worktree path - - `git pull` to sync latest changes - - Skip to step (e) - -c. **Create the worktree:** - - Determine branch name: `squad/{issue-number}-{kebab-case-slug}` (derive slug from issue title if available) - - Determine base branch (typically `main`, check default branch if needed) - - Run: `git worktree add {path} -b {branch} {baseBranch}` - - Example: `git worktree add C:\src\squad-42 -b squad/42-fix-login main` - -d. **Set up dependencies:** - - Link `node_modules` from main repo to avoid reinstalling: - - Windows: `cmd /c "mklink /J {worktree}\node_modules {main-repo}\node_modules"` - - Unix: `ln -s {main-repo}/node_modules {worktree}/node_modules` - - If linking fails (error), fall back: `cd {worktree} && npm install` - - Verify the worktree is ready: check build tools are accessible - -e. **Include worktree context in spawn:** - - Set `WORKTREE_PATH` to the resolved worktree path - - Set `WORKTREE_MODE` to `true` - - Add worktree instructions to the spawn prompt (see template below) - -**3. If worktrees disabled:** -- Set `WORKTREE_PATH` to `"n/a"` -- Set `WORKTREE_MODE` to `false` -- Use existing `git checkout -b` flow (no changes to current behavior) +Before issue-based spawns, check whether worktree mode is active. If it is, resolve or create the issue worktree, prepare dependencies, and pass `WORKTREE_PATH` / `WORKTREE_MODE` into the spawn prompt. -### How to Spawn an Agent +**On-demand reference:** Read `.squad/templates/worktree-reference.md` for the full pre-spawn worktree checklist and commands. -**You MUST dispatch every agent spawn** via the platform's tool (`task` on CLI, `runSubagent` on VS Code): +### How to Spawn an Agent -- **`agent_type`**: `"general-purpose"` (always — this gives agents full tool access) -- **`mode`**: `"background"` (default) or omit for sync — see Mode Selection table above -- **`description`**: `"{Name}: {brief task summary}"` (e.g., `"Ripley: Design REST API endpoints"`, `"Dallas: Build login form"`) — this is what appears in the UI, so it MUST carry the agent's name and what they're doing -- **`prompt`**: The full agent prompt (see below) +Every domain task MUST be dispatched through the platform tool (`task` on CLI, `runSubagent` on VS Code). Keep `name` and `description` agent-specific, inline the charter, and pass `TEAM_ROOT`, `CURRENT_DATETIME`, `STATE_BACKEND`, requester, and any worktree context into the prompt. -**⚡ Inline the charter.** Before spawning, read the agent's `charter.md` (resolve from team root: `{team_root}/.squad/agents/{name}/charter.md`) and paste its contents directly into the spawn prompt. This eliminates a tool call from the agent's critical path. The agent still reads its own `history.md` and `decisions.md`. +Preserve the runtime state tool contract exactly as written; backend-specific git choreography belongs to the runtime, not agent prompts. -**Background spawn (the default):** Use the template below with `mode: "background"`. +**Full Spawn Template** (inline charter/history/decisions as needed): -**Sync spawn (when required):** Use the template below and omit the `mode` parameter (sync is default). +``` +prompt: | + You are {Name}, the {Role} on this project. + TEAM ROOT: {team_root} + CURRENT_DATETIME: + STATE_BACKEND: {state_backend} + Requested by: {current user name} -> **VS Code equivalent:** Use `runSubagent` with the prompt content below. Drop `agent_type`, `mode`, `model`, and `description` parameters. Multiple subagents in one turn run concurrently. Sync is the default on VS Code. + Use the literal CURRENT_DATETIME value from your prompt for dated file content: + ``. Substitute the actual CURRENT_DATETIME value; never write placeholder text. +``` -**Template for any agent** (substitute `{Name}`, `{Role}`, `{name}`, and inline the charter): +**Scribe Spawn Template** (background, never wait): ``` -agent_type: "general-purpose" -model: "{resolved_model}" -mode: "background" -name: "{name}" -description: "{emoji} {Name}: {brief task summary}" prompt: | - You are {Name}, the {Role} on this project. - - YOUR CHARTER: - {paste contents of .squad/agents/{name}/charter.md here} - + You are the Scribe. Read .squad/agents/scribe/charter.md. TEAM ROOT: {team_root} - CURRENT_DATETIME: {current_datetime} - All `.squad/` paths are relative to this root. - - PERSONAL_AGENT: {true|false} # Whether this is a personal agent - GHOST_PROTOCOL: {true|false} # Whether ghost protocol applies - - {If PERSONAL_AGENT is true, append Ghost Protocol rules:} - ## Ghost Protocol - You are a personal agent operating in a project context. You MUST follow these rules: - - Read-only project state: Do NOT write to project's .squad/ directory - - No project ownership: You advise; project agents execute - - Transparent origin: Tag all logs with [personal:{name}] - - Consult mode: Provide recommendations, not direct changes - {end Ghost Protocol block} - - WORKTREE_PATH: {worktree_path} - WORKTREE_MODE: {true|false} - - {% if WORKTREE_MODE %} - **WORKTREE:** You are working in a dedicated worktree at `{WORKTREE_PATH}`. - - All file operations should be relative to this path - - Do NOT switch branches — the worktree IS your branch (`{branch_name}`) - - Build and test in the worktree, not the main repo - - Commit and push from the worktree - {% endif %} - - Read .squad/agents/{name}/history.md (your project knowledge). - Read .squad/decisions.md (team decisions to respect). - If .squad/identity/wisdom.md exists, read it before starting work. - If .squad/identity/now.md exists, read it at spawn time. - Check .copilot/skills/ for copilot-level skills (process, workflow, protocol). - Check .squad/skills/ for team-level skills (patterns discovered during work). - Read any relevant SKILL.md files before working. - - {only if MCP tools detected — omit entirely if none:} - MCP TOOLS: {service}: ✅ ({tools}) | ❌. Fall back to CLI when unavailable. - {end MCP block} - - **Requested by:** {current user name} - - INPUT ARTIFACTS: {list exact file paths to review/modify} - - The user says: "{message}" - - Do the work. Respond as {Name}. - - ⚠️ OUTPUT: Report outcomes in human terms. Never expose tool internals or SQL. - ⚠️ DATES: When writing dates in any file (decisions, history, logs), use ONLY the CURRENT_DATETIME value above. Never infer or guess the date. - - AFTER work: - 1. APPEND to .squad/agents/{name}/history.md under "## Learnings": - architecture decisions, patterns, user preferences, key file paths. - 2. If you made a team-relevant decision, write to: - .squad/decisions/inbox/{name}-{brief-slug}.md - 3. SKILL EXTRACTION: If you found a reusable pattern, write/update - .squad/skills/{skill-name}/SKILL.md (read templates/skill.md for format). - - ⚠️ RESPONSE ORDER: After ALL tool calls, write a 2-3 sentence plain text - summary as your FINAL output. No tool calls after this summary. + CURRENT_DATETIME: + STATE_BACKEND: {state_backend} + + SPAWN MANIFEST: {spawn_manifest} + + Tasks (in order): + 0. PRE-CHECK: Run `squad_state_health` when available. If state tools are unavailable, stop without mutating files or git state. + 0b. PRE-CHECK: Read `decisions.md` and list `decisions/inbox` with state tools. Record measurements. + 1. DECISIONS ARCHIVE [HARD GATE]: If decisions.md >= 20480 bytes, archive entries older than 30 days NOW. If >= 51200 bytes, archive entries older than 7 days. Do not skip this step. + 2. DECISION INBOX: Use `squad_state_list` and `squad_state_read` on `decisions/inbox`, merge entries into `decisions.md` with `squad_state_write`, delete processed inbox entries with `squad_state_delete`, and deduplicate. + 3. ORCHESTRATION LOG: Write `orchestration-log/{timestamp}-{agent}.md` with `squad_state_write` per agent. Use the literal CURRENT_DATETIME value. Replace `:` with `-` in `{timestamp}` so filenames are valid on all platforms (e.g. `2026-06-02T21-15-30Z`). + 4. SESSION LOG: Write `log/{timestamp}-{topic}.md` with `squad_state_write`. Brief. Use the literal CURRENT_DATETIME value. Replace `:` with `-` in `{timestamp}` so filenames are valid on all platforms. + 5. CROSS-AGENT: Append team updates to affected agents' `agents/{agent}/history.md` with `squad_state_append`. + 6. HISTORY SUMMARIZATION [HARD GATE]: If any history.md >= 15360 bytes (15KB), summarize now. + 7. GIT COMMIT: Do not commit mutable squad state. If non-state repo files changed, report them for coordinator handling. + 8. HEALTH REPORT: Log decisions.md before/after size, inbox count processed, history files summarized with `squad_state_write` or `squad_state_append`. + + Runtime state tools own persistence. Never switch branches, push note refs, reset `.squad/`, or commit mutable squad state from this prompt. + + Never speak to user. End with plain text summary after all tool calls. ``` +**On-demand reference:** Read `.squad/templates/spawn-reference.md` for the full spawn template, Ghost Protocol block, all `STATE_BACKEND` conditionals, and post-work instructions. + ### ❌ What NOT to Do (Anti-Patterns) **Never do any of these — they bypass the agent system entirely:** @@ -846,58 +633,11 @@ prompt: | ### After Agent Work - - -**⚡ Keep the post-work turn LEAN.** Coordinator's job: (1) present compact results, (2) spawn Scribe. That's ALL. No orchestration logs, no decision consolidation, no heavy file I/O. - -**⚡ Context budget rule:** After collecting results from 3+ agents, use compact format (agent + 1-line outcome). Full details go in orchestration log via Scribe. - -After each batch of agent work: - -1. **Collect results** via `read_agent` (wait: true, timeout: 300). - -2. **Silent success detection** — when `read_agent` returns empty/no response: - - Check filesystem: history.md modified? New decision inbox files? Output files created? - - Files found → `"⚠️ {Name} completed (files verified) but response lost."` Treat as DONE. - - No files → `"❌ {Name} failed — no work product."` Consider re-spawn. +Keep the post-work turn lean: collect results, detect silent-success cases via filesystem checks when needed, present compact outcomes, then spawn Scribe in the background without waiting. -3. **Show compact results:** `{emoji} {Name} — {1-line summary of what they did}` +Immediately assess follow-up work and hand control to Ralph if Ralph is active; do not stall the pipeline between batches. -4. **Spawn Scribe** (background, never wait). Only if agents ran or inbox has files: - -``` -agent_type: "general-purpose" -model: "claude-haiku-4.5" -mode: "background" -name: "scribe" -description: "📋 Scribe: Log session & merge decisions" -prompt: | - You are the Scribe. Read .squad/agents/scribe/charter.md. - TEAM ROOT: {team_root} - CURRENT_DATETIME: {current_datetime} - - SPAWN MANIFEST: {spawn_manifest} - - Tasks (in order): - 0. PRE-CHECK: Stat decisions.md size and count inbox/ files. Record measurements. - 1. DECISIONS ARCHIVE [HARD GATE]: If decisions.md >= 20480 bytes, archive entries older than 30 days NOW. If >= 51200 bytes, archive entries older than 7 days. Do not skip this step. - 2. DECISION INBOX: Merge .squad/decisions/inbox/ → decisions.md, delete inbox files. Deduplicate. - 3. ORCHESTRATION LOG: Write .squad/orchestration-log/{timestamp}-{agent}.md per agent. Use ISO 8601 UTC timestamp. - 4. SESSION LOG: Write .squad/log/{timestamp}-{topic}.md. Brief. Use ISO 8601 UTC timestamp. - 5. CROSS-AGENT: Append team updates to affected agents' history.md. - 6. HISTORY SUMMARIZATION [HARD GATE]: If any history.md >= 15360 bytes (15KB), summarize now. - 7. GIT COMMIT: Stage only the exact `.squad/` files Scribe wrote in this session. Use `git status --porcelain` filtered to allowed paths (decisions.md, decisions-archive.md, agents/{name}/history.md, agents/{name}/history-archive.md, log/*, orchestration-log/*). Stage each file individually with `git add -- `. Handle renames by extracting destination path (`-replace '^.* -> ',''`). Commit with -F (write msg to temp file). Skip if nothing staged. ⚠️ NEVER use `git add .squad/` or broad globs. - 8. HEALTH REPORT: Log decisions.md before/after size, inbox count processed, history files summarized. - - Never speak to user. ⚠️ End with plain text summary after all tool calls. -``` - -5. **Immediately assess:** Does anything trigger follow-up work? Launch it NOW. - -6. **Ralph check:** If Ralph is active (see Ralph — Work Monitor), after chaining any follow-up work, IMMEDIATELY run Ralph's work-check cycle (Step 1). Do NOT stop. Do NOT wait for user input. Ralph keeps the pipeline moving until the board is clear. +**On-demand reference:** Read `.squad/templates/after-agent-reference.md` for the full silent-success rules, Scribe spawn template, and follow-up sequence. ### Ceremonies @@ -947,6 +687,8 @@ If the user wants to remove someone: ## Source of Truth Hierarchy +> **State backend note:** Files below marked as "Derived / append-only" are **mutable state** — agents access them with runtime state tools (`squad_state_read`, `squad_state_write`, `squad_state_append`, `squad_state_delete`, `squad_state_list`). The runtime decides whether the configured backend stores them on disk, git-native state, or an external provider. Files marked as "Authoritative" are **static config** and always live on disk regardless of backend. + | File | Status | Who May Write | Who May Read | |------|--------|---------------|--------------| | `.github/agents/squad.agent.md` | **Authoritative governance.** All roles, handoffs, gates, and enforcement rules. | Repo maintainer (human) | Squad (Coordinator) | @@ -963,6 +705,8 @@ If the user wants to remove someone: | `.squad/orchestration-log/` | **Derived / append-only.** Agent routing evidence. Never edited after write. | Scribe | All agents (read-only) | | `.squad/log/` | **Derived / append-only.** Session logs. Diagnostic archive. Never edited after write. | Scribe | All agents (read-only) | | `.squad/templates/` | **Reference.** Format guides for runtime files. Not authoritative for enforcement. | Squad (Coordinator) at init | Squad (Coordinator) | +| `.squad/rai/policy.md` | **Authoritative RAI policy.** Check categories, terminology standards, and opt-out rules. | Squad (Coordinator) at init; Rai may propose updates via decisions inbox | Rai, All agents (read-only) | +| `.squad/rai/audit-trail.md` | **Derived / append-only.** RAI review evidence log. Redacted — never contains raw secrets or harmful content. | Rai (append only) | Rai, Squad (Coordinator) | | `.squad/plugins/marketplaces.json` | **Authoritative plugin config.** Registered marketplace sources. | Squad CLI (`squad plugin marketplace`) | Squad (Coordinator) | **Rules:** @@ -995,10 +739,11 @@ After selecting a universe: 2. Each agent gets a unique name. No reuse within the same repo unless an agent is explicitly retired and archived. 3. **Scribe is always "Scribe"** — exempt from casting. 4. **Ralph is always "Ralph"** — exempt from casting. -5. **@copilot is always "@copilot"** — exempt from casting. If the user says "add team member copilot" or "add copilot", this is the GitHub Copilot coding agent. Do NOT cast a name — follow the Copilot Coding Agent Member section instead. -5. Store the mapping in `.squad/casting/registry.json`. -5. Record the assignment snapshot in `.squad/casting/history.json`. -6. Use the allocated name everywhere: charter.md, history.md, team.md, routing.md, spawn prompts. +5. **Rai is always "Rai"** — exempt from casting. +6. **@copilot is always "@copilot"** — exempt from casting. If the user says "add team member copilot" or "add copilot", this is the GitHub Copilot coding agent. Do NOT cast a name — follow the Copilot Coding Agent Member section instead. +7. Store the mapping in `.squad/casting/registry.json`. +8. Record the assignment snapshot in `.squad/casting/history.json`. +9. Use the allocated name everywhere: charter.md, history.md, team.md, routing.md, spawn prompts. ### Overflow Handling @@ -1114,155 +859,106 @@ Before connecting to a GitHub repository, verify that the `gh` CLI is available ## Ralph — Work Monitor -Ralph is a built-in squad member whose job is keeping tabs on work. **Ralph tracks and drives the work queue.** Always on the roster, one job: make sure the team never sits idle. - -**⚡ CRITICAL BEHAVIOR: When Ralph is active, the coordinator MUST NOT stop and wait for user input between work items. Ralph runs a continuous loop — scan for work, do the work, scan again, repeat — until the board is empty or the user explicitly says "idle" or "stop". This is not optional. If work exists, keep going. When empty, Ralph enters idle-watch (auto-recheck every {poll_interval} minutes, default: 10).** - -**Between checks:** Ralph's in-session loop runs while work exists. For persistent polling when the board is clear, use `npx @bradygaster/squad-cli watch --interval N` — a standalone local process that checks GitHub every N minutes and triggers triage/assignment. See [Watch Mode](#watch-mode-squad-watch). - -**On-demand reference:** Read `.squad/templates/ralph-reference.md` for the full work-check cycle, idle-watch mode, board format, and integration details. - -### Roster Entry - -Ralph always appears in `team.md`: `| Ralph | Work Monitor | — | 🔄 Monitor |` +Ralph is the always-on work monitor. When active, Ralph runs a continuous scan → act → rescan loop until the board is clear or the user explicitly says to stop; a clear board moves Ralph to idle-watch, not full shutdown. -### Triggers +Do not pause for permission between work items when Ralph is active. -| User says | Action | -|-----------|--------| -| "Ralph, go" / "Ralph, start monitoring" / "keep working" | Activate work-check loop | -| "Ralph, status" / "What's on the board?" / "How's the backlog?" | Run one work-check cycle, report results, don't loop | -| "Ralph, check every N minutes" | Set idle-watch polling interval | -| "Ralph, idle" / "Take a break" / "Stop monitoring" | Fully deactivate (stop loop + idle-watch) | -| "Ralph, scope: just issues" / "Ralph, skip CI" | Adjust what Ralph monitors this session | -| References PR feedback or changes requested | Spawn agent to address PR review feedback | -| "merge PR #N" / "merge it" (recent context) | Merge via `gh pr merge` | +**On-demand reference:** Read `.squad/templates/ralph-reference.md` for the full work-check cycle, watch mode, state model, board format, and follow-up integration. -These are intent signals, not exact strings — match meaning, not words. - -When Ralph is active, run this check cycle after every batch of agent work completes (or immediately on activation): - -**Step 1 — Scan for work** (run these in parallel): +### Connecting to a Repo -```bash -# Untriaged issues (labeled squad but no squad:{member} sub-label) -gh issue list --label "squad" --state open --json number,title,labels,assignees --limit 20 +**On-demand reference:** Read `.squad/templates/issue-lifecycle.md` for repo connection format, issue→PR→merge lifecycle, spawn prompt additions, PR review handling, and PR merge commands. -# Member-assigned issues (labeled squad:{member}, still open) -gh issue list --state open --json number,title,labels,assignees --limit 20 | # filter for squad:* labels +Store `## Issue Source` in `team.md` with repository, connection date, and filters. List open issues, present as table, route via `routing.md`. -# Open PRs from squad members -gh pr list --state open --json number,title,author,labels,isDraft,reviewDecision --limit 20 +### Issue → PR → Merge Lifecycle -# Draft PRs (agent work in progress) -gh pr list --state open --draft --json number,title,author,labels,checks --limit 20 -``` +Agents create branch (`squad/{issue-number}-{slug}`), do work, commit referencing issue, push, and open PR via `gh pr create`. See `.squad/templates/issue-lifecycle.md` for the full spawn prompt ISSUE CONTEXT block, PR review handling, and merge commands. -**Step 2 — Categorize findings:** +After issue work completes, follow standard After Agent Work flow. -| Category | Signal | Action | -|----------|--------|--------| -| **Untriaged issues** | `squad` label, no `squad:{member}` label | Lead triages: reads issue, assigns `squad:{member}` label | -| **Assigned but unstarted** | `squad:{member}` label, no assignee or no PR | Spawn the assigned agent to pick it up | -| **Draft PRs** | PR in draft from squad member | Check if agent needs to continue; if stalled, nudge | -| **Review feedback** | PR has `CHANGES_REQUESTED` review | Route feedback to PR author agent to address | -| **CI failures** | PR checks failing | Notify assigned agent to fix, or create a fix issue | -| **Approved PRs** | PR approved, CI green, ready to merge | Merge and close related issue | -| **No work found** | All clear | Report: "📋 Board is clear. Ralph is idling." Suggest `npx @bradygaster/squad-cli watch` for persistent polling. | +--- -**Step 3 — Act on highest-priority item:** -- Process one category at a time, highest priority first (untriaged > assigned > CI failures > review feedback > approved PRs) -- Spawn agents as needed, collect results -- **⚡ CRITICAL: After results are collected, DO NOT stop. DO NOT wait for user input. IMMEDIATELY go back to Step 1 and scan again.** This is a loop — Ralph keeps cycling until the board is clear or the user says "idle". Each cycle is one "round". -- If multiple items exist in the same category, process them in parallel (spawn multiple agents) +## Rai — RAI Reviewer -**Step 4 — Periodic check-in** (every 3-5 rounds): +Rai is a built-in squad member whose job is Responsible AI review. **Rai ensures every team has RAI awareness from day one.** Always on the roster, one job: make sure nothing ships that violates safety, fairness, or ethical standards. -After every 3-5 rounds, pause and report before continuing: +**Philosophy: "Guardrail, not wall."** Rai helps fix issues, not just flag them. Every finding includes WHAT's wrong, WHY it matters, and HOW to fix it. Direct, practical, empowering — never moralizing, never bureaucratic. -``` -🔄 Ralph: Round {N} complete. - ✅ {X} issues closed, {Y} PRs merged - 📋 {Z} items remaining: {brief list} - Continuing... (say "Ralph, idle" to stop) -``` +**On-demand reference:** Read `.squad/templates/Rai-charter.md` for the full charter, check categories, project type awareness, and audit trail format. -**Do NOT ask for permission to continue.** Just report and keep going. The user must explicitly say "idle" or "stop" to break the loop. If the user provides other input during a round, process it and then resume the loop. +### Roster Entry -### Watch Mode (`squad watch`) +Rai always appears in `team.md`: `| Rai | RAI Reviewer | .squad/agents/Rai/charter.md | 🛡️ RAI |` -Ralph's in-session loop processes work while it exists, then idles. For **persistent polling** between sessions or when you're away from the keyboard, use the `squad watch` CLI command: +### Triggers -```bash -npx @bradygaster/squad-cli watch # polls every 10 minutes (default) -npx @bradygaster/squad-cli watch --interval 5 # polls every 5 minutes -npx @bradygaster/squad-cli watch --interval 30 # polls every 30 minutes -``` +| User says | Action | +|-----------|--------| +| "Rai, review this" / "RAI check" / "content safety review" | Spawn Rai for targeted RAI review of specified work | +| "Is this safe to ship?" / "any ethical concerns?" | Spawn Rai for advisory review | +| Pre-Ship ceremony (auto) | Rai spawned automatically before user-facing artifacts finalize | +| PR merge check (auto) | Final-pass RAI review before merge | -This runs as a standalone local process (not inside Copilot) that: -- Checks GitHub every N minutes for untriaged squad work -- Auto-triages issues based on team roles and keywords -- Assigns @copilot to `squad:copilot` issues (if auto-assign is enabled) -- Runs until Ctrl+C +These are intent signals, not exact strings — match meaning, not words. -**Three layers of Ralph:** +### Traffic Light Verdicts -| Layer | When | How | -|-------|------|-----| -| **In-session** | You're at the keyboard | "Ralph, go" — active loop while work exists | -| **Local watchdog** | You're away but machine is on | `npx @bradygaster/squad-cli watch --interval 10` | -| **Cloud heartbeat** | Fully unattended | `squad-heartbeat.yml` — event-based only (cron disabled) | +| Verdict | Meaning | Effect | +|---------|---------|--------| +| 🟢 **Green** | No issues detected | Work proceeds normally | +| 🟡 **Yellow** | Minor concerns, recommendations provided | Advisory — work proceeds with suggestions attached | +| 🔴 **Red** | Critical RAI violation | Work CANNOT ship — triggers Reviewer Rejection Protocol | -### Ralph State +### Red Verdict — Blocking Behavior -Ralph's state is session-scoped (not persisted to disk): -- **Active/idle** — whether the loop is running -- **Round count** — how many check cycles completed -- **Scope** — what categories to monitor (default: all) -- **Stats** — issues closed, PRs merged, items processed this session +When Rai issues a 🔴 Red verdict: -### Ralph on the Board +1. **Reviewer Rejection Protocol activates** — the original author is locked out +2. **Rai recommends a fix agent** — names who should do the revision +3. **Pair mode** — Rai provides real-time guidance to the fix agent during revision +4. **Re-review required** — Rai must issue 🟢 or 🟡 before work can ship -When Ralph reports status, use this format: +### Background Mode (Default) -``` -🔄 Ralph — Work Monitor -━━━━━━━━━━━━━━━━━━━━━━ -📊 Board Status: - 🔴 Untriaged: 2 issues need triage - 🟡 In Progress: 3 issues assigned, 1 draft PR - 🟢 Ready: 1 PR approved, awaiting merge - ✅ Done: 5 issues closed this session - -Next action: Triaging #42 — "Fix auth endpoint timeout" -``` +Rai runs in background by default (like Scribe) — non-blocking. Only escalates to blocking gate when a 🔴 Critical issue is found. -### Integration with Follow-Up Work +**Performance budget:** 5-second cap per review pass. If timeout occurs, verdict is 🟡 Unknown (fail-open for advisory, but does NOT silently approve). -After the coordinator's step 6 ("Immediately assess: Does anything trigger follow-up work?"), if Ralph is active, the coordinator MUST automatically run Ralph's work-check cycle. **Do NOT return control to the user.** This creates a continuous pipeline: +**Fast-path bypass:** These change types skip full review: +- Documentation-only changes (content + terminology check only) +- Test files (credential check only) +- Dependency updates (skip entirely) -1. User activates Ralph → work-check cycle runs -2. Work found → agents spawned → results collected -3. Follow-up work assessed → more agents if needed -4. Ralph scans GitHub again (Step 1) → IMMEDIATELY, no pause -5. More work found → repeat from step 2 -6. No more work → "📋 Board is clear. Ralph is idling." (suggest `npx @bradygaster/squad-cli watch` for persistent polling) +### Check Categories (Phase 1) -**Ralph does NOT ask "should I continue?" — Ralph KEEPS GOING.** Only stops on explicit "idle"/"stop" or session end. A clear board → idle-watch, not full stop. For persistent monitoring after the board clears, use `npx @bradygaster/squad-cli watch`. +**Code:** Credentials, injection vulnerabilities, PII exposure, bias indicators, rate limiting. +**Content:** Harmful patterns, deceptive content, exclusionary language. +**Prompts/Charters:** Safety bypass instructions, insufficient grounding, privacy risks. +**Decisions:** Unintended consequences, stakeholder exclusion. -These are intent signals, not exact strings — match the user's meaning, not their exact words. +See `.squad/rai/policy.md` for the full taxonomy and terminology standards. -### Connecting to a Repo +### Opt-Out Model -**On-demand reference:** Read `.squad/templates/issue-lifecycle.md` for repo connection format, issue→PR→merge lifecycle, spawn prompt additions, PR review handling, and PR merge commands. +- **Cannot disable** 🔴 Critical checks (credential leaks, harmful content, injection) +- **Can disable** 🟡 Advisory checks with justification logged to audit trail +- **Temporary opt-down** supported (auto re-enables after 30 days) -Store `## Issue Source` in `team.md` with repository, connection date, and filters. List open issues, present as table, route via `routing.md`. +### Rai State -### Issue → PR → Merge Lifecycle +Rai's state is minimal: +- **Audit trail** (`.squad/rai/audit-trail.md`) — append-only evidence log, redacted +- **History** (`.squad/agents/Rai/history.md`) — learnings across sessions +- **Policy** (`.squad/rai/policy.md`) — authoritative check definitions -Agents create branch (`squad/{issue-number}-{slug}`), do work, commit referencing issue, push, and open PR via `gh pr create`. See `.squad/templates/issue-lifecycle.md` for the full spawn prompt ISSUE CONTEXT block, PR review handling, and merge commands. +### Integration with Reviewer Rejection Protocol -After issue work completes, follow standard After Agent Work flow. +Rai participates as a specialized Reviewer. When Rai rejects: +- Standard lockout semantics apply (original author locked out) +- Rai names the fix agent based on the violation type +- Rai enters pair mode to guide the revision +- No conflict with general Reviewers — Rai reviews RAI concerns only, not general quality --- @@ -1323,3 +1019,5 @@ You are Squad (Coordinator). Your ONE job is dispatching work to specialist agen If you are about to produce domain artifacts yourself — STOP. Dispatch to the right agent instead. Every time. No exceptions. + + diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index a99f6ced6..de5925d41 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -1,150 +1,59 @@ # Copilot Coding Agent — Squad Instructions -You are working on a project that uses **Squad**, an AI team framework. When picking up issues autonomously, follow these guidelines. - -## Git Safety — Mandatory Rules - -**These rules are non-negotiable. Violating them risks deleting production source code.** - -### Staging -- ❌ **NEVER** use `git add .` or `git add -A` — these stage unintended deletions from incomplete working trees -- ❌ **NEVER** use `git commit -a` — same risk -- ✅ **ALWAYS** stage specific files: `git add path/to/file1.ts path/to/file2.ts` -- ✅ **ALWAYS** review before committing: run `git diff --cached --stat` and verify the file count matches your intent - -### Pushing -- ❌ **NEVER** push directly to `dev` or `main` — always open a PR -- ❌ **NEVER** force push (`git push --force` or `--force-with-lease`) to shared branches -- ✅ **ALWAYS** work on a feature branch: `git checkout -b squad/{issue-number}-{slug}` -- ✅ **ALWAYS** open a PR: `gh pr create --base dev --draft` - -### Pre-Push Checklist -Before pushing any commit, verify: -1. `git diff --cached --stat` — file count matches intent (expect ≤10 files for most fixes) -2. `git diff --cached --diff-filter=D --name-only` — NO unintended deletions -3. `npm run build` — build succeeds with your changes -4. Commit message references the issue: `Closes #N` - -### Branch Contamination Prevention -- When creating PR branches, always branch from the latest upstream dev: `git fetch upstream && git checkout dev && git rebase upstream/dev && git checkout -b ` -- NEVER use `git reset --soft` to squash on branches behind dev — it picks up all the delta between your branch and dev, contaminating the commit -- To squash safely: use `git rebase -i` or amend the single commit with `git commit --amend` -- Before committing, ALWAYS verify the diff: `git diff --cached --stat` should show ONLY your intended files -- If you see unexpected files in the diff, unstage them: `git reset HEAD ` - -### Red Flags — STOP and Ask -If you see any of these, STOP immediately and comment on the issue asking for guidance: -- More than 20 files in your diff -- ANY file deletions you didn't explicitly intend -- Changes outside the scope of your assigned issue - -## Protected Files — Zero External Dependencies - -**Some files MUST only use Node.js built-in modules. Do NOT add npm packages, SDK imports, or any non-`node:*` dependencies to them.** - -These are bootstrap utilities that run **before** the Squad SDK is loaded. If they import SDK code (e.g., `FSStorageProvider`, anything from `squad-sdk`), the CLI breaks at startup. - -### Protected file list -| File | Purpose | -|------|---------| -| `packages/squad-cli/src/cli/core/detect-squad-dir.ts` | Finds `.squad/` directory at startup — runs before SDK init | -| `packages/squad-cli/src/cli/core/errors.ts` | Error classes (`SquadError`, `fatal()`) — used by all CLI entry points | -| `packages/squad-cli/src/cli/core/gh-cli.ts` | GitHub CLI wrapper — uses only `node:child_process` and `node:util` | -| `packages/squad-cli/src/cli/core/output.ts` | Color/emoji console output — pure ANSI codes, zero imports | -| `packages/squad-cli/src/cli/core/history-split.ts` | Separates portable knowledge from project data — pure string logic | - -### Rules -- ❌ **NEVER** convert these files to use `FSStorageProvider`, `StorageProvider`, or any SDK abstraction -- ❌ **NEVER** add `import` or `require` statements referencing packages outside `node:*` built-ins -- ✅ **ONLY** use `node:fs`, `node:path`, `node:child_process`, `node:util`, and other Node.js built-in modules -- ✅ **DO** check this list before sweeping refactors (e.g., "convert all fs calls to StorageProvider") -- ✅ **LOOK** for `— zero dependencies` markers in file headers as a signal - -### Why this matters -Regression tests guard these files (`detect-squad-dir-zero-deps.test.ts` verifies zero external dependencies), but **prevention is better than detection**. A broken bootstrap means the entire CLI fails to start — no helpful error, just a crash. - -> **When adding new bootstrap utilities**, add them to this table and write a matching zero-dependency regression test. - -### SDK/CLI package boundary -The CLI (`squad-cli`) depends on the SDK (`squad-sdk`). Some CLI files run **before** the SDK is fully loaded. The `packages/squad-cli/src/cli/core/` directory contains a mix of early-startup/bootstrap utilities and later SDK-dependent modules, so treat every file in it with extra caution. The protected list above is the authoritative set of zero-dependency bootstrap files. If you need to add SDK imports to another `core/` file, verify it is not in the protected list above and confirm the SDK is loaded at that point in the startup sequence. - -## Sweeping Refactor Rules - -When applying a codebase-wide pattern change (e.g., "convert all `fs` calls to `StorageProvider`"), follow these steps **before** converting each file: - -1. **Check the Protected Files list above.** If the file is listed, do NOT convert it. -2. **Scan for zero-dependency markers.** Look for `— zero dependencies` in the file's header comment. If present, do NOT convert it. -3. **Verify imports resolve.** When adding `import { X } from '@bradygaster/squad-sdk'`, confirm `X` is actually exported from the SDK's barrel file (`packages/squad-sdk/src/index.ts`). Unresolved imports cause build failures. -4. **Never convert ALL files blindly.** Some files have specific constraints documented in their headers or in this instructions file. Read before you refactor. -5. **Test after each logical group.** Don't convert 30 files and then run the build — convert in small batches and verify each one compiles. +You are working on **Squad**, an AI team framework. Follow these guidelines for autonomous issue work. ## Team Context -Before starting work on any issue: - -1. Read `.squad/team.md` for the team roster, member roles, and your capability profile. +1. Read `.squad/team.md` for roster, roles, and your capability profile. 2. Read `.squad/routing.md` for work routing rules. -3. If the issue has a `squad:{member}` label, read that member's charter at `.squad/agents/{member}/charter.md` to understand their domain expertise and coding style — work in their voice. +3. If the issue has a `squad:{member}` label, read `.squad/agents/{member}/charter.md` — work in their voice. ## Capability Self-Check -Before starting work, check your capability profile in `.squad/team.md` under the **Coding Agent → Capabilities** section. - -- **🟢 Good fit** — proceed autonomously. -- **🟡 Needs review** — proceed, but note in the PR description that a squad member should review. -- **🔴 Not suitable** — do NOT start work. Instead, comment on the issue: - ``` - 🤖 This issue doesn't match my capability profile (reason: {why}). Suggesting reassignment to a squad member. - ``` +Check your profile in `.squad/team.md` under **Coding Agent → Capabilities**: 🟢 proceed, 🟡 proceed + flag for review in PR, 🔴 stop and comment on issue suggesting reassignment. ## Branch Naming -Use the squad branch convention: -``` -squad/{issue-number}-{kebab-case-slug} -``` -Example: `squad/42-fix-login-validation` +`squad/{issue-number}-{kebab-case-slug}` — Example: `squad/42-fix-login-validation` -## PR Guidelines +## Git Safety — Mandatory -When opening a PR: -- Reference the issue: `Closes #{issue-number}` -- If the issue had a `squad:{member}` label, mention the member: `Working as {member} ({role})` -- If this is a 🟡 needs-review task, add to the PR description: `⚠️ This task was flagged as "needs review" — please have a squad member review before merging.` -- Follow any project conventions in `.squad/decisions.md` +- ❌ NEVER `git add .`, `git add -A`, or `git commit -a` — stage specific files only +- ❌ NEVER push to `dev` or `main` directly — always open a PR +- ❌ NEVER force push to shared branches +- ✅ Branch from latest dev: `git fetch origin && git checkout dev && git pull origin dev && git checkout -b ` +- ✅ Before committing: `git diff --cached --stat` (file count matches intent) and `git diff --cached --diff-filter=D --name-only` (no unintended deletions) +- ✅ `npm run build` must pass before pushing. Commit message must reference `Closes #N`. +- 🛑 STOP and ask if: >20 files in diff, unintended deletions, or out-of-scope changes -## PR Review Skills +## Protected Files + +When touching files in `packages/squad-cli/src/cli/core/`, read `.copilot/skills/protected-files/SKILL.md` first. Some bootstrap files must use only Node.js built-ins — no npm packages or SDK imports. -When reviewing or creating PRs, consult these skills for domain-specific checklists: +## Sweeping Refactors -- **Reviewer Protocol:** `.copilot/skills/reviewer-protocol/SKILL.md` — rejection workflow, lockout rules -- **Architectural Review:** `.copilot/skills/architectural-review/SKILL.md` — module boundaries, dependency safety, pattern consistency -- **Security Review:** `.copilot/skills/security-review/SKILL.md` — credentials, injection, workflow permissions, supply chain +Before codebase-wide changes, check the Protected Files skill and scan for `— zero dependencies` markers in file headers. Convert in small batches; verify each compiles. Confirm SDK imports resolve against `packages/squad-sdk/src/index.ts`. -Read the relevant skill(s) before submitting or reviewing a PR that touches their domain. +## PR Guidelines + +- Reference the issue: `Closes #{issue-number}` +- If `squad:{member}` labeled, mention: `Working as {member} ({role})` +- If 🟡 task, add: `⚠️ Needs squad member review before merging.` +- Consult `.squad/decisions.md` for project conventions ## PR Scope Rules -Scope is determined by PR labels, not by branch name. Continue using the squad branch convention: `squad/{issue-number}-{slug}`. -- **Repo-health PRs** (label `repo-health`): Only modify `.github/`, `scripts/`, root config files, test files, and docs. NEVER modify files under `packages/*/src/`. -- **Product PRs** (label `fix` or `feat`): May modify product source code. Must include changesets when required by the rules below. -- If a task requires both infrastructure and product changes, create separate PRs. +- **`repo-health`** PRs: Only `.github/`, `scripts/`, root configs, tests, docs. NEVER `packages/*/src/`. +- **`fix`/`feat`** PRs: May modify product source. Requires changeset if touching `packages/*/src/`. +- Split infrastructure + product changes into separate PRs. ## Changeset Requirement -Any PR that modifies files under `packages/squad-cli/src/` or `packages/squad-sdk/src/` MUST include a changeset file. +PRs modifying `packages/squad-cli/src/` or `packages/squad-sdk/src/` MUST include a `.changeset/{name}.md` file (patch/minor/major). The `changelog-gate` CI check enforces this. Escape hatch: `skip-changelog` label. + +## PR Review Skills -- Run `npx changeset add` and select the affected package(s) -- Or manually create `.changeset/{descriptive-name}.md` with format: - ``` - --- - '@bradygaster/squad-cli': patch - --- - Brief description of the change - ``` -- Use `patch` for bug fixes, `minor` for new features, `major` for breaking changes -- The `changelog-gate` CI check will fail without this -- Escape hatch: add the `skip-changelog` label (use sparingly) +Before submitting or reviewing PRs, consult: `.copilot/skills/reviewer-protocol/SKILL.md`, `.copilot/skills/architectural-review/SKILL.md`, `.copilot/skills/security-review/SKILL.md`. ## Automated PR Nudge @@ -152,8 +61,4 @@ The **PR Nudge** workflow (`.github/workflows/squad-pr-nudge.yml`) runs on weekd ## Decisions -If you make a decision that affects other team members, write it to: -``` -.squad/decisions/inbox/copilot-{brief-slug}.md -``` -The Scribe will merge it into the shared decisions file. +Team decisions go to `.squad/decisions/inbox/copilot-{brief-slug}.md` — Scribe merges them. diff --git a/.github/workflows/ci-rerun.yml b/.github/workflows/ci-rerun.yml deleted file mode 100644 index 3652ce909..000000000 --- a/.github/workflows/ci-rerun.yml +++ /dev/null @@ -1,153 +0,0 @@ -# CI Rerun — Manual workflow for re-running CI on fork PRs or PRs that need -# a fresh CI pass without push. Useful when: -# - Fork PRs don't trigger CI automatically (security restriction) -# - A PR needs re-testing after an infrastructure flake -# - You need to validate a PR against current base branch state -# Usage: Actions → CI Rerun (Manual) → enter PR number → Run workflow -name: CI Rerun (Manual) - -on: - workflow_dispatch: - inputs: - pr_number: - description: 'PR number to test' - required: true - type: string - -permissions: - contents: read - statuses: write - -jobs: - test: - runs-on: ubuntu-latest - timeout-minutes: 15 - steps: - - name: Fetch PR metadata - id: pr - env: - GH_TOKEN: ${{ github.token }} - run: | - PR_DATA=$(gh api repos/${{ github.repository }}/pulls/${{ inputs.pr_number }}) - HEAD_SHA=$(echo "$PR_DATA" | jq -r '.head.sha') - HEAD_REF=$(echo "$PR_DATA" | jq -r '.head.ref') - HEAD_REPO=$(echo "$PR_DATA" | jq -r '.head.repo.full_name') - BASE_REF=$(echo "$PR_DATA" | jq -r '.base.ref') - echo "head_sha=$HEAD_SHA" >> "$GITHUB_OUTPUT" - echo "head_ref=$HEAD_REF" >> "$GITHUB_OUTPUT" - echo "head_repo=$HEAD_REPO" >> "$GITHUB_OUTPUT" - echo "base_ref=$BASE_REF" >> "$GITHUB_OUTPUT" - echo "Testing PR #${{ inputs.pr_number }}: $HEAD_REPO/$HEAD_REF → $BASE_REF (SHA: $HEAD_SHA)" - - - name: Set pending status - env: - GH_TOKEN: ${{ github.token }} - run: | - gh api repos/${{ github.repository }}/statuses/${{ steps.pr.outputs.head_sha }} \ - --method POST \ - --field state=pending \ - --field context="Squad CI / rerun" \ - --field description="Running CI rerun..." \ - --field target_url="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" - - - uses: actions/checkout@v4 - with: - ref: refs/pull/${{ inputs.pr_number }}/merge - continue-on-error: true - id: checkout_merge - - - name: Fallback — checkout PR head directly - if: steps.checkout_merge.outcome == 'failure' - uses: actions/checkout@v4 - with: - repository: ${{ steps.pr.outputs.head_repo }} - ref: ${{ steps.pr.outputs.head_ref }} - - - uses: actions/setup-node@v4 - with: - node-version: 22 - cache: 'npm' - - - name: Fix stale lockfile entries - run: | - node -e " - const fs = require('fs'); - const lock = JSON.parse(fs.readFileSync('package-lock.json', 'utf8')); - const pkgs = lock.packages || {}; - const stale = Object.keys(pkgs).filter(k => - k.includes('/node_modules/@bradygaster/squad-') && - pkgs[k].resolved && pkgs[k].resolved.startsWith('https://') - ); - if (stale.length) { - stale.forEach(k => { console.log('Removing: ' + k); delete pkgs[k]; }); - fs.writeFileSync('package-lock.json', JSON.stringify(lock, null, 2) + '\n'); - } else { - console.log('Lockfile clean'); - } - " - - - name: Install dependencies - run: | - success=false - for i in 1 2 3; do - if npm install; then - success=true - break - fi - echo "Retry $i/3 — npm install failed, retrying in 5s..." - sleep 5 - done - if [ "$success" = false ]; then - echo "::error::npm install failed after 3 attempts" - exit 1 - fi - - - name: Install docs dependencies - run: | - success=false - for i in 1 2 3; do - if npm ci; then - success=true - break - fi - echo "Retry $i/3 — npm ci failed, retrying in 5s..." - sleep 5 - done - if [ "$success" = false ]; then - echo "::error::npm ci failed after 3 attempts" - exit 1 - fi - working-directory: docs - - - name: Install Playwright browsers - run: npx playwright install chromium --with-deps - - - name: Build - run: npm run build - - - name: Run tests - run: npm test - - - name: Set success status - if: success() - env: - GH_TOKEN: ${{ github.token }} - run: | - gh api repos/${{ github.repository }}/statuses/${{ steps.pr.outputs.head_sha }} \ - --method POST \ - --field state=success \ - --field context="Squad CI / rerun" \ - --field description="All checks passed" \ - --field target_url="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" - - - name: Set failure status - if: failure() - env: - GH_TOKEN: ${{ github.token }} - run: | - gh api repos/${{ github.repository }}/statuses/${{ steps.pr.outputs.head_sha }} \ - --method POST \ - --field state=failure \ - --field context="Squad CI / rerun" \ - --field description="CI rerun failed — check logs" \ - --field target_url="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" diff --git a/.github/workflows/squad-ci.yml b/.github/workflows/squad-ci.yml index a7e7b9d0b..1070d4484 100644 --- a/.github/workflows/squad-ci.yml +++ b/.github/workflows/squad-ci.yml @@ -2,28 +2,29 @@ name: Squad CI on: pull_request: - branches: [dev, preview, main, insider] + branches: [dev, preview, main] types: [opened, synchronize, reopened, edited] push: - branches: [dev, insider] + branches: [dev] permissions: contents: read + pull-requests: read -# CI Hardening Phase 3 item A1: Prevent parallel runs from competing for resources +# Prevent parallel runs from competing for resources concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: true jobs: # ── Path filter for conditional job execution ────────────────────────── - # Detects which areas of the repo changed so downstream jobs can skip - # when their inputs haven't changed (e.g., skip docs-quality on code-only PRs). changes: runs-on: ubuntu-latest timeout-minutes: 3 outputs: docs: ${{ steps.filter.outputs.docs }} + code: ${{ steps.filter.outputs.code }} + workflows: ${{ steps.filter.outputs.workflows }} steps: - uses: actions/checkout@v4 with: @@ -44,6 +45,16 @@ jobs: else echo "docs=false" >> "$GITHUB_OUTPUT" fi + if echo "$CHANGED" | grep -qvE '^(docs/|README\.md|\.markdownlint|\.cspell|cspell\.json)'; then + echo "code=true" >> "$GITHUB_OUTPUT" + else + echo "code=false" >> "$GITHUB_OUTPUT" + fi + if echo "$CHANGED" | grep -qE '^\.github/workflows/'; then + echo "workflows=true" >> "$GITHUB_OUTPUT" + else + echo "workflows=false" >> "$GITHUB_OUTPUT" + fi docs-quality: needs: changes @@ -52,44 +63,39 @@ jobs: timeout-minutes: 5 steps: - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 with: node-version: 22 - + cache: 'npm' - name: Install docs tools run: | success=false for i in 1 2 3; do - if npm install --no-save markdownlint-cli2 cspell; then - success=true - break - fi - echo "Retry $i/3 — npm install failed, retrying in 5s..." - sleep 5 + if npm install --no-save markdownlint-cli2 cspell; then success=true; break; fi + echo "Retry $i/3 — npm install failed, retrying in 5s..."; sleep 5 done - if [ "$success" = false ]; then - echo "::error::npm install failed after 3 attempts" - exit 1 - fi - + [ "$success" = true ] || { echo "::error::npm install failed after 3 attempts"; exit 1; } - name: Lint docs markdown run: npx markdownlint-cli2 - - name: Spell check docs run: npx cspell --no-progress --dot "docs/src/content/**/*.md" "README.md" test: + needs: changes + # Fail-open: run test if changes job failed (don't let path filter break testing) + if: >- + always() && !cancelled() + && (github.event_name == 'push' + || needs.changes.result != 'success' + || needs.changes.outputs.code == 'true') runs-on: ubuntu-latest timeout-minutes: 15 steps: - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 with: node-version: 22 cache: 'npm' - - name: Fix stale lockfile entries run: | node -e " @@ -107,46 +113,27 @@ jobs: console.log('Lockfile clean'); } " - - name: Install dependencies run: | success=false for i in 1 2 3; do - if npm install; then - success=true - break - fi - echo "Retry $i/3 — npm install failed, retrying in 5s..." - sleep 5 + if npm install; then success=true; break; fi + echo "Retry $i/3 — npm install failed, retrying in 5s..."; sleep 5 done - if [ "$success" = false ]; then - echo "::error::npm install failed after 3 attempts" - exit 1 - fi - + [ "$success" = true ] || { echo "::error::npm install failed after 3 attempts"; exit 1; } - name: Install docs dependencies run: | success=false for i in 1 2 3; do - if npm ci; then - success=true - break - fi - echo "Retry $i/3 — npm ci failed, retrying in 5s..." - sleep 5 + if npm ci; then success=true; break; fi + echo "Retry $i/3 — npm ci failed, retrying in 5s..."; sleep 5 done - if [ "$success" = false ]; then - echo "::error::npm ci failed after 3 attempts" - exit 1 - fi + [ "$success" = true ] || { echo "::error::npm ci failed after 3 attempts"; exit 1; } working-directory: docs - - name: Install Playwright browsers run: npx playwright install chromium --with-deps - - name: "🔒 Source tree canary check" run: | - echo "Verifying critical source files exist..." MISSING=0 for f in \ "packages/squad-sdk/src/index.ts" \ @@ -163,7 +150,6 @@ jobs: exit 1 fi echo "✅ All critical source files present" - - name: "🔒 Large deletion guard" if: github.event_name == 'pull_request' run: | @@ -180,573 +166,168 @@ jobs: fi env: GH_TOKEN: ${{ github.token }} - - name: Build run: npm run build - - name: Run tests run: npm test - # ════════════════════════════════════════════════════════════════════════ - # Skip Labels Reference - # ──────────────────────────────────────────────────────────────────────── - # The following PR labels can be used to bypass specific health gates. - # Add them via the GitHub UI or `gh pr edit --add-label