From 34bc550c4253993657c66cd89fd3a6f07fcbf107 Mon Sep 17 00:00:00 2001 From: Ohad Beltzer Date: Sat, 30 May 2026 19:26:30 +0300 Subject: [PATCH 1/6] fix(ci): expand changelog gate to cover template and scaffolding paths The changelog-gate job only matched packages/squad-(sdk|cli)/src/, so PRs touching bundled templates, scaffolding, and agent files bypassed the changeset requirement silently. Expand the SDK_CLI_CHANGED pattern to also match packages/squad-(sdk|cli)/templates/, .squad-templates/, and templates/, aligning CI enforcement with CONTRIBUTING.md. Closes #1156 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/squad-ci.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/squad-ci.yml b/.github/workflows/squad-ci.yml index 569e498cd..1772e6308 100644 --- a/.github/workflows/squad-ci.yml +++ b/.github/workflows/squad-ci.yml @@ -219,12 +219,12 @@ jobs: BASE="${{ github.event.pull_request.base.sha }}" HEAD="${{ github.event.pull_request.head.sha }}" CHANGED=$(git diff --name-only "$BASE"..."$HEAD") - SDK_CLI_CHANGED=$(echo "$CHANGED" | grep -E '^packages/squad-(sdk|cli)/src/' || true) + SDK_CLI_CHANGED=$(echo "$CHANGED" | grep -E '^packages/squad-(sdk|cli)/src/|^packages/squad-(sdk|cli)/templates/|^\.squad-templates/|^templates/' || true) if [ -z "$SDK_CLI_CHANGED" ]; then - echo "✅ Not applicable (no SDK/CLI source changes)" >> $GITHUB_STEP_SUMMARY + echo "✅ Not applicable (no SDK/CLI source or template changes)" >> $GITHUB_STEP_SUMMARY exit 0 fi - echo "SDK/CLI source files changed:" + echo "SDK/CLI source or template files changed:" echo "$SDK_CLI_CHANGED" CHANGESET_ADDED=$(git diff --diff-filter=AM --name-only "$BASE"..."$HEAD" | grep -E '^\.changeset/[^/]+\.md$' | grep -vxF '.changeset/README.md' || true) CHANGELOG_CHANGED=$(echo "$CHANGED" | grep -E '^CHANGELOG\.md$' || true) From 3426fe13c61a58d2e2fe05a8b78a507923d702c5 Mon Sep 17 00:00:00 2001 From: Ohad Beltzer Date: Sat, 30 May 2026 19:30:46 +0300 Subject: [PATCH 2/6] fix(ci): align changelog gate error message with widened template scope Follows up #1156: the changelog gate now also fires on template/scaffolding path changes, so the failure message should mention template files, not only source. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/squad-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/squad-ci.yml b/.github/workflows/squad-ci.yml index 1772e6308..e87f3f090 100644 --- a/.github/workflows/squad-ci.yml +++ b/.github/workflows/squad-ci.yml @@ -236,7 +236,7 @@ jobs: echo "✅ CHANGELOG.md updated" >> $GITHUB_STEP_SUMMARY exit 0 fi - echo "::error::No changeset or CHANGELOG.md update found, but SDK/CLI source files were changed." + echo "::error::No changeset or CHANGELOG.md update found, but SDK/CLI source or template files were changed." echo "::error::Run 'npx changeset add' or edit CHANGELOG.md. Escape hatch: add 'skip-changelog' label." echo "❌ No changeset or CHANGELOG.md update" >> $GITHUB_STEP_SUMMARY exit 1 From 3e0ec5a1e1641c3de6e0aa366aa8e9a40b6c6d08 Mon Sep 17 00:00:00 2001 From: Ohad Beltzer Date: Sat, 30 May 2026 19:45:36 +0300 Subject: [PATCH 3/6] refactor(ci): extract changelog-gate path regex into named variable Address PR review feedback on the changelog gate: consolidate the grep -E alternation into a single SDK_CLI_PATH_REGEX variable for readability and safer extension, and document why the whole top-level templates/ tree is governed (it is a canonical mirror of .squad-templates/ per scripts/sync-templates.mjs). No behavioral change. Closes #1156 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/workflows/squad-ci.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/squad-ci.yml b/.github/workflows/squad-ci.yml index e87f3f090..de6ecc2b6 100644 --- a/.github/workflows/squad-ci.yml +++ b/.github/workflows/squad-ci.yml @@ -219,7 +219,12 @@ jobs: BASE="${{ github.event.pull_request.base.sha }}" HEAD="${{ github.event.pull_request.head.sha }}" CHANGED=$(git diff --name-only "$BASE"..."$HEAD") - SDK_CLI_CHANGED=$(echo "$CHANGED" | grep -E '^packages/squad-(sdk|cli)/src/|^packages/squad-(sdk|cli)/templates/|^\.squad-templates/|^templates/' || true) + # Paths whose changes ship behavioral or scaffolding updates and therefore + # require a changeset (or CHANGELOG update). The top-level templates/ tree is + # a full canonical mirror of .squad-templates/ (see scripts/sync-templates.mjs), + # so the entire tree is governed squad scaffolding, not unrelated content. + SDK_CLI_PATH_REGEX='^packages/squad-(sdk|cli)/src/|^packages/squad-(sdk|cli)/templates/|^\.squad-templates/|^templates/' + SDK_CLI_CHANGED=$(echo "$CHANGED" | grep -E "$SDK_CLI_PATH_REGEX" || true) if [ -z "$SDK_CLI_CHANGED" ]; then echo "✅ Not applicable (no SDK/CLI source or template changes)" >> $GITHUB_STEP_SUMMARY exit 0 From ef3135577e78604c13d090eaacd90dea2e33aca0 Mon Sep 17 00:00:00 2001 From: Ohad Beltzer Date: Sat, 30 May 2026 19:51:23 +0300 Subject: [PATCH 4/6] test(ci): add changelog-gate path-matching suite Add test/ci/changelog-gate.test.ts, which reads the live SDK_CLI_PATH_REGEX from .github/workflows/squad-ci.yml and asserts a table of governed paths (src/ + all template trees) match the gate while unrelated paths (docs, root configs, package.json) do not. The test extracts the pattern from the workflow itself so it stays in sync with the gate. Guards the fix for #1156 against regression. Closes #1156 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- test/ci/changelog-gate.test.ts | 55 ++++++++++++++++++++++++++++++++++ 1 file changed, 55 insertions(+) create mode 100644 test/ci/changelog-gate.test.ts diff --git a/test/ci/changelog-gate.test.ts b/test/ci/changelog-gate.test.ts new file mode 100644 index 000000000..4389dad11 --- /dev/null +++ b/test/ci/changelog-gate.test.ts @@ -0,0 +1,55 @@ +/** + * Reads the live SDK_CLI_PATH_REGEX from the changelog gate workflow so this + * suite stays in sync with CI path matching. Guards issue #1156 against + * regressions in governed source/template paths. + */ + +import { describe, it, expect } from 'vitest'; +import { readFileSync } from 'node:fs'; +import path, { dirname } from 'node:path'; +import { fileURLToPath } from 'node:url'; + +const __dirname = dirname(fileURLToPath(import.meta.url)); +const workflowPath = path.resolve(__dirname, '..', '..', '.github', 'workflows', 'squad-ci.yml'); +const workflow = readFileSync(workflowPath, 'utf-8'); +const patternMatch = workflow.match(/SDK_CLI_PATH_REGEX='([^']+)'/); + +expect(patternMatch, 'Expected changelog gate SDK_CLI_PATH_REGEX to be defined in squad-ci.yml').not.toBeNull(); + +const pattern = patternMatch?.[1] ?? ''; +const regex = new RegExp(pattern); + +const governedPaths = [ + 'packages/squad-sdk/src/index.ts', + 'packages/squad-cli/src/cli/core/bootstrap.ts', + 'packages/squad-sdk/templates/skills/example/SKILL.md', + 'packages/squad-cli/templates/scaffold/agent.md', + '.squad-templates/squad.agent.md', + '.squad-templates/scribe-charter.md', + 'templates/skills/release-process/SKILL.md', + 'templates/casting/policy.json', +]; + +const unrelatedPaths = [ + 'README.md', + 'docs/guide/intro.md', + '.github/workflows/squad-ci.yml', + 'package.json', + 'packages/squad-cli/package.json', + 'scripts/bump-build.mjs', + 'test/ci/changelog-gate.test.ts', +]; + +describe('changelog gate path matching', () => { + describe('governed paths require a changeset', () => { + it.each(governedPaths)('%s', filePath => { + expect(regex.test(filePath)).toBe(true); + }); + }); + + describe('unrelated paths are not gated', () => { + it.each(unrelatedPaths)('%s', filePath => { + expect(regex.test(filePath)).toBe(false); + }); + }); +}); From 89db44d81ae2ca3f3fc6f95ab42e783f8ff997d5 Mon Sep 17 00:00:00 2001 From: Ohad Beltzer Date: Sat, 30 May 2026 20:09:15 +0300 Subject: [PATCH 5/6] docs(changeset): document changelog-gate template-path widening Closes #1156 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .changeset/widen-changelog-gate-template-paths.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 .changeset/widen-changelog-gate-template-paths.md diff --git a/.changeset/widen-changelog-gate-template-paths.md b/.changeset/widen-changelog-gate-template-paths.md new file mode 100644 index 000000000..38a59667a --- /dev/null +++ b/.changeset/widen-changelog-gate-template-paths.md @@ -0,0 +1,7 @@ +--- +'@bradygaster/squad-cli': patch +--- + +Widen changelog-gate coverage for template and scaffolding paths + +Previously, the changelog gate only required a changeset for `packages/squad-(sdk|cli)/src/` changes, so template and scaffolding updates under `packages/squad-(sdk|cli)/templates/`, `.squad-templates/`, and top-level `templates/` could reach users with no release-note entry. This widens the gate to those paths so user-facing template changes are no longer silently omitted from release notes. Closes #1156. From 72402629cfde2402233f13662d2a54383840fb1c Mon Sep 17 00:00:00 2001 From: Ohad Beltzer Date: Sat, 6 Jun 2026 18:50:52 +0300 Subject: [PATCH 6/6] fix(ci): cover .squad/agents charters, fix gate docs and test hygiene Address review on #1195: - Add .squad/agents/*/charter.md to SDK_CLI_PATH_REGEX (final #1156 bypass path) - Correct the templates/ comment: append-only superset of .squad-templates/, not a full mirror - Update CONTRIBUTING.md changeset-gate scope to match the widened gate - Wrap the regex-presence assertion in beforeAll so YAML drift surfaces as a readable failure - Extend the gate test with governed/unrelated .squad/agents cases Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../widen-changelog-gate-template-paths.md | 2 +- .github/workflows/squad-ci.yml | 7 ++++--- CONTRIBUTING.md | 8 ++++---- test/ci/changelog-gate.test.ts | 16 ++++++++++++---- 4 files changed, 21 insertions(+), 12 deletions(-) diff --git a/.changeset/widen-changelog-gate-template-paths.md b/.changeset/widen-changelog-gate-template-paths.md index 38a59667a..31563a7e3 100644 --- a/.changeset/widen-changelog-gate-template-paths.md +++ b/.changeset/widen-changelog-gate-template-paths.md @@ -4,4 +4,4 @@ Widen changelog-gate coverage for template and scaffolding paths -Previously, the changelog gate only required a changeset for `packages/squad-(sdk|cli)/src/` changes, so template and scaffolding updates under `packages/squad-(sdk|cli)/templates/`, `.squad-templates/`, and top-level `templates/` could reach users with no release-note entry. This widens the gate to those paths so user-facing template changes are no longer silently omitted from release notes. Closes #1156. +Previously, the changelog gate only required a changeset for `packages/squad-(sdk|cli)/src/` changes, so template and scaffolding updates under `packages/squad-(sdk|cli)/templates/`, `.squad-templates/`, top-level `templates/`, and agent charters under `.squad/agents/*/charter.md` could reach users with no release-note entry. This widens the gate to those paths so user-facing template and scaffolding changes are no longer silently omitted from release notes. Closes #1156. diff --git a/.github/workflows/squad-ci.yml b/.github/workflows/squad-ci.yml index de6ecc2b6..2a9b6aa70 100644 --- a/.github/workflows/squad-ci.yml +++ b/.github/workflows/squad-ci.yml @@ -221,9 +221,10 @@ jobs: CHANGED=$(git diff --name-only "$BASE"..."$HEAD") # Paths whose changes ship behavioral or scaffolding updates and therefore # require a changeset (or CHANGELOG update). The top-level templates/ tree is - # a full canonical mirror of .squad-templates/ (see scripts/sync-templates.mjs), - # so the entire tree is governed squad scaffolding, not unrelated content. - SDK_CLI_PATH_REGEX='^packages/squad-(sdk|cli)/src/|^packages/squad-(sdk|cli)/templates/|^\.squad-templates/|^templates/' + # the primary sync target of .squad-templates/ (see scripts/sync-templates.mjs) — + # an append-only superset whose entire tree is governed squad scaffolding, not + # unrelated content. Agent charters under .squad/agents/ are likewise governed. + SDK_CLI_PATH_REGEX='^packages/squad-(sdk|cli)/src/|^packages/squad-(sdk|cli)/templates/|^\.squad-templates/|^templates/|^\.squad/agents/.+/charter\.md$' SDK_CLI_CHANGED=$(echo "$CHANGED" | grep -E "$SDK_CLI_PATH_REGEX" || true) if [ -z "$SDK_CLI_CHANGED" ]; then echo "✅ Not applicable (no SDK/CLI source or template changes)" >> $GITHUB_STEP_SUMMARY diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2d2c5548c..8c0eae1c2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -187,7 +187,7 @@ External contributors don't have write access, so the review-to-merge flow has a **Your side (contributor):** -1. ✅ All required CI checks are green (build, test, lint; changeset/CHANGELOG gate only applies when `packages/squad-cli/src/` or `packages/squad-sdk/src/` files change) +1. ✅ All required CI checks are green (build, test, lint; the changeset/CHANGELOG gate applies when `packages/squad-(sdk|cli)/src/` **or** governed template/scaffolding paths change — `packages/squad-(sdk|cli)/templates/`, `.squad-templates/`, top-level `templates/`, and `.squad/agents/*/charter.md`) 2. ✅ PR is no longer a draft — mark as **"Ready for review"** 3. ✅ Copilot reviewer bot posts its review automatically 4. ✅ Review Copilot's suggestions and manually apply any you agree with in your fork @@ -214,7 +214,7 @@ An automated readiness check runs on every PR and posts a checklist comment. Add | **Not in draft** | Mark your PR as "Ready for review" when it's done | | **Branch up to date** | Rebase on latest `dev` (`git fetch upstream && git rebase upstream/dev`) | | **Copilot review** | Wait for the Copilot reviewer bot to post its review | -| **Changeset present** | Run `npx changeset add` if you changed files in `packages/squad-sdk/src/` or `packages/squad-cli/src/` | +| **Changeset present** | Run `npx changeset add` if you changed `packages/squad-(sdk|cli)/src/` or governed template/scaffolding paths (`packages/squad-(sdk|cli)/templates/`, `.squad-templates/`, top-level `templates/`, `.squad/agents/*/charter.md`) | | **No merge conflicts** | Resolve any conflicts with the target branch | | **CI passing** | All CI checks (build, test, lint) must be green | @@ -277,7 +277,7 @@ npm unlink -w packages/squad-cli Squad uses [@changesets/cli](https://github.com/changesets/changesets) for independent package versioning. -**When your PR changes SDK or CLI source files** (`packages/squad-sdk/src/` or `packages/squad-cli/src/`), add a changeset file instead of editing `CHANGELOG.md` directly. Changesets prevent merge conflicts when multiple PRs are open simultaneously and are the preferred workflow. +**When your PR changes SDK or CLI source files** (`packages/squad-sdk/src/` or `packages/squad-cli/src/`) **or governed template/scaffolding paths** (`packages/squad-(sdk|cli)/templates/`, `.squad-templates/`, top-level `templates/`, or `.squad/agents/*/charter.md`), add a changeset file instead of editing `CHANGELOG.md` directly. Changesets prevent merge conflicts when multiple PRs are open simultaneously and are the preferred workflow. ### Adding a Changeset @@ -321,7 +321,7 @@ Add streaming support to agent orchestration. Update CLI to display stream progr ### CI Changelog Gate -The `changelog-gate` CI check enforces that PRs touching SDK/CLI source files include either: +The `changelog-gate` CI check enforces that PRs touching SDK/CLI source files — or governed template/scaffolding paths (`packages/squad-(sdk|cli)/templates/`, `.squad-templates/`, top-level `templates/`, `.squad/agents/*/charter.md`) — include either: - A `.changeset/*.md` file (preferred), **or** - A direct `CHANGELOG.md` edit (backward-compatible) diff --git a/test/ci/changelog-gate.test.ts b/test/ci/changelog-gate.test.ts index 4389dad11..59d96e559 100644 --- a/test/ci/changelog-gate.test.ts +++ b/test/ci/changelog-gate.test.ts @@ -4,7 +4,7 @@ * regressions in governed source/template paths. */ -import { describe, it, expect } from 'vitest'; +import { describe, it, expect, beforeAll } from 'vitest'; import { readFileSync } from 'node:fs'; import path, { dirname } from 'node:path'; import { fileURLToPath } from 'node:url'; @@ -14,10 +14,15 @@ const workflowPath = path.resolve(__dirname, '..', '..', '.github', 'workflows', const workflow = readFileSync(workflowPath, 'utf-8'); const patternMatch = workflow.match(/SDK_CLI_PATH_REGEX='([^']+)'/); -expect(patternMatch, 'Expected changelog gate SDK_CLI_PATH_REGEX to be defined in squad-ci.yml').not.toBeNull(); +let regex: RegExp; -const pattern = patternMatch?.[1] ?? ''; -const regex = new RegExp(pattern); +beforeAll(() => { + expect( + patternMatch, + 'Expected changelog gate SDK_CLI_PATH_REGEX to be defined in squad-ci.yml', + ).not.toBeNull(); + regex = new RegExp(patternMatch?.[1] ?? ''); +}); const governedPaths = [ 'packages/squad-sdk/src/index.ts', @@ -28,6 +33,7 @@ const governedPaths = [ '.squad-templates/scribe-charter.md', 'templates/skills/release-process/SKILL.md', 'templates/casting/policy.json', + '.squad/agents/troi/charter.md', ]; const unrelatedPaths = [ @@ -38,6 +44,8 @@ const unrelatedPaths = [ 'packages/squad-cli/package.json', 'scripts/bump-build.mjs', 'test/ci/changelog-gate.test.ts', + '.squad/agents/troi/notes.md', + '.squad/routing.md', ]; describe('changelog gate path matching', () => {