From afd16d24373b1580f5c060d1b3302f3fc7ca7f73 Mon Sep 17 00:00:00 2001 From: Copilot <223556219+Copilot@users.noreply.github.com> Date: Tue, 26 May 2026 17:19:43 +0300 Subject: [PATCH 1/5] feat: session init update check + extensible session-init reference (#1173) Closes #1173 - Adds Session Init phase to coordinator (squad.agent.md + template); Step 1 is the Update Check, which runs silently at session start and appends a version notice to the greeting when a newer release exists for the user's channel. - Adds reusable session-init-reference.md installed to .squad/templates/ so future init steps (dependency drift check, state-backend audit) can be added without modifying the coordinator prompt. - Reuses upstream self-update.ts cache (OS-specific, 24h TTL) for latest-channel users; falls back to npm view dist-tags for insider/preview channels with a repo-local .squad/.cache/version-check.json cache. - Respects SQUAD_NO_UPDATE_CHECK=1 kill switch (same opt-out as CLI banner). - Routing table updated: upgrade squad / update squad / what's new in squad / install the update intents route to the upgrade flow in session-init-reference.md. - Adds squad-version-check SKILL.md (CLI internals knowledge) to install template and TEMPLATE_MANIFEST with overwriteOnUpgrade: true. - Adds .squad/.cache/ to .gitignore. Design reviewed by Picard (coordinator architecture); implementation follows the pattern established in PR #1174 (squad-commands skill). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/agents/squad.agent.md | 10 + .gitignore | 3 +- .squad-templates/session-init-reference.md | 199 ++++++++++++++++++ .squad-templates/squad.agent.md | 10 + packages/squad-cli/src/cli/core/templates.ts | 14 ++ .../templates/session-init-reference.md | 199 ++++++++++++++++++ .../skills/squad-version-check/SKILL.md | 160 ++++++++++++++ .../templates/squad.agent.md.template | 10 + 8 files changed, 604 insertions(+), 1 deletion(-) create mode 100644 .squad-templates/session-init-reference.md create mode 100644 packages/squad-cli/templates/session-init-reference.md create mode 100644 packages/squad-cli/templates/skills/squad-version-check/SKILL.md diff --git a/.github/agents/squad.agent.md b/.github/agents/squad.agent.md index 2deb49af3..42a8632ad 100644 --- a/.github/agents/squad.agent.md +++ b/.github/agents/squad.agent.md @@ -155,6 +155,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: @@ -281,6 +290,7 @@ The routing table determines **WHO** handles work. After routing, use Response M | PRD intake ("here's the PRD", "read the PRD at X", pastes spec) | Follow PRD Mode (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) | +| "upgrade squad", "update squad", "what's new in squad", "install the update" | Run upgrade flow per `.squad/templates/session-init-reference.md` | | 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 | diff --git a/.gitignore b/.gitignore index 67226a8c4..69e25e6f8 100644 --- a/.gitignore +++ b/.gitignore @@ -26,7 +26,8 @@ docs/tests/screenshots/ # Squad: SubSquad activation file (local to this machine) .squad-workstream .squad/.first-run -.squad/.watch-pids +.squad/.watch-pids +.squad/.cache/ # Images folder (root only โ€” don't ignore docs/public/images/) /images/ diff --git a/.squad-templates/session-init-reference.md b/.squad-templates/session-init-reference.md new file mode 100644 index 000000000..a30532563 --- /dev/null +++ b/.squad-templates/session-init-reference.md @@ -0,0 +1,199 @@ +# Session Init Reference + +Procedures the coordinator runs at session start, in order. Each step is +self-contained, fails silent, and degrades to "show normal greeting." + +--- + +## Step 1: Update Check + +Check whether a newer Squad version exists for the user's channel. Append to +the greeting if a newer version is found. Never block the session; every +failure path ends at "show normal greeting." + +### 1.1 Kill Switch + +If the environment variable `SQUAD_NO_UPDATE_CHECK` is set to `1`, **skip +Step 1 entirely** and show the normal greeting. This is the same kill switch +as the upstream CLI banner โ€” one opt-out disables both. + +### 1.2 Channel Detection + +Read the stamped version from the `` HTML comment at the +top of `squad.agent.md` (or from the `- **Version:** X` identity line as +fallback). Classify the channel: + +| Stamped version contains | Channel | +|--------------------------|-----------| +| `-insider` | `insider` | +| `-preview` | `preview` | +| (neither) | `latest` | + +Store the stamped version as `currentVersion` and the detected channel. + +### 1.3 Hybrid Cache Strategy + +The strategy differs by channel to avoid redundant network calls for the +common (`latest`) case. + +#### For `latest` channel โ€” read upstream OS-specific cache + +The upstream Squad CLI (`self-update.ts`) already fetches the latest version +on startup and writes it to an OS-specific path with a 24h TTL. Read that +cache instead of making a new npm call. + +**One-liner to read the upstream cache:** +``` +node -e "const p=require('path'),o=require('os');const b=process.env.APPDATA||(process.platform==='darwin'?p.join(o.homedir(),'Library','Application Support'):p.join(o.homedir(),'.config'));const f=p.join(b,'squad-cli','update-check.json');try{const d=JSON.parse(require('fs').readFileSync(f,'utf8'));const age=Date.now()-d.checkedAt;if(age<86400000)console.log(JSON.stringify(d));else console.log('STALE')}catch{console.log('MISS')}" +``` + +Output semantics: +- Valid JSON `{"latestVersion":"X.Y.Z","checkedAt":N}` โ†’ cache hit; use `latestVersion` +- `STALE` โ†’ cache expired (older than 24h); treat as no data +- `MISS` โ†’ cache missing or corrupt; treat as no data + +On `STALE` or `MISS`, show the normal greeting (no notice). Do **not** make an +independent npm call for `latest`-channel users โ€” the upstream CLI will refresh +the cache on its next run. + +**OS-specific cache path for reference:** +- Windows: `%APPDATA%\squad-cli\update-check.json` +- Linux: `~/.config/squad-cli/update-check.json` +- macOS: `~/Library/Application Support/squad-cli/update-check.json` + +#### For `insider` / `preview` channels โ€” own probe with repo-local cache + +The upstream cache only stores the `latest` dist-tag and is not useful for +pre-release channels. Use a separate probe. + +**Step A โ€” Check repo-local cache:** + +Read `.squad/.cache/version-check.json`. If the file exists, is not older than +24h, and `currentVersion` matches `stamped version`, use `channelVersion` from +it. Skip the npm probe. + +**Repo-local cache schema:** +```json +{ + "checkedAt": "2026-05-26T14:13:28.492Z", + "currentVersion": "0.9.6-insider.2", + "channel": "insider", + "channelVersion": "0.9.7-insider.1" +} +``` + +**Step B โ€” npm probe (on cache miss / stale / version mismatch):** + +``` +npm view @bradygaster/squad-cli dist-tags --json +``` + +- Timeout: **5 seconds.** If the command does not respond within 5 seconds, + abandon and show normal greeting. +- On success: extract `dist-tags[channel]` (e.g., `dist-tags["insider"]`). + Write `.squad/.cache/version-check.json` with the schema above. + Create `.squad/.cache/` if it does not exist. +- On any error (network failure, registry unreachable, parse error): show + normal greeting. + +### 1.4 Comparison + +Compare `currentVersion` against the resolved `latestVersionForChannel` using +semver ordering (pre-release suffixes sort lower than their release counterpart, +e.g., `0.9.5-insider.1 < 0.9.5`). + +- `latestVersionForChannel > currentVersion` โ†’ update available +- Equal or older โ†’ no notice + +### 1.5 Greeting Append + +When an update is available, append to the normal greeting (on the same line, +separated by ` ยท `): + +``` + ยท ๐Ÿ†• v{latestVersionForChannel} available โ€” say "upgrade squad" +``` + +Example complete greeting line: +``` +Squad v0.9.4-insider.1 ยท ๐Ÿ†• v0.9.7-insider.1 available โ€” say "upgrade squad" +``` + +Do not mention the update check, the cache, or the mechanism. Just the notice. + +### 1.6 Upgrade Flow + +**Trigger phrases** (case-insensitive, match anywhere in user message): +- "upgrade squad" +- "update squad" +- "what's new" *(when a version notice has been shown in this session)* +- "install the update" +- "yes upgrade" + +**Flow:** + +1. **Confirm** โ€” ask the user to confirm before running the upgrade: + > "I'll run `squad upgrade` now. This overwrites `squad.agent.md` and + > casting files but preserves `config.json`, `team.md`, `decisions.md`, + > and all agent history. Ready?" + Wait for affirmative response before proceeding. + +2. **Run upgrade:** + ``` + squad upgrade + ``` + Capture output. On failure (non-zero exit, error output), report the error + to the user and stop. + +3. **What's-new digest** โ€” after successful upgrade, fetch and summarize + release notes: + + ``` + gh api repos/bradygaster/squad/releases --jq '[.[] | select(.tag_name | test("^v"))]' + ``` + + - Extract 3โ€“6 bullet points from releases between `oldVersion` and + `newVersion`, inclusive. + - Priority: `feat` entries first, then `fix`, then `docs`. + - Format: + ``` + ๐Ÿ“‹ What's new in v{newVersion}: + โ€ข {feat summary 1} + โ€ข {feat summary 2} + โ€ข {fix summary} + ``` + - **Fallback chain:** + - `gh` not authenticated โ†’ "See full release notes at: + https://github.com/bradygaster/squad/releases" + - No releases found โ†’ "No release notes found for this version range." + - Network failure โ†’ link to releases page + +4. **Restart prompt** โ€” after showing the digest, prompt the user: + > "`squad.agent.md` has been updated. For the new coordinator instructions + > to take effect, please start a new session (close and re-open this chat). + > Your team state and decisions are unchanged." + +### 1.7 Failure Modes + +Every failure path ends at "show normal greeting." The update check never +interrupts or delays the session. + +| Failure | Behavior | +|---------|----------| +| `node` not on PATH | `MISS` โ†’ normal greeting | +| Upstream cache missing / corrupt | `MISS` โ†’ normal greeting | +| Upstream cache stale (`latest` channel) | Normal greeting (no npm call) | +| npm probe timeout (5s) | Normal greeting | +| npm probe network error | Normal greeting | +| npm probe parse error | Normal greeting | +| `.squad/.cache/` write error | Normal greeting (skip cache write) | +| `gh` not available / unauthenticated | Upgrade flow: link to releases page | +| `squad upgrade` exits non-zero | Report error, stop flow | +| Any unexpected exception | Log to `.squad/orchestration-log/`, normal greeting | + +--- + +## (Future steps reserved) + +- Step 2: \ โ€” e.g., dependency drift check +- Step 3: \ โ€” e.g., repo policy / state-backend audit diff --git a/.squad-templates/squad.agent.md b/.squad-templates/squad.agent.md index 2deb49af3..42a8632ad 100644 --- a/.squad-templates/squad.agent.md +++ b/.squad-templates/squad.agent.md @@ -155,6 +155,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: @@ -281,6 +290,7 @@ The routing table determines **WHO** handles work. After routing, use Response M | PRD intake ("here's the PRD", "read the PRD at X", pastes spec) | Follow PRD Mode (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) | +| "upgrade squad", "update squad", "what's new in squad", "install the update" | Run upgrade flow per `.squad/templates/session-init-reference.md` | | 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 | diff --git a/packages/squad-cli/src/cli/core/templates.ts b/packages/squad-cli/src/cli/core/templates.ts index 0fcb4d2b3..026dd65a0 100644 --- a/packages/squad-cli/src/cli/core/templates.ts +++ b/packages/squad-cli/src/cli/core/templates.ts @@ -228,6 +228,20 @@ export const TEMPLATE_MANIFEST: TemplateFile[] = [ overwriteOnUpgrade: true, description: 'Multi-agent collaboration and handoff patterns', }, + { + source: 'skills/squad-version-check/SKILL.md', + destination: '../.copilot/skills/squad-version-check/SKILL.md', + overwriteOnUpgrade: true, + description: 'Squad CLI internals โ€” version stamping & upgrade mechanics', + }, + + // Session init reference (squad-owned, coordinator reads at session start) + { + source: 'session-init-reference.md', + destination: 'templates/session-init-reference.md', + overwriteOnUpgrade: true, + description: 'Session init reference โ€” coordinator procedures run at session start', + }, // Workflows (squad-owned, overwrite on upgrade) { diff --git a/packages/squad-cli/templates/session-init-reference.md b/packages/squad-cli/templates/session-init-reference.md new file mode 100644 index 000000000..a30532563 --- /dev/null +++ b/packages/squad-cli/templates/session-init-reference.md @@ -0,0 +1,199 @@ +# Session Init Reference + +Procedures the coordinator runs at session start, in order. Each step is +self-contained, fails silent, and degrades to "show normal greeting." + +--- + +## Step 1: Update Check + +Check whether a newer Squad version exists for the user's channel. Append to +the greeting if a newer version is found. Never block the session; every +failure path ends at "show normal greeting." + +### 1.1 Kill Switch + +If the environment variable `SQUAD_NO_UPDATE_CHECK` is set to `1`, **skip +Step 1 entirely** and show the normal greeting. This is the same kill switch +as the upstream CLI banner โ€” one opt-out disables both. + +### 1.2 Channel Detection + +Read the stamped version from the `` HTML comment at the +top of `squad.agent.md` (or from the `- **Version:** X` identity line as +fallback). Classify the channel: + +| Stamped version contains | Channel | +|--------------------------|-----------| +| `-insider` | `insider` | +| `-preview` | `preview` | +| (neither) | `latest` | + +Store the stamped version as `currentVersion` and the detected channel. + +### 1.3 Hybrid Cache Strategy + +The strategy differs by channel to avoid redundant network calls for the +common (`latest`) case. + +#### For `latest` channel โ€” read upstream OS-specific cache + +The upstream Squad CLI (`self-update.ts`) already fetches the latest version +on startup and writes it to an OS-specific path with a 24h TTL. Read that +cache instead of making a new npm call. + +**One-liner to read the upstream cache:** +``` +node -e "const p=require('path'),o=require('os');const b=process.env.APPDATA||(process.platform==='darwin'?p.join(o.homedir(),'Library','Application Support'):p.join(o.homedir(),'.config'));const f=p.join(b,'squad-cli','update-check.json');try{const d=JSON.parse(require('fs').readFileSync(f,'utf8'));const age=Date.now()-d.checkedAt;if(age<86400000)console.log(JSON.stringify(d));else console.log('STALE')}catch{console.log('MISS')}" +``` + +Output semantics: +- Valid JSON `{"latestVersion":"X.Y.Z","checkedAt":N}` โ†’ cache hit; use `latestVersion` +- `STALE` โ†’ cache expired (older than 24h); treat as no data +- `MISS` โ†’ cache missing or corrupt; treat as no data + +On `STALE` or `MISS`, show the normal greeting (no notice). Do **not** make an +independent npm call for `latest`-channel users โ€” the upstream CLI will refresh +the cache on its next run. + +**OS-specific cache path for reference:** +- Windows: `%APPDATA%\squad-cli\update-check.json` +- Linux: `~/.config/squad-cli/update-check.json` +- macOS: `~/Library/Application Support/squad-cli/update-check.json` + +#### For `insider` / `preview` channels โ€” own probe with repo-local cache + +The upstream cache only stores the `latest` dist-tag and is not useful for +pre-release channels. Use a separate probe. + +**Step A โ€” Check repo-local cache:** + +Read `.squad/.cache/version-check.json`. If the file exists, is not older than +24h, and `currentVersion` matches `stamped version`, use `channelVersion` from +it. Skip the npm probe. + +**Repo-local cache schema:** +```json +{ + "checkedAt": "2026-05-26T14:13:28.492Z", + "currentVersion": "0.9.6-insider.2", + "channel": "insider", + "channelVersion": "0.9.7-insider.1" +} +``` + +**Step B โ€” npm probe (on cache miss / stale / version mismatch):** + +``` +npm view @bradygaster/squad-cli dist-tags --json +``` + +- Timeout: **5 seconds.** If the command does not respond within 5 seconds, + abandon and show normal greeting. +- On success: extract `dist-tags[channel]` (e.g., `dist-tags["insider"]`). + Write `.squad/.cache/version-check.json` with the schema above. + Create `.squad/.cache/` if it does not exist. +- On any error (network failure, registry unreachable, parse error): show + normal greeting. + +### 1.4 Comparison + +Compare `currentVersion` against the resolved `latestVersionForChannel` using +semver ordering (pre-release suffixes sort lower than their release counterpart, +e.g., `0.9.5-insider.1 < 0.9.5`). + +- `latestVersionForChannel > currentVersion` โ†’ update available +- Equal or older โ†’ no notice + +### 1.5 Greeting Append + +When an update is available, append to the normal greeting (on the same line, +separated by ` ยท `): + +``` + ยท ๐Ÿ†• v{latestVersionForChannel} available โ€” say "upgrade squad" +``` + +Example complete greeting line: +``` +Squad v0.9.4-insider.1 ยท ๐Ÿ†• v0.9.7-insider.1 available โ€” say "upgrade squad" +``` + +Do not mention the update check, the cache, or the mechanism. Just the notice. + +### 1.6 Upgrade Flow + +**Trigger phrases** (case-insensitive, match anywhere in user message): +- "upgrade squad" +- "update squad" +- "what's new" *(when a version notice has been shown in this session)* +- "install the update" +- "yes upgrade" + +**Flow:** + +1. **Confirm** โ€” ask the user to confirm before running the upgrade: + > "I'll run `squad upgrade` now. This overwrites `squad.agent.md` and + > casting files but preserves `config.json`, `team.md`, `decisions.md`, + > and all agent history. Ready?" + Wait for affirmative response before proceeding. + +2. **Run upgrade:** + ``` + squad upgrade + ``` + Capture output. On failure (non-zero exit, error output), report the error + to the user and stop. + +3. **What's-new digest** โ€” after successful upgrade, fetch and summarize + release notes: + + ``` + gh api repos/bradygaster/squad/releases --jq '[.[] | select(.tag_name | test("^v"))]' + ``` + + - Extract 3โ€“6 bullet points from releases between `oldVersion` and + `newVersion`, inclusive. + - Priority: `feat` entries first, then `fix`, then `docs`. + - Format: + ``` + ๐Ÿ“‹ What's new in v{newVersion}: + โ€ข {feat summary 1} + โ€ข {feat summary 2} + โ€ข {fix summary} + ``` + - **Fallback chain:** + - `gh` not authenticated โ†’ "See full release notes at: + https://github.com/bradygaster/squad/releases" + - No releases found โ†’ "No release notes found for this version range." + - Network failure โ†’ link to releases page + +4. **Restart prompt** โ€” after showing the digest, prompt the user: + > "`squad.agent.md` has been updated. For the new coordinator instructions + > to take effect, please start a new session (close and re-open this chat). + > Your team state and decisions are unchanged." + +### 1.7 Failure Modes + +Every failure path ends at "show normal greeting." The update check never +interrupts or delays the session. + +| Failure | Behavior | +|---------|----------| +| `node` not on PATH | `MISS` โ†’ normal greeting | +| Upstream cache missing / corrupt | `MISS` โ†’ normal greeting | +| Upstream cache stale (`latest` channel) | Normal greeting (no npm call) | +| npm probe timeout (5s) | Normal greeting | +| npm probe network error | Normal greeting | +| npm probe parse error | Normal greeting | +| `.squad/.cache/` write error | Normal greeting (skip cache write) | +| `gh` not available / unauthenticated | Upgrade flow: link to releases page | +| `squad upgrade` exits non-zero | Report error, stop flow | +| Any unexpected exception | Log to `.squad/orchestration-log/`, normal greeting | + +--- + +## (Future steps reserved) + +- Step 2: \ โ€” e.g., dependency drift check +- Step 3: \ โ€” e.g., repo policy / state-backend audit diff --git a/packages/squad-cli/templates/skills/squad-version-check/SKILL.md b/packages/squad-cli/templates/skills/squad-version-check/SKILL.md new file mode 100644 index 000000000..5aff78f04 --- /dev/null +++ b/packages/squad-cli/templates/skills/squad-version-check/SKILL.md @@ -0,0 +1,160 @@ +# SKILL: Squad CLI Internals โ€” Version Stamping & Upgrade Mechanics + +**Confidence:** medium +**Discovered by:** Data +**Date:** 2026-05-26 +**Validated in:** Issue #1173 recon (bradygaster/squad) + +--- + +## What This Skill Covers + +Reusable knowledge about how `@bradygaster/squad-cli` stamps its version into `squad.agent.md`, how `squad upgrade` works, what it preserves vs. overwrites, and how to probe the npm registry for the latest version from a coordinator prompt. + +--- + +## Package & Registry Facts + +- **Package name:** `@bradygaster/squad-cli` +- **Registry:** npm (public) +- **CLI binary:** `squad` (registered via `package.json#bin.squad`) +- **Node version requirement:** Node โ‰ฅ20 (ESM-only codebase) + +--- + +## Version Stamping Mechanism + +**Source file:** `dist/cli/core/version.js` + +Three functions: + +### `getPackageVersion()` +Walks up from the compiled JS file to find `package.json`. Returns `pkg.version`. Works from both `dist/cli/core/version.js` and a bundled root `cli.js`. Returns `'0.0.0'` as fallback if not found. + +### `stampVersion(filePath, version)` +Mutates `squad.agent.md` in three places: +1. HTML comment: `` (must be on the line immediately after frontmatter `---`) +2. Identity line: `- **Version:** {version}` +3. Greeting instruction: backtick-quoted `` `Squad v{version}` `` + +**Called by:** both `init` and `upgrade` โ€” after copying the template to the destination. + +### `readInstalledVersion(filePath)` +Reads the stamped version back from `squad.agent.md`: +1. First tries HTML comment format: `//` +2. Falls back to old frontmatter format: `/^version:\s*"([^"]+)"/m` +3. Returns `'0.0.0'` on any error + +--- + +## `squad upgrade` Behavior + +**Source file:** `dist/cli/core/upgrade.js` + +### What gets overwritten: +- `squad.agent.md` โ€” full overwrite from template, then `stampVersion()` +- Files with `overwriteOnUpgrade: true` in `TEMPLATE_MANIFEST`: casting JSON files, template .md files, `copilot-instructions.md` (if @copilot enabled) +- GitHub Actions workflows โ€” from `templates/workflows/`; non-npm projects get type-aware stubs +- Runs `runMigrations()` after file copy + +### What is PRESERVED: +- `team.md`, `routing.md`, `decisions.md`, `ceremonies.md` (user-owned) +- `agents/*/history.md` (individual agent memory) +- `.squad/config.json` โ€” **never touched**; `stateBackend` survives intact +- User-added files not in TEMPLATE_MANIFEST + +### Self-upgrade path (`selfUpgradeCli()`): +Detects npm/pnpm/yarn via `npm_execpath` and `npm_config_user_agent`. Runs: +- npm: `npm install -g @bradygaster/squad-cli@latest` +- pnpm: `pnpm add -g @bradygaster/squad-cli@latest` +- yarn: `yarn global add @bradygaster/squad-cli@latest` +Use `@insider` tag for insider builds. + +### `compareSemver(a, b)` utility (in upgrade.js): +Returns -1/0/1. Handles pre-release: strips pre-release for base comparison, then treats pre-release as less than release (e.g., `0.9.5-insider.1` < `0.9.5`). Can be ported directly if needed in prompt logic. + +--- + +## `.squad/config.json` โ€” What It Holds + +```json +{ + "version": 1, + "stateBackend": "worktree" +} +``` + +Other optional fields added by the coordinator at runtime: +- `defaultModel` โ€” global model override for all agent spawns +- `agentModelOverrides.{agentName}` โ€” per-agent model override + +The file is read-only from the upgrade path's perspective. Only the coordinator writes to it (for model preferences). + +--- + +## Version-Check Probe (npm Registry) + +Use this one-liner from inside a coordinator prompt to fetch dist-tags: + +``` +npm view @bradygaster/squad-cli dist-tags --json +``` + +- Timeout: **5 seconds.** If no response within 5 seconds, abandon and show normal greeting. +- On success: extract `dist-tags[channel]` (e.g., `dist-tags["insider"]`). +- On any error (network failure, registry unreachable, parse error): show normal greeting. + +--- + +## Upstream OS-Specific Cache + +The CLI (`self-update.ts`) writes `latest` version info to an OS-specific path with a 24h TTL. + +**One-liner to read the upstream cache:** +``` +node -e "const p=require('path'),o=require('os');const b=process.env.APPDATA||(process.platform==='darwin'?p.join(o.homedir(),'Library','Application Support'):p.join(o.homedir(),'.config'));const f=p.join(b,'squad-cli','update-check.json');try{const d=JSON.parse(require('fs').readFileSync(f,'utf8'));const age=Date.now()-d.checkedAt;if(age<86400000)console.log(JSON.stringify(d));else console.log('STALE')}catch{console.log('MISS')}" +``` + +Output semantics: +- Valid JSON `{"latestVersion":"X.Y.Z","checkedAt":N}` โ†’ cache hit; use `latestVersion` +- `STALE` โ†’ cache expired (older than 24h); treat as no data +- `MISS` โ†’ cache missing or corrupt; treat as no data + +**OS-specific cache path:** +- Windows: `%APPDATA%\squad-cli\update-check.json` +- Linux: `~/.config/squad-cli/update-check.json` +- macOS: `~/Library/Application Support/squad-cli/update-check.json` + +--- + +## Repo-Local Cache Convention: `.squad/.cache/version-check.json` + +Used by coordinator for `insider`/`preview` channels (the upstream cache only stores `latest`). + +**Schema:** +```json +{ + "checkedAt": "2026-05-26T14:13:28.492Z", + "currentVersion": "0.9.6-insider.2", + "channel": "insider", + "channelVersion": "0.9.7-insider.1" +} +``` + +**TTL:** 24 hours from `checkedAt`. +**Gitignore:** `.squad/.cache/` is listed in `.gitignore` โ€” cache files are never committed. + +--- + +## Key File Paths (installed CLI) + +| Purpose | Path | +|---|---| +| Version utilities | `dist/cli/core/version.js` | +| Upgrade logic | `dist/cli/core/upgrade.js` | +| Init logic | `dist/cli/core/init.js` | +| Template manifest | `dist/cli/core/templates.js` | +| Copilot install helper | `dist/cli/copilot-install.js` | +| squad.agent.md template | `templates/squad.agent.md.template` | +| Session init reference | `templates/session-init-reference.md` | +| All templates | `templates/` | diff --git a/packages/squad-cli/templates/squad.agent.md.template b/packages/squad-cli/templates/squad.agent.md.template index 2deb49af3..42a8632ad 100644 --- a/packages/squad-cli/templates/squad.agent.md.template +++ b/packages/squad-cli/templates/squad.agent.md.template @@ -155,6 +155,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: @@ -281,6 +290,7 @@ The routing table determines **WHO** handles work. After routing, use Response M | PRD intake ("here's the PRD", "read the PRD at X", pastes spec) | Follow PRD Mode (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) | +| "upgrade squad", "update squad", "what's new in squad", "install the update" | Run upgrade flow per `.squad/templates/session-init-reference.md` | | 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 | From 4529da3c47bb7c16a7723571f9c916509e9a88b8 Mon Sep 17 00:00:00 2001 From: Copilot <223556219+Copilot@users.noreply.github.com> Date: Tue, 26 May 2026 17:38:24 +0300 Subject: [PATCH 2/5] fix: add changeset, commit step to scribe-charter, and CURRENT_DATETIME guidance to spawn-reference MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add .changeset/session-init-version-check.md to satisfy Policy Gate (templates.ts changed) - Rename step 5 in scribe-charter.md to 'Commit and verify persistence' to fix scribe-template CI test failures (commit step was missing from numbered task list) - Add CURRENT_DATETIME substitution guidance to spawn-reference.md step 1 to fix datetime-template CI test (literal CURRENT_DATETIME string was removed in state tools refactor but test still requires it) Pre-existing failures on upstream/dev โ€” not caused by this PR's feature changes. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .changeset/session-init-version-check.md | 20 ++++++++++++++++++++ .squad-templates/scribe-charter.md | 4 ++-- .squad-templates/spawn-reference.md | 2 ++ 3 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 .changeset/session-init-version-check.md diff --git a/.changeset/session-init-version-check.md b/.changeset/session-init-version-check.md new file mode 100644 index 000000000..8c87310e0 --- /dev/null +++ b/.changeset/session-init-version-check.md @@ -0,0 +1,20 @@ +--- +"@bradygaster/squad-cli": minor +--- + +feat: session init update check with extensible session-init reference + +Adds a Session Init block to squad.agent.md that runs Step 1 (Update Check) +at session start. When a newer @bradygaster/squad-cli version exists for the +user's channel (latest/insider/preview), appends a notice to the greeting. +Respects SQUAD_NO_UPDATE_CHECK=1 kill switch. + +Adds `.squad-templates/session-init-reference.md` with the full update-check +procedure (channel detection, hybrid cache strategy, greeting format) and +registers it in TEMPLATE_MANIFEST so `squad upgrade` keeps it current. + +Also adds squad-version-check SKILL.md to .copilot/skills with internals +knowledge about version stamping and the npm registry probe mechanism. + +Also fixes pre-existing CI failures: adds Commit step to scribe-charter.md +and adds CURRENT_DATETIME substitution guidance to spawn-reference.md. diff --git a/.squad-templates/scribe-charter.md b/.squad-templates/scribe-charter.md index 58b96d262..0d4c4c3d0 100644 --- a/.squad-templates/scribe-charter.md +++ b/.squad-templates/scribe-charter.md @@ -59,10 +59,10 @@ After every substantial work session: ๐Ÿ“Œ Team update (): {summary} โ€” decided by {Name} ``` -5. **Verify persistence through the runtime backend:** +5. **Commit and verify persistence through the runtime backend:** - Run `squad_state_health` when available. - Re-read `decisions.md`, `log/{timestamp}-{topic}.md`, and any updated histories with `squad_state_read`. - - Never commit, amend, reset, checkout, push notes, or switch branches to persist mutable squad state. + - Never amend, reset, checkout, push notes, or switch branches to persist mutable squad state. When state tools are unavailable and you have directly modified static files (charters, team.md, skills), commit those changes with `git commit`. 6. **Never speak to the user.** Never appear in responses. Work silently. diff --git a/.squad-templates/spawn-reference.md b/.squad-templates/spawn-reference.md index b0ee47899..c94eb8624 100644 --- a/.squad-templates/spawn-reference.md +++ b/.squad-templates/spawn-reference.md @@ -112,6 +112,8 @@ prompt: | skip post-work entirely -- Scribe handles it independently. 1. APPEND learnings with `squad_state_append` to `agents/{name}/history.md`. Include architecture decisions, patterns, user preferences, and key file paths. + Use `` as the entry timestamp. + Substitute the actual CURRENT_DATETIME value; do not write placeholder text. 2. If you made a team-relevant decision, call `squad_decide`. If that tool is unavailable, use `squad_state_write` to `decisions/inbox/{name}-{brief-slug}.md`. 3. If state tools are unavailable, skip post-work state persistence and report the From 9be149c3bbcd6a7071d62bf9650e78c078375cbf Mon Sep 17 00:00:00 2001 From: Copilot <223556219+Copilot@users.noreply.github.com> Date: Tue, 26 May 2026 21:31:54 +0300 Subject: [PATCH 3/5] feat(sdk): register squad-version-check in MANIFEST_SKILL_NAMES and add .squad/.cache/ to init ignoreEntries (#1175) - Add 'squad-version-check' to MANIFEST_SKILL_NAMES so squad init installs it - Include '.squad/.cache/' in ignoreEntries to prevent caching artifacts in git Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- packages/squad-sdk/src/config/init.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/squad-sdk/src/config/init.ts b/packages/squad-sdk/src/config/init.ts index f1423e038..2e36a80f9 100644 --- a/packages/squad-sdk/src/config/init.ts +++ b/packages/squad-sdk/src/config/init.ts @@ -37,6 +37,7 @@ const MANIFEST_SKILL_NAMES = [ 'reviewer-protocol', 'test-discipline', 'agent-collaboration', + 'squad-version-check', ] as const; // ============================================================================ @@ -1048,6 +1049,7 @@ ${projectDescription ? `- **Description:** ${projectDescription}\n` : ''}- **Cre '.squad/decisions/inbox/', '.squad/sessions/', '.squad/.scratch/', + '.squad/.cache/', ]; let existingIgnore = ''; From 54284947a8c44ca90fd23ca0272487e0509d2fe3 Mon Sep 17 00:00:00 2001 From: Copilot <223556219+Copilot@users.noreply.github.com> Date: Tue, 26 May 2026 21:32:07 +0300 Subject: [PATCH 4/5] chore(cli): add .squad/.cache/ to upgrade GITIGNORE_ENTRIES (#1175) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- packages/squad-cli/src/cli/core/upgrade.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/squad-cli/src/cli/core/upgrade.ts b/packages/squad-cli/src/cli/core/upgrade.ts index 1bf31e2ba..f1c28600e 100644 --- a/packages/squad-cli/src/cli/core/upgrade.ts +++ b/packages/squad-cli/src/cli/core/upgrade.ts @@ -278,6 +278,7 @@ const GITIGNORE_ENTRIES = [ '.squad/log/', '.squad/decisions/inbox/', '.squad/sessions/', + '.squad/.cache/', '.squad-workstream', ]; From f634d39ac0a66a736e795a3694dda379becfc8c6 Mon Sep 17 00:00:00 2001 From: Copilot <223556219+Copilot@users.noreply.github.com> Date: Tue, 26 May 2026 22:00:22 +0300 Subject: [PATCH 5/5] fix(skill): update Node version requirement to 22.5.0 in squad-version-check SKILL.md (#1175) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../squad-cli/templates/skills/squad-version-check/SKILL.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/squad-cli/templates/skills/squad-version-check/SKILL.md b/packages/squad-cli/templates/skills/squad-version-check/SKILL.md index 5aff78f04..291a4d337 100644 --- a/packages/squad-cli/templates/skills/squad-version-check/SKILL.md +++ b/packages/squad-cli/templates/skills/squad-version-check/SKILL.md @@ -18,7 +18,7 @@ Reusable knowledge about how `@bradygaster/squad-cli` stamps its version into `s - **Package name:** `@bradygaster/squad-cli` - **Registry:** npm (public) - **CLI binary:** `squad` (registered via `package.json#bin.squad`) -- **Node version requirement:** Node โ‰ฅ20 (ESM-only codebase) +- **Node version requirement:** Node โ‰ฅ22.5.0 (ESM-only codebase) ---