From e6e61e669ff61b80d3bd75cb4e11708a2f59a2d5 Mon Sep 17 00:00:00 2001 From: brady gaster Date: Mon, 24 Aug 2026 22:20:17 -0700 Subject: [PATCH 1/2] docs(gh-aw): ship advisory review Closes #1736 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- .github/agents.md | 16 +++-- README.md | 3 +- docs/demo-agentic-sdlc-walkthrough.md | 2 +- docs/src/content/docs/guide/gh-aw.md | 95 +++++++++++++++++++-------- test/gh-aw-review-workflow.test.ts | 83 ++++++++++++++++++++++- workflows/shared/squad.md | 5 +- 6 files changed, 165 insertions(+), 39 deletions(-) diff --git a/.github/agents.md b/.github/agents.md index d46d7e3a2..920175397 100644 --- a/.github/agents.md +++ b/.github/agents.md @@ -17,21 +17,25 @@ GitHub Agentic Workflows (`gh-aw`) are composable AI workflows triggered by slas - **GitHub CLI** (`gh`) installed and authenticated — [install guide](https://cli.github.com/) - **`gh aw` extension** available (ships with recent `gh` versions; run `gh aw --help` to verify) -### Install the Squad workflow +### Install the Squad workflows ```bash -gh aw add bradygaster/squad/workflows/squad.md@dev +gh aw add \ + bradygaster/squad/workflows/squad.md@dev \ + bradygaster/squad/workflows/squad-implement-worker.md@dev \ + bradygaster/squad/workflows/squad-review.md@dev ``` This command: -1. Fetches the Squad workflow definition from the source repository -2. Compiles it into a GitHub Actions–compatible workflow -3. Adds the workflow to your repository's `.github/` directory +1. Fetches the Squad dispatcher, implementation worker, and advisory reviewer +2. Compiles them into GitHub Actions–compatible workflows +3. Adds the workflow sources and generated files to your repository's `.github/` directory ### Verify installation -After running the command, confirm the workflow appears in your repository's **Actions** tab. You should see a new workflow named "Squad" (or similar) listed and ready to trigger. +After running the command, confirm the Squad, Squad Implement Worker, and Squad +Review workflows appear in your repository's **Actions** tab. ### Try your first command diff --git a/README.md b/README.md index ff2745dcb..18ae11174 100644 --- a/README.md +++ b/README.md @@ -535,8 +535,9 @@ If you use [GitHub Agentic Workflows](https://github.blog/changelog/2025-05-19-g ```bash gh aw add \ + bradygaster/squad/workflows/squad.md@dev \ bradygaster/squad/workflows/squad-implement-worker.md@dev \ - bradygaster/squad/workflows/squad.md@dev + bradygaster/squad/workflows/squad-review.md@dev gh aw compile git add -- \ .github/workflows/ \ diff --git a/docs/demo-agentic-sdlc-walkthrough.md b/docs/demo-agentic-sdlc-walkthrough.md index 36fe48a33..08310a1f4 100644 --- a/docs/demo-agentic-sdlc-walkthrough.md +++ b/docs/demo-agentic-sdlc-walkthrough.md @@ -3,7 +3,7 @@ > **Duration:** 12–18 minutes > **Audience:** Developers familiar with GitHub and .NET Aspire > **Scenario:** Add real-time notifications via SignalR to a .NET Aspire app using the Squad agentic SDLC -> **Prerequisite:** The presenter has a fresh .NET Aspire app (AppHost, ServiceDefaults, WebFrontend, ApiService) and has installed the Squad workflow via `gh aw add bradygaster/squad/workflows/squad.md@latest`. No squad has been cast yet. +> **Prerequisite:** The presenter has a fresh .NET Aspire app (AppHost, ServiceDefaults, WebFrontend, ApiService) and has installed the dispatcher, implementation worker, and advisory reviewer with the [gh-aw guide's install command](src/content/docs/guide/gh-aw.md#install-the-workflows). No squad has been cast yet. Planning comments remain human-readable. For programmatic discovery, gh-aw appends a validated `Structured data:` JSON block containing `squad_artifact`, `schema_version: "1"`, `origin_issue`, and a `phases` array. The screen excerpts below omit that footer for readability. diff --git a/docs/src/content/docs/guide/gh-aw.md b/docs/src/content/docs/guide/gh-aw.md index a99c1942c..5b5955e87 100644 --- a/docs/src/content/docs/guide/gh-aw.md +++ b/docs/src/content/docs/guide/gh-aw.md @@ -28,8 +28,9 @@ gh api --method PUT repos/{owner}/{repo}/actions/permissions/workflow \ # 3. Add the Squad workflows to your repo gh aw add \ + bradygaster/squad/workflows/squad.md@dev \ bradygaster/squad/workflows/squad-implement-worker.md@dev \ - bradygaster/squad/workflows/squad.md@dev + bradygaster/squad/workflows/squad-review.md@dev # 4. Commit and push the workflow sources and generated files git add -- .gitattributes .github/workflows/ .github/skills/ @@ -82,12 +83,19 @@ approve their own pull requests. ```bash gh aw add \ + bradygaster/squad/workflows/squad.md@dev \ bradygaster/squad/workflows/squad-implement-worker.md@dev \ - bradygaster/squad/workflows/squad.md@dev + bradygaster/squad/workflows/squad-review.md@dev ``` -The single command installs the dedicated worker first, then the main workflow -that dispatches it. +Keep the dispatcher first. `gh aw add` discovers its implementation-worker and +reviewer dependencies while compiling it; the explicit worker and reviewer +entries then confirm the complete install surface without creating duplicates. +The installed top-level workflow set is: + +- `squad.md` and `squad.lock.yml` +- `squad-implement-worker.md` and `squad-implement-worker.lock.yml` +- `squad-review.md` and `squad-review.lock.yml` > **Branch note:** `@dev` pulls from the latest development branch where new modes and fixes land first. Stay on `@dev` to get improvements as they ship. Once gh-aw support reaches stable, you can switch to `@main` or drop the ref entirely for the default branch. @@ -97,12 +105,11 @@ deterministic `.lock.yml` files — no separate compile step is needed. > **Restricted secrets prompt:** During `gh aw add`, you may see a safe-update-mode > warning listing new restricted secrets (`SQUAD_GITHUB_APP_PRIVATE_KEY`, -> `SQUAD_GITHUB_TOKEN`). This is expected. Run with `--approve` to accept the changes: +> `SQUAD_GITHUB_TOKEN`). This is expected. Review the changes, then approve them +> during compilation: > > ```bash -> gh aw add --approve \ -> bradygaster/squad/workflows/squad-implement-worker.md@dev \ -> bradygaster/squad/workflows/squad.md@dev +> gh aw compile --approve > ``` ### Commit the workflow files @@ -210,6 +217,7 @@ wins: `/squad plan accept scope` is not treated as `/squad plan`. | Activation | `/squad plan activate` | Create GitHub issues from an accepted plan | Terminal step; creates real GitHub issues | | Activation | `/squad plan activate phase {N}` | Create GitHub issues for only Phase N | Use when accept didn't auto-activate | | Implementation | `/squad implement` | Implement an issue, or start the next ready wave of an epic | Dispatches an isolated implementation worker | +| Review | `/squad review` | Independently review the current pull request | Advisory `COMMENT` or `REQUEST_CHANGES`; human approval remains mandatory | ### Where you can use slash commands @@ -742,9 +750,9 @@ capability profiles. --- -## Review lifecycle and current gaps +## Review lifecycle -### What review happens during and after `/squad implement` +### What happens during and after `/squad implement` The implementation worker performs an internal self-review before opening a PR: @@ -754,32 +762,60 @@ The implementation worker performs an internal self-review before opening a PR: 4. **Diff review** — the worker reviews its own final diff against the issue acceptance criteria before calling `create-pull-request` 5. **Protected-file guard** — changes to protected paths trigger a review request on the PR rather than a direct commit -After the PR is opened, review follows the standard GitHub flow: human -reviewers, required status checks (CI), and merge by a repository maintainer. -If you configured `GH_AW_CI_TRIGGER_TOKEN`, implementation PRs will trigger -your CI workflows automatically; without it, the default `GITHUB_TOKEN`-created -PRs do not start other workflow runs. +After the PR is opened, `squad-review` provides an independent advisory review. +You can start it in either of these ways: + +- **Manual:** Comment `/squad review` on a same-repository pull request. The main + Squad router relays the pull request number, current head SHA, and manual + origin to the isolated reviewer workflow. +- **Automatic:** A same-repository pull request triggers review on + `ready_for_review` and `synchronize` when it has recognized Squad or Copilot + provenance. Fork pull requests are refused. + +The reviewer classifies provenance in this priority order: + +1. One validated `` worker marker and + its matching `squad/implement-*` branch +2. A `squad/implement-*` branch when no marker-like text is present +3. Author `copilot-swe-agent[bot]` or a `copilot/*` branch when no marker-like + text is present +4. Unattributed -### There is no separate `/squad review` command +Malformed higher-priority evidence fails closed instead of falling through to a +weaker classification. Automatic review refuses unattributed pull requests; +manual review can continue as `Unattributed (manual)`. A +`Squad-Review-Head: ` marker deduplicates review for an unchanged head, and +per-PR concurrency cancels stale runs after a new push. -Squad does not currently have a post-implementation review command. There is no -`/squad review` slash command, and no workflow runs automatically to review PRs -after `/squad implement` opens them. +### Advisory verdicts and reviewer independence -This is a **current lifecycle gap**: the path from an open implementation PR to -merge relies entirely on human review, your existing CI, and normal GitHub PR -processes. If you have a squad member designated as a reviewer, you can ask -them to review the PR in a Copilot Chat session, but that is not an automated -Squad workflow. +The reviewer can add a bounded summary comment, inline review comments, and +exactly one pull request review. It returns: -The lifecycle today is: +- `REQUEST_CHANGES` for a concrete merge blocker, such as an acceptance-criteria + violation, unsafe authority expansion, protected-file violation, missing test, + or required-but-missing changeset +- `COMMENT` when findings are advisory or no merge blocker is established + +The reviewer has no file-editing, workflow-dispatch, issue-creation, +pull-request-creation, remediation, merge, or `APPROVE` authority. Its verdict +does not replace branch protection, required status checks, or a human +reviewer's approval. Human approval remains mandatory. + +The lifecycle is: ``` -/squad implement → implementation PR opened → human review + CI → merge → epic relay (next wave) +/squad implement → implementation PR opened → advisory Squad review → human review + CI → merge → epic relay (next wave) ``` -If a dedicated automated review phase is added in a future release, it will -appear as a new slash command in this guide. +### Advisory fast path + +Because review is advisory, it is possible to merge without waiting for an +automatic review or manually running `/squad review`. That fast path gives up an +independent, head-SHA-specific check of the linked issue's acceptance criteria, +Squad routing and charter compliance, protected-file boundaries, focused tests, +and changeset coverage. Your repository's human approval and required checks +still decide whether the pull request can merge. --- @@ -941,8 +977,9 @@ To update your compiled workflow after pulling upstream changes: ```bash gh aw add \ + bradygaster/squad/workflows/squad.md@dev \ bradygaster/squad/workflows/squad-implement-worker.md@dev \ - bradygaster/squad/workflows/squad.md@dev + bradygaster/squad/workflows/squad-review.md@dev ``` This re-compiles the workflow from source. If you have local customizations in your compiled `.github/workflows/squad-*.lock.yml`, they will be overwritten — keep customizations in the source `.md` files instead. diff --git a/test/gh-aw-review-workflow.test.ts b/test/gh-aw-review-workflow.test.ts index f2e565139..e5ed822d5 100644 --- a/test/gh-aw-review-workflow.test.ts +++ b/test/gh-aw-review-workflow.test.ts @@ -1,5 +1,5 @@ import { afterAll, describe, expect, it } from 'vitest'; -import { cpSync, mkdirSync, mkdtempSync, readFileSync, rmSync } from 'node:fs'; +import { cpSync, mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync } from 'node:fs'; import { execFileSync } from 'node:child_process'; import { tmpdir } from 'node:os'; import { dirname, resolve } from 'node:path'; @@ -8,6 +8,11 @@ import { fileURLToPath } from 'node:url'; const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..'); const REVIEWER = read('workflows/squad-review.md'); const ROUTER = read('workflows/squad.md'); +const GUIDE = read('docs/src/content/docs/guide/gh-aw.md'); +const README = read('README.md'); +const AGENT_GUIDE = read('.github/agents.md'); +const DEMO = read('docs/demo-agentic-sdlc-walkthrough.md'); +const SHARED_BOOTSTRAP = read('workflows/shared/squad.md'); const REVIEWER_FRONTMATTER = frontmatter(REVIEWER); const ROUTER_FRONTMATTER = frontmatter(ROUTER); const compileWorkspaces: string[] = []; @@ -69,6 +74,13 @@ function provenanceRows(workflow: string): string[] { .map(match => `${match[1]}:${match[2].trim()}:${match[3].trim()}`); } +function installOrders(markdown: string): string[][] { + const uncommented = markdown.replace(/^#\s?/gm, ''); + return [...uncommented.matchAll(/gh aw add \\\n((?:\s+bradygaster\/squad\/workflows\/[^\n]+\n?)+)/g)] + .map(block => [...block[1].matchAll(/bradygaster\/squad\/workflows\/([^@\s\\]+\.md)@dev/g)] + .map(match => match[1])); +} + function assertReviewerContract(workflow: string): void { const yaml = frontmatter(workflow); const tools = yamlBlock(yaml, 'tools'); @@ -172,6 +184,75 @@ describe('gh-aw advisory Squad reviewer', () => { expect(relay).toContain('Never call the generic'); }); + it('materializes the documented install as complete source and lock pairs', () => { + const installOrder = installOrders(GUIDE)[0]; + expect(installOrder).toEqual([ + 'squad.md', + 'squad-implement-worker.md', + 'squad-review.md', + ]); + + const workspace = mkdtempSync(resolve(tmpdir(), 'squad-review-install-')); + compileWorkspaces.push(workspace); + const workflowDir = resolve(workspace, '.github', 'workflows'); + mkdirSync(workflowDir, { recursive: true }); + cpSync(resolve(ROOT, 'workflows', 'shared'), resolve(workflowDir, 'shared'), { recursive: true }); + for (const name of installOrder) { + cpSync(resolve(ROOT, 'workflows', name), resolve(workflowDir, name)); + } + execFileSync('git', ['init', '--quiet'], { cwd: workspace }); + for (const name of installOrder) { + execFileSync( + 'gh', + ['aw', 'compile', name.slice(0, -3), '--strict', '--approve', '--no-check-update'], + { cwd: workspace, encoding: 'utf8', stdio: 'pipe' }, + ); + } + + const installed = readdirSync(workflowDir, { withFileTypes: true }) + .filter(entry => entry.isFile()) + .map(entry => entry.name) + .sort(); + expect(installed).toEqual([ + 'squad-implement-worker.lock.yml', + 'squad-implement-worker.md', + 'squad-review.lock.yml', + 'squad-review.md', + 'squad.lock.yml', + 'squad.md', + ]); + }, 30000); + + it('keeps all consumer install surfaces on the coherent three-workflow order', () => { + for (const surface of [GUIDE, README, AGENT_GUIDE, SHARED_BOOTSTRAP]) { + const orders = installOrders(surface); + expect(orders.length).toBeGreaterThan(0); + for (const order of orders) { + expect(order).toEqual([ + 'squad.md', + 'squad-implement-worker.md', + 'squad-review.md', + ]); + } + } + expect(DEMO).toContain("gh-aw guide's install command"); + expect(DEMO).not.toContain('gh aw add bradygaster/squad/workflows/squad.md@latest'); + }); + + it('documents advisory review without claiming enforcement or remediation', () => { + expect(GUIDE).toContain('| Review | `/squad review` |'); + expect(GUIDE).not.toContain('/squad review fix'); + expect(GUIDE).not.toContain('Review lifecycle and current gaps'); + expect(GUIDE).not.toContain('There is no separate `/squad review` command'); + expect(GUIDE).toContain('`ready_for_review` and `synchronize`'); + expect(GUIDE).toContain('`Squad-Review-Head: `'); + expect(GUIDE).toContain('`COMMENT`'); + expect(GUIDE).toContain('`REQUEST_CHANGES`'); + expect(GUIDE).toContain('no file-editing, workflow-dispatch, issue-creation,'); + expect(GUIDE).toContain('Human approval remains mandatory.'); + expect(GUIDE).toContain('Because review is advisory, it is possible to merge without waiting'); + }); + it('enforces attribution priority and refuses malformed or unattributed automatic provenance', () => { expect(REVIEWER).toContain( '^$', diff --git a/workflows/shared/squad.md b/workflows/shared/squad.md index 465d008c6..9a0283347 100644 --- a/workflows/shared/squad.md +++ b/workflows/shared/squad.md @@ -5,7 +5,10 @@ # # This is the DISTRIBUTION version of the bootstrap, living under workflows/shared/ # so users can pull it via: -# gh aw add bradygaster/squad/workflows/squad.md@latest +# gh aw add \ +# bradygaster/squad/workflows/squad.md@dev \ +# bradygaster/squad/workflows/squad-implement-worker.md@dev \ +# bradygaster/squad/workflows/squad-review.md@dev # # Design credit: adapted from Peli de Halleux's proven gh-aw integration in # github/gh-aw. Original: From e363cb3d67449656957d997b2f1be47297ababdd Mon Sep 17 00:00:00 2001 From: brady gaster Date: Mon, 24 Aug 2026 22:27:12 -0700 Subject: [PATCH 2/2] docs(gh-aw): clarify optional compile step Closes #1736 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> --- README.md | 4 +++- docs/src/content/docs/guide/gh-aw.md | 12 +++++++----- test/gh-aw-review-workflow.test.ts | 3 +++ 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 18ae11174..0d1a52177 100644 --- a/README.md +++ b/README.md @@ -538,7 +538,6 @@ gh aw add \ bradygaster/squad/workflows/squad.md@dev \ bradygaster/squad/workflows/squad-implement-worker.md@dev \ bradygaster/squad/workflows/squad-review.md@dev -gh aw compile git add -- \ .github/workflows/ \ .gitattributes @@ -546,6 +545,9 @@ git commit -m "Add Squad workflow" git push ``` +`gh aw add` compiles the workflows automatically. If it reports unapproved +safe-update changes, review them and run `gh aw compile --approve`. + > `@dev` pulls the latest modes and fixes; switch to `@main` once gh-aw support is stable. ### Slash commands diff --git a/docs/src/content/docs/guide/gh-aw.md b/docs/src/content/docs/guide/gh-aw.md index 5b5955e87..cca07592b 100644 --- a/docs/src/content/docs/guide/gh-aw.md +++ b/docs/src/content/docs/guide/gh-aw.md @@ -101,16 +101,18 @@ The installed top-level workflow set is: This registers the Squad workflow in your repository's agentic workflow configuration and automatically compiles the workflow definitions into -deterministic `.lock.yml` files — no separate compile step is needed. +deterministic `.lock.yml` files. Under normal conditions, no separate compile +step is needed. -> **Restricted secrets prompt:** During `gh aw add`, you may see a safe-update-mode -> warning listing new restricted secrets (`SQUAD_GITHUB_APP_PRIVATE_KEY`, -> `SQUAD_GITHUB_TOKEN`). This is expected. Review the changes, then approve them -> during compilation: +> **Safe-update approval:** If `gh aw add` reports unapproved safe-update +> changes for restricted secrets (`SQUAD_GITHUB_APP_PRIVATE_KEY`, +> `SQUAD_GITHUB_TOKEN`), review those changes and complete the approval with: > > ```bash > gh aw compile --approve > ``` +> +> This follow-up is only needed when the safe-update warning appears. ### Commit the workflow files diff --git a/test/gh-aw-review-workflow.test.ts b/test/gh-aw-review-workflow.test.ts index e5ed822d5..38b34bc9f 100644 --- a/test/gh-aw-review-workflow.test.ts +++ b/test/gh-aw-review-workflow.test.ts @@ -251,6 +251,9 @@ describe('gh-aw advisory Squad reviewer', () => { expect(GUIDE).toContain('no file-editing, workflow-dispatch, issue-creation,'); expect(GUIDE).toContain('Human approval remains mandatory.'); expect(GUIDE).toContain('Because review is advisory, it is possible to merge without waiting'); + expect(GUIDE).toContain('This follow-up is only needed when the safe-update warning appears.'); + expect(README).toContain('`gh aw add` compiles the workflows automatically.'); + expect(README).toContain('run `gh aw compile --approve`'); }); it('enforces attribution priority and refuses malformed or unattributed automatic provenance', () => {