Repository navigation
feat(gh-aw): add Squad shared component for GitHub Agentic Workflows - #1587
bradygaster wants to merge 8 commits into
Conversation
- Merged 5 pending decisions from .squad/decisions/inbox to .squad/decisions.md: - 2026-03-26: CI deletion guard and source tree canary (Booster) - 2026-03-26: Copilot git safety rules (RETRO) - 2026-03-29: Versioning Policy (Flight) - 2026-04-25: Release Process Skill Update (Booster) - 2026-06-24: Restore always-on coordinator inline-dispatch gate (Procedures) - Added orchestration logs for Flight, FIDO, RETRO, Surgeon agents (Session: 2026-07-24T09:20:10.011Z) - Added session log: locked PR merge strategy for 17 open PRs - Deleted merged inbox files (.squad/decisions/inbox/*) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Adapt Peli de Halleux's proven Squad × gh-aw integration (github/gh-aw) into this repo. The shared component bootstraps Squad in the gh-aw activation job and restores its state into the agent job, so the Squad CLI never runs inside the network-restricted agent sandbox. - .github/workflows/shared/squad.md: importable component (no `on:`), activation/agent split preserved, App-token > SQUAD_GITHUB_TOKEN > github.token auth ladder intact. Pins `--state-backend local` because the agent runs with `--disable-builtin-mcps`; documents repo-local and SHA-pinned remote import shapes; drops the inaccurate `--agent squad` claim in favor of gh-aw's `.github/agents/*.agent.md` pickup. - .github/workflows/squad-backlog-triage.md (+ compiled .lock.yml): sample workflow_dispatch workflow that imports the component and triages this repo's issues. Compiled clean with gh aw compile v0.81.6 (strict, 0 errors). - docs: new features/gh-aw.md page (+ nav) covering the job split, both import shapes, optional App-token vars/secrets, SQUAD_CLI_VERSION, and the known limitations (no cross-run state, npm required in activation, no MCP state bridge). - test: sync EXPECTED_GUIDES with agent-framework-integration (drifted since #1574) so docs-build passes; add cspell words (Peli, mcps). Design credit: Peli de Halleux https://github.com/github/gh-aw/blob/main/.github/workflows/shared/squad.md Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
🟠 Impact Analysis — PR #1587Risk tier: 🟠 HIGH 📊 Summary
🎯 Risk Factors
📦 Modules Affectedci-workflows (3 files)
docs (2 files)
root (2 files)
squad-state (1 file)
tests (1 file)
This report is generated automatically for every PR. See #733 for details. |
🛫 PR Readiness Check
PR Scope: 🔧 Infrastructure
|
| Status | Check | Details |
|---|---|---|
| ❌ | Single commit | 8 commits — consider squashing before review |
| ✅ | Not in draft | Ready for review |
| ❌ | Branch up to date | dev is 1 commit(s) ahead — rebase recommended |
| ❌ | Copilot review | No Copilot review yet — it may still be processing |
| ✅ | Changeset present | No source files changed — changeset not required |
| ✅ | Scope clean | |
| ✅ | No merge conflicts | No merge conflicts |
| ❌ | Copilot threads resolved | 1 unresolved Copilot thread(s) — fix and resolve before merging |
| ❌ | CI passing | 1 check(s) failing: Lint workflows and templates |
Files Changed (9 files, +2099 −2)
| File | +/− |
|---|---|
.github/workflows/shared/squad.md |
+150 −0 |
.github/workflows/squad-backlog-triage.lock.yml |
+1599 −0 |
.github/workflows/squad-backlog-triage.md |
+92 −0 |
.squad/agents/fido/history.md |
+38 −1 |
aw.yml |
+4 −0 |
cspell.json |
+2 −0 |
docs/src/content/docs/features/gh-aw.md |
+211 −0 |
docs/src/navigation.ts |
+1 −0 |
test/docs-build.test.ts |
+2 −1 |
Total: +2099 −2
This check runs automatically on every push. Fix any ❌ items and push again.
See CONTRIBUTING.md and PR Requirements for details.
|
🔒 Security Review🔒 Security review: 29 warning(s), 4 info.
Automated security review — informational only. |
🏗️ Architectural Review
Automated architectural review — informational only. |
There was a problem hiding this comment.
Pull request overview
This PR introduces a Squad × GitHub Agentic Workflows (gh-aw) integration by adding a reusable shared workflow component, a sample consuming workflow (plus compiled lock), and end-user documentation so Squad can be bootstrapped in the activation job and then used in the agent job without running the Squad CLI inside the restricted sandbox.
Changes:
- Added an importable shared component at
.github/workflows/shared/squad.mdthat performssquad initduring activation and hands off state via an artifact. - Added a sample
workflow_dispatchbacklog-triage workflow (.github/workflows/squad-backlog-triage.md) and committed its compiled.lock.yml. - Added docs + nav wiring for the new
gh-awfeature page, and synced the docs-build test expectations.
Show a summary per file
| File | Description |
|---|---|
| test/docs-build.test.ts | Updates expected docs directory lists to include new content. |
| docs/src/navigation.ts | Adds “GitHub Agentic Workflows” to the Features nav section. |
| docs/src/content/docs/features/gh-aw.md | Documents how the gh-aw activation/agent split works and how to import the shared component. |
| cspell.json | Adds dictionary entries for new terminology/names used in docs. |
| .squad/agents/fido/history.md | Records the gh-aw integration ship note in FIDO history. |
| .github/workflows/squad-backlog-triage.md | Adds a sample gh-aw workflow source that imports the shared Squad component. |
| .github/workflows/squad-backlog-triage.lock.yml | Adds the compiled gh-aw lock workflow that GitHub Actions will execute. |
| .github/workflows/shared/squad.md | Adds the shared Squad bootstrap component used by gh-aw imports. |
Review details
Suppressed comments (2)
.github/workflows/shared/squad.md:73
- Action reference is a mutable tag (v7.0.1). Since this repo pins Actions to commit SHAs in workflows, it would be safer to pin upload-artifact to the immutable SHA (matching the compiled lock file) so remote importers aren’t relying on a moving tag.
uses: actions/upload-artifact@v7.0.1
.github/workflows/shared/squad.md:85
- Action reference is a mutable tag (v8.0.1). To align with the repo’s workflow security posture, pin download-artifact to an immutable commit SHA (matching the compiled lock file) so consumers get a reproducible dependency graph.
uses: actions/download-artifact@v8.0.1
- Files reviewed: 7/8 changed files
- Comments generated: 1
- Review effort level: Lite
| - name: Mint Squad GitHub App token | ||
| id: squad-app-token | ||
| if: ${{ vars.SQUAD_GITHUB_APP_ID != '' }} | ||
| uses: actions/create-github-app-token@v3.2.0 |
|
Verification note — the Published Tracked separately in #1588. Out of scope here (this PR touches no Everything else verified against the published tarballs rather than local source, since that is what the workflow consumes:
Still unproven: no end-to-end gh-aw run has ever executed. |
Add `--ignore-scripts` to the activation-job `npx` in the gh-aw Squad shared component so npm lifecycle scripts don't execute during CI install — a supply-chain hardening measure suggested by Peli de Halleux in review of #1587. squad-cli@0.11.0 ships a postinstall (patch-esm-imports.mjs + patch-ink-rendering.mjs). patch-esm-imports patches vscode-jsonrpc for Copilot SDK sessions (#449), but `squad init` is pure file scaffolding and never opens a session. Verified byte-identical `.squad/` output with and without the flag on Node 24, so skipping scripts is safe. Header comment added so it isn't removed. Recompiled the lock with `gh aw compile` (v0.81.6, strict) — the lock run line matches the source byte-for-byte. Docs table updated to match. docs-build 22/22. Refs #1587 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Applied Peli's review suggestion: added What changed
Why it's safe (not a blind accept) A/B verified on Node v24.16.0 (the version the patch targets):
Validation: (Re: the 109KB compiled lock shrinking in the next AW release — noted, informational, no action here.) |
| # handoff with retention-days: 1) — every run starts from a fresh `squad init`. | ||
| engine: | ||
| id: copilot | ||
|
|
There was a problem hiding this comment.
@copilot add agent: squad to emit --agent squad
…ream Sync PR #1587 with Peli de Halleux's revised gh-aw Squad component, taking only the parts that compile on our pinned gh aw v0.81.6: - shared/squad.md: add engine.agent: squad (compiler emits --agent squad); correct the stale header note that misattributed a '--agent' error; note that ambient-folders (gh-aw main, unreleased) will supersede the manual artifact upload/download once it ships. - squad-backlog-triage.md: adopt the fail-fast pre-agent-steps preflight that emits a noop safe-output when Squad files are missing; align prompt body. - Recompiled lock (gh aw compile --strict: 0 errors, 0 warnings); lock now carries --agent squad. - docs/features/gh-aw.md: document engine.agent, the preflight, and the ambient-folders note. docs-build test passes. Deliberately NOT adopted: top-level ambient-folders key (unknown property on v0.81.6/v0.84.3; rejected by --strict). Kept --ignore-scripts and --state-backend local. Closes #1587 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…quad' Package Squad's ready-made agentic workflows so users can install them with 'gh aw add bradygaster/squad' (Peli de Halleux's suggestion). Uses the verified v0.81.6 schema: - name: required (published docs omit it — validation fails without it) - includes: (not the deprecated 'files:', which emits a codemod warning) - root README.md required for validation (already present) gh aw compile --strict: 0 errors, 0 warnings, no files:-deprecation warning. Docs updated with a 'gh aw add' install section crediting Peli; docs-build test passes (22/22). No new cspell entries required. Closes #1587 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
|
Reviewed. Two things — one safety note, one suggestion. 1.
|
|
Follow-up to my previous comment — here's the concrete patch for the detection idea, so it's directly usable rather than just a question. 1.
|
Adds a build path that produces self-contained Squad bundles vendoring their own Node.js runtime, so installing Squad touches github.com only and never registry.npmjs.org. This is the foundation for the distribution work proposed in github#1593, and it closes the limitation Brady documented and deferred in github#1587: the gh-aw activation job currently requires npx, so it cannot run on a self-hosted runner behind a firewall that blocks the npm registry. What is here: - scripts/build-standalone.mjs — builds a bundle for a platform/arch pair. Packs the workspace packages, installs them with --omit=dev --omit=optional, vendors an official Node runtime, and writes a launcher. - scripts/install.sh — POSIX installer that resolves the platform, downloads the matching release asset, verifies it against SHA256SUMS.txt, and links squad onto PATH. Mirrors the shape of gh.io/copilot-install. - .github/workflows/squad-standalone-release.yml — 6-target matrix build that attaches archives plus a combined SHA256SUMS.txt to a release. - docs/src/content/docs/features/standalone-install.md — feature docs, with known limitations stated. Design notes: squad-cli and squad-sdk locate templates/, presets/builtin/ and package.json by walking up from import.meta.url at runtime. The bundle therefore preserves a real directory layout instead of compiling to a single executable, which is why this needs zero source changes. It is also the same shape GitHub's own Copilot CLI publishes. Optional dependencies are omitted by default. That drops the Copilot CLI platform binary pulled in transitively through @github/copilot-sdk (~318 MB), node-pty prebuilds, the OpenTelemetry SDK and sql.js — 546 MB down to 114 MB, in line with Copilot CLI's own ~110 MB archives. Squad already requires the copilot CLI on PATH and Copilot CLI ships npm-free installers of its own, so vendoring a second copy would only add weight and version skew. --ignore-scripts is safe here: the vscode-jsonrpc ESM fix that squad-cli's postinstall applies is also applied at runtime by cli-entry.js via a Module._resolveFilename hook, so the bundle does not depend on it having run. Verified locally on win32-x64: - squad --version from the bundle returns 0.11.0 on its own vendored runtime - squad init --preset default --state-backend local scaffolds 5 agents in a clean directory with no npm involved - generated .github/workflows/squad-heartbeat.yml is byte-identical (sha256 5CE0F5D1...) to the repo template source, confirming the bundle reproduces its source faithfully - docs-build test passes, cspell and markdownlint clean on the new page No packages/*/src changes, so no changeset is required. Refs github#1593, github#1587 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d2a1f506-af41-4d6d-b497-d0a5b255d4cf
…#1593) Second slice of the standalone distribution work. Builds on the bundle mechanism from the previous commit and closes the gap that made it incomplete. The gap: installing Squad from a bundle removed npm from *installation*, but `squad init` still wrote an npx-based `squad_state` MCP entry into `.mcp.json`, and probed registry.npmjs.org to choose the version. On a firewalled machine the CLI installed fine and then the MCP server silently failed to launch on first use — the exact failure mode this work exists to prevent. What changed: - mcp-spec.ts gains a tier-0 ahead of the two npx tiers. When SQUAD_STANDALONE_HOME is set (exported by the bundle launchers) the spec points at that bundle's launcher by absolute path with args ['state-mcp']. It short-circuits before the registry probe, so a machine with no route to npm makes no network call here at all. Absolute because Copilot spawns the MCP server in its own environment, where neither PATH nor that variable is guaranteed. - describeMcpSpec() previously read args[1] to name the package; standalone specs have no package there and would have printed '<unknown>'. It now reports the launcher path. - build-standalone.mjs launchers (sh, cmd, ps1) export SQUAD_STANDALONE_HOME. - .github/actions/squad-init — composite action that installs from a release bundle and runs squad init. This is the direct replacement for the `npx @bradygaster/squad-cli init` step in the gh-aw activation job (#1587). It also fails the build if the resulting .mcp.json still mentions npx. - Dockerfile + .dockerignore — image built from a bundle instead of `npm install -g`, honoring the existing container contract in docs/reference/container-image.md (WORKDIR /app, non-root uid 1001, SIGTERM, `squad watch --execute`). Sets SQUAD_STANDALONE_HOME=/opt/squad. Built with --include-optional because the contract documents OTLP export, which lives in the optional OpenTelemetry packages. - .gitattributes pins LF for Dockerfile and .dockerignore. CRLF breaks RUN line continuations when the image builds on Linux. Verified: - 13 new tests in mcp-spec-init.test.ts, including an explicit assertion that the registry probe never fires in standalone mode. 23/23 pass. - Built a bundle and ran `squad init` from it on win32-x64: the generated .mcp.json contains command=<bundle>/squad.cmd, args=['state-mcp'], no npx. - Runtime stage of the Dockerfile built and exercised on linux/amd64 with a host-built bundle: `squad --version` returns 0.11.0 as the non-root squad user, `which squad` resolves to /opt/squad/squad, `squad init` writes command=/opt/squad/squad, and `squad state-mcp` answers a JSON-RPC initialize handshake with serverInfo.name=squad-state. - lint, docs-build, mcp-root-write, state-mcp, cspell, markdownlint all clean. Not verified: the Dockerfile builder stage. This machine intercepts TLS, so every container gets ERR_SSL_SSL/TLS_ALERT_HANDSHAKE_FAILURE reaching registry.npmjs.org — reproducible with a bare `docker run node:22-slim npm view lodash`. Not a Dockerfile defect, but the full image has never been built end to end and CI must prove it. Likewise the squad-init action cannot run until a release with bundle assets exists. Refs #1593, #1587 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d2a1f506-af41-4d6d-b497-d0a5b255d4cf
) * fix(ci): skip DO-NOT-EDIT gh-aw generated workflows in lint; widen agents guard actionlint v1.7.12 is the current latest release — upgrading cannot fix this. The tool lags GitHub's evolving feature set on two specific constructs: • 'copilot-requests: write' — a real current Actions permission scope used by GitHub's own gh-aw toolchain. • 'concurrency.queue: max' — a newer Actions concurrency feature. The files triggering these errors are DO-NOT-EDIT compiler output from gh-aw's 'gh aw compile' toolchain (*.lock.yml) and gh-aw's code generators (e.g. agentics-maintenance.yml). Editing them is not acceptable — they are clobbered on each compile/generate cycle and are validated upstream by gh-aw's own toolchain. Fix 1 (.github/workflows/squad-workflow-lint.yml): Detect generated files by their header ('automatically generated' / 'DO NOT EDIT' within the first 5 lines) and skip them. Header-based detection automatically covers future gh-aw generated files without manual maintenance. Hand-authored workflows are always linted. Verified with a sabotage test: intentionally broken hand-authored workflow still fails the gate. Skipped files are echoed in CI logs for debuggability. Fix 2 (test/template-sync.test.ts): The '.github/agents/ negative guard' asserted strict directory equality, which over-reaches. 'gh aw init' legitimately installs its own agentic-workflows.md in that directory. Narrowed the guard to its actual intent: squad.agent.md must be present, no *unexpected* files allowed, with an explicit allowlist of known non-Squad agents. A truly random stray file still fails the test. Unblocks PRs #1587 and #1592 (does NOT close them). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix(test): add section-1 beforeAll sync to guard against init-scaffolding race test/init-scaffolding.test.ts runs runInit() from a subdirectory of the repo root. In monorepo mode the init command detects the git root and places squad.agent.md at .github/agents/ in the REAL repo root, then calls stampVersion() to rewrite that file in place. This runs concurrently with template-sync.test.ts in a different Vitest worker. The file-level beforeAll sync in template-sync.test.ts is correct but leaves a race window: if init-scaffolding's stampVersion write lands between the file-level sync and section 1's readFileBytes calls, the byte comparison sees the stamped file (which differs from the canonical) and fails. Fix: add a describe-scoped beforeAll inside section 1 that re-runs the sync immediately before the byte comparisons start. This collapses the race window from 'entire beforeAll + test-collection time' to near-zero. The byte-for-byte assertion itself is unchanged; this only makes the setup more resilient. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…#1593) (#1610) * feat(dist): npm-free MCP spec, squad-init action, and container image (#1593) Second slice of the standalone distribution work. Builds on the bundle mechanism from the previous commit and closes the gap that made it incomplete. The gap: installing Squad from a bundle removed npm from *installation*, but `squad init` still wrote an npx-based `squad_state` MCP entry into `.mcp.json`, and probed registry.npmjs.org to choose the version. On a firewalled machine the CLI installed fine and then the MCP server silently failed to launch on first use — the exact failure mode this work exists to prevent. What changed: - mcp-spec.ts gains a tier-0 ahead of the two npx tiers. When SQUAD_STANDALONE_HOME is set (exported by the bundle launchers) the spec points at that bundle's launcher by absolute path with args ['state-mcp']. It short-circuits before the registry probe, so a machine with no route to npm makes no network call here at all. Absolute because Copilot spawns the MCP server in its own environment, where neither PATH nor that variable is guaranteed. - describeMcpSpec() previously read args[1] to name the package; standalone specs have no package there and would have printed '<unknown>'. It now reports the launcher path. - build-standalone.mjs launchers (sh, cmd, ps1) export SQUAD_STANDALONE_HOME. - .github/actions/squad-init — composite action that installs from a release bundle and runs squad init. This is the direct replacement for the `npx @bradygaster/squad-cli init` step in the gh-aw activation job (#1587). It also fails the build if the resulting .mcp.json still mentions npx. - Dockerfile + .dockerignore — image built from a bundle instead of `npm install -g`, honoring the existing container contract in docs/reference/container-image.md (WORKDIR /app, non-root uid 1001, SIGTERM, `squad watch --execute`). Sets SQUAD_STANDALONE_HOME=/opt/squad. Built with --include-optional because the contract documents OTLP export, which lives in the optional OpenTelemetry packages. - .gitattributes pins LF for Dockerfile and .dockerignore. CRLF breaks RUN line continuations when the image builds on Linux. Verified: - 13 new tests in mcp-spec-init.test.ts, including an explicit assertion that the registry probe never fires in standalone mode. 23/23 pass. - Built a bundle and ran `squad init` from it on win32-x64: the generated .mcp.json contains command=<bundle>/squad.cmd, args=['state-mcp'], no npx. - Runtime stage of the Dockerfile built and exercised on linux/amd64 with a host-built bundle: `squad --version` returns 0.11.0 as the non-root squad user, `which squad` resolves to /opt/squad/squad, `squad init` writes command=/opt/squad/squad, and `squad state-mcp` answers a JSON-RPC initialize handshake with serverInfo.name=squad-state. - lint, docs-build, mcp-root-write, state-mcp, cspell, markdownlint all clean. Not verified: the Dockerfile builder stage. This machine intercepts TLS, so every container gets ERR_SSL_SSL/TLS_ALERT_HANDSHAKE_FAILURE reaching registry.npmjs.org — reproducible with a bare `docker run node:22-slim npm view lodash`. Not a Dockerfile defect, but the full image has never been built end to end and CI must prove it. Likewise the squad-init action cannot run until a release with bundle assets exists. Refs #1593, #1587 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d2a1f506-af41-4d6d-b497-d0a5b255d4cf * fix(action): run the bundled installer and fail on npx MCP specs Addresses both Copilot review comments on #1610. 1. The action fetched scripts/install.sh from the repository HEAD over the network. That is unpinned remote code execution, and the installer could drift from the release tag being installed. It now runs the install.sh that ships alongside the action, resolved from github.action_path. Consumers pin the action to a SHA, so the installer is pinned with it. 2. The npx check only wrote a warning to the step summary and exited 0, which did not match what the PR claimed. An npx-based squad_state entry is unrunnable on exactly the firewalled runners this action targets, and it fails later at Copilot start rather than here, so it now fails the step. Verified the action_path walk resolves correctly on Linux (alpine container: /repo/.github/actions/squad-init -> /repo/scripts/install.sh) rather than assuming the relative depth. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d2a1f506-af41-4d6d-b497-d0a5b255d4cf * fix(dist): cross-build posix bundles from Windows, add build/install tests Found while running the installer end to end for the first time: building a linux or darwin bundle from a Windows host failed. node-v22.20.0-linux-x64/bin/npx: Can't create '...': Invalid argument tar: Error exit delayed from previous errors. The builder extracted the whole Node.js archive, and the posix archives carry symlinks (bin/npm, bin/npx, bin/corepack) that Windows cannot create. Only the node binary is ever shipped, so extraction is now scoped to that single member. Extraction failures also report the underlying tar error instead of a bare non-zero exit. This would have bitten anyone building non-linux targets from a Windows runner, and the release workflow's structural checks would not have caught it. Also adds test/standalone-build.test.ts (11 cases) covering the behaviors that break silently: selective extraction, SQUAD_STANDALONE_HOME in all three launchers, symlink resolution in the posix launcher, optional-dep omission, checksum verification, VERSION/PREFIX/REPO overrides, and an assertion that install.sh never reaches the npm registry. Verified the full install path in a container with no Node and no npm: served a packaged bundle over HTTP, ran the real install.sh against it, and got squad --version -> 0.11.0 through the PATH symlink. Corrupting the asset made the installer abort with a checksum mismatch, as intended. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d2a1f506-af41-4d6d-b497-d0a5b255d4cf --------- Co-authored-by: Tamir Dresher <342800+tamirdresher@users.noreply.github.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d2a1f506-af41-4d6d-b497-d0a5b255d4cf
…) (#1611) * feat(dist): npm-free MCP spec, squad-init action, and container image (#1593) Second slice of the standalone distribution work. Builds on the bundle mechanism from the previous commit and closes the gap that made it incomplete. The gap: installing Squad from a bundle removed npm from *installation*, but `squad init` still wrote an npx-based `squad_state` MCP entry into `.mcp.json`, and probed registry.npmjs.org to choose the version. On a firewalled machine the CLI installed fine and then the MCP server silently failed to launch on first use — the exact failure mode this work exists to prevent. What changed: - mcp-spec.ts gains a tier-0 ahead of the two npx tiers. When SQUAD_STANDALONE_HOME is set (exported by the bundle launchers) the spec points at that bundle's launcher by absolute path with args ['state-mcp']. It short-circuits before the registry probe, so a machine with no route to npm makes no network call here at all. Absolute because Copilot spawns the MCP server in its own environment, where neither PATH nor that variable is guaranteed. - describeMcpSpec() previously read args[1] to name the package; standalone specs have no package there and would have printed '<unknown>'. It now reports the launcher path. - build-standalone.mjs launchers (sh, cmd, ps1) export SQUAD_STANDALONE_HOME. - .github/actions/squad-init — composite action that installs from a release bundle and runs squad init. This is the direct replacement for the `npx @bradygaster/squad-cli init` step in the gh-aw activation job (#1587). It also fails the build if the resulting .mcp.json still mentions npx. - Dockerfile + .dockerignore — image built from a bundle instead of `npm install -g`, honoring the existing container contract in docs/reference/container-image.md (WORKDIR /app, non-root uid 1001, SIGTERM, `squad watch --execute`). Sets SQUAD_STANDALONE_HOME=/opt/squad. Built with --include-optional because the contract documents OTLP export, which lives in the optional OpenTelemetry packages. - .gitattributes pins LF for Dockerfile and .dockerignore. CRLF breaks RUN line continuations when the image builds on Linux. Verified: - 13 new tests in mcp-spec-init.test.ts, including an explicit assertion that the registry probe never fires in standalone mode. 23/23 pass. - Built a bundle and ran `squad init` from it on win32-x64: the generated .mcp.json contains command=<bundle>/squad.cmd, args=['state-mcp'], no npx. - Runtime stage of the Dockerfile built and exercised on linux/amd64 with a host-built bundle: `squad --version` returns 0.11.0 as the non-root squad user, `which squad` resolves to /opt/squad/squad, `squad init` writes command=/opt/squad/squad, and `squad state-mcp` answers a JSON-RPC initialize handshake with serverInfo.name=squad-state. - lint, docs-build, mcp-root-write, state-mcp, cspell, markdownlint all clean. Not verified: the Dockerfile builder stage. This machine intercepts TLS, so every container gets ERR_SSL_SSL/TLS_ALERT_HANDSHAKE_FAILURE reaching registry.npmjs.org — reproducible with a bare `docker run node:22-slim npm view lodash`. Not a Dockerfile defect, but the full image has never been built end to end and CI must prove it. Likewise the squad-init action cannot run until a release with bundle assets exists. Refs #1593, #1587 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d2a1f506-af41-4d6d-b497-d0a5b255d4cf * fix(action): run the bundled installer and fail on npx MCP specs Addresses both Copilot review comments on #1610. 1. The action fetched scripts/install.sh from the repository HEAD over the network. That is unpinned remote code execution, and the installer could drift from the release tag being installed. It now runs the install.sh that ships alongside the action, resolved from github.action_path. Consumers pin the action to a SHA, so the installer is pinned with it. 2. The npx check only wrote a warning to the step summary and exited 0, which did not match what the PR claimed. An npx-based squad_state entry is unrunnable on exactly the firewalled runners this action targets, and it fails later at Copilot start rather than here, so it now fails the step. Verified the action_path walk resolves correctly on Linux (alpine container: /repo/.github/actions/squad-init -> /repo/scripts/install.sh) rather than assuming the relative depth. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d2a1f506-af41-4d6d-b497-d0a5b255d4cf * fix(dist): cross-build posix bundles from Windows, add build/install tests Found while running the installer end to end for the first time: building a linux or darwin bundle from a Windows host failed. node-v22.20.0-linux-x64/bin/npx: Can't create '...': Invalid argument tar: Error exit delayed from previous errors. The builder extracted the whole Node.js archive, and the posix archives carry symlinks (bin/npm, bin/npx, bin/corepack) that Windows cannot create. Only the node binary is ever shipped, so extraction is now scoped to that single member. Extraction failures also report the underlying tar error instead of a bare non-zero exit. This would have bitten anyone building non-linux targets from a Windows runner, and the release workflow's structural checks would not have caught it. Also adds test/standalone-build.test.ts (11 cases) covering the behaviors that break silently: selective extraction, SQUAD_STANDALONE_HOME in all three launchers, symlink resolution in the posix launcher, optional-dep omission, checksum verification, VERSION/PREFIX/REPO overrides, and an assertion that install.sh never reaches the npm registry. Verified the full install path in a container with no Node and no npm: served a packaged bundle over HTTP, ran the real install.sh against it, and got squad --version -> 0.11.0 through the PATH symlink. Corrupting the asset made the installer abort with a checksum mismatch, as intended. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d2a1f506-af41-4d6d-b497-d0a5b255d4cf * feat(dist): Homebrew and winget packaging, plus a real squad.exe (#1593) Third slice of the distribution work. Adds the two package managers people actually expect, and the Windows executable that makes one of them possible. The blocker I found first: winget's portable installer only creates command aliases for .exe targets — .cmd and .bat are explicitly unsupported. Our Windows bundle's entry point was squad.cmd, so a winget manifest would have installed something that could not be invoked. Homebrew has no such restriction and works with the existing shell launcher. So Windows bundles now ship a real squad.exe, built with Node's single executable application support. It is the vendored runtime with a small launcher embedded, so it REPLACES runtime/node.exe rather than adding to the bundle — a Windows bundle is still 114 MB. The launcher resolves the bundle from its own location and follows a symlink if it finds one, because winget installs portables by symlinking the exe into a links directory. Also here: - scripts/generate-packaging.mjs renders the Homebrew cask and the three winget manifests from a release's SHA256SUMS.txt. Both ecosystems embed a version and a per-artifact SHA-256, so hand-maintaining them guarantees they go stale — this is exactly the standing cost flagged in #1593. - The release workflow generates them after publishing and attaches them as an artifact for a maintainer to submit. - mcp-spec now prefers squad.exe over squad.cmd on Windows. Since the fix for CVE-2024-27980 Node refuses to spawn a .cmd without shell:true, so an MCP client spawning the command directly would fail to start squad_state. Two real bugs found while testing, both of which CI would have hit: 1. GNU tar cannot read zip archives; bsdtar (Windows, macOS) can. The release workflow builds every target on ubuntu-latest, so every win32 bundle would have failed to unpack its Node runtime. Now uses unzip on posix hosts, and the workflow installs it for win32 targets. 2. execFileSync with shell:true splits an unquoted command path on spaces, so invoking process.execPath from "C:\Program Files\nodejs" failed. The run() helper now quotes. Verified: - squad.exe, squad.cmd and squad.ps1 all return 0.11.0 from a real bundle - squad init from squad.exe scaffolds 5 agents and writes an npx-free .mcp.json pointing at the bundle launcher - SEA blob is version-locked: a blob built by Node 23.5 injected into the vendored 22.20.0 produced an exe that died with an access violation (0xC0000005). The builder now downloads a matching host Node to generate it. - Cross-build works: a Linux container unzipped the Windows runtime, generated the blob with Linux Node 22.20.0, injected it with postject, and the resulting PE ran correctly on Windows. That is the production path, since the workflow builds all six targets on ubuntu-latest. - Generator output parses as YAML, all three winget manifests agree on identifier/version/schema, and both installers point at .exe - 67 tests pass (18 new for the generator, 8 new for the exe and extraction) Dropped the shebang from generate-packaging.mjs so vitest can import it on Windows; scripts/pr-readiness.mjs, the repo's other importable script, has no shebang either. Worth noting separately: the same shebang interaction is why test/promote-insider-tag.test.ts is one of the pre-existing Windows failures. Left alone as out of scope. Not verified: no winget or Homebrew submission has been made, because neither can be tested without a published release carrying bundle assets. Code signing and notarization are still absent, and injecting the SEA blob invalidates the Node runtime's Authenticode signature, so SmartScreen will warn on Windows. That is the main gap before either package should be recommended widely. Refs #1593 Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Copilot-Session: d2a1f506-af41-4d6d-b497-d0a5b255d4cf * fix(ci): suppress shellcheck SC2016 on Actions expression in release workflow The single-quoted backticks are intentional markdown formatting in the step summary, not shell expressions. Disable SC2016 for those lines. Closes #1611 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Tamir Dresher <342800+tamirdresher@users.noreply.github.com> Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com> Co-authored-by: Brady Gaster <41929050+bradygaster@users.noreply.github.com> Copilot-Session: d2a1f506-af41-4d6d-b497-d0a5b255d4cf
…e workflows) gh aw init had never been run in this repo; this adds the standard scaffolding gh-aw generates for a repository that authors and ships agentic workflows. We are now a gh-aw publisher (.github/workflows/shared/squad.md, squad-backlog-triage.md, aw.yml in PR #1587), so this tooling protects the correctness of what we ship: - .github/skills/agentic-workflows/ and agentic-workflow-designer/: designer / dispatcher skills that keep gh-aw frontmatter and compiled .lock.yml correct. - .github/agents/agentic-workflows.md: the gh-aw authoring sub-agent. - .github/workflows/copilot-setup-steps.yml: lets @copilot run 'gh aw compile' in CI rather than hand-editing generated .lock.yml files. - .github/workflows/agentics-maintenance.yml: REQUIRED because squad-backlog-triage.md uses 'expires: 7' — this workflow closes the gh-aw-created expiring issues/PRs/discussions. - .github/mcp.json: configures the gh-aw MCP server for the CLOUD coding agent. The local-CLI equivalent lives in root .mcp.json and is intentionally NOT included here. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…e workflows) gh aw init had never been run in this repo; this adds the standard scaffolding gh-aw generates for a repository that authors and ships agentic workflows. We are now a gh-aw publisher (.github/workflows/shared/squad.md, squad-backlog-triage.md, aw.yml in PR #1587), so this tooling protects the correctness of what we ship: - .github/skills/agentic-workflows/ and agentic-workflow-designer/: designer / dispatcher skills that keep gh-aw frontmatter and compiled .lock.yml correct. - .github/agents/agentic-workflows.md: the gh-aw authoring sub-agent. - .github/workflows/copilot-setup-steps.yml: lets @copilot run 'gh aw compile' in CI rather than hand-editing generated .lock.yml files. - .github/workflows/agentics-maintenance.yml: REQUIRED because squad-backlog-triage.md uses 'expires: 7' — this workflow closes the gh-aw-created expiring issues/PRs/discussions. - .github/mcp.json: configures the gh-aw MCP server for the CLOUD coding agent. The local-CLI equivalent lives in root .mcp.json and is intentionally NOT included here. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…e workflows) (#1592) * chore(gh-aw): add gh aw init tooling (skills, MCP, setup + maintenance workflows) gh aw init had never been run in this repo; this adds the standard scaffolding gh-aw generates for a repository that authors and ships agentic workflows. We are now a gh-aw publisher (.github/workflows/shared/squad.md, squad-backlog-triage.md, aw.yml in PR #1587), so this tooling protects the correctness of what we ship: - .github/skills/agentic-workflows/ and agentic-workflow-designer/: designer / dispatcher skills that keep gh-aw frontmatter and compiled .lock.yml correct. - .github/agents/agentic-workflows.md: the gh-aw authoring sub-agent. - .github/workflows/copilot-setup-steps.yml: lets @copilot run 'gh aw compile' in CI rather than hand-editing generated .lock.yml files. - .github/workflows/agentics-maintenance.yml: REQUIRED because squad-backlog-triage.md uses 'expires: 7' — this workflow closes the gh-aw-created expiring issues/PRs/discussions. - .github/mcp.json: configures the gh-aw MCP server for the CLOUD coding agent. The local-CLI equivalent lives in root .mcp.json and is intentionally NOT included here. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: address Copilot review threads on gh-aw init PR - Pin actions/checkout to SHA (supply-chain hardening) - Fix MCP tool name: agentic-workflows → github-agentic-workflows - Remove reference to non-existent skills/otel-queries/SKILL.md Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
What this does
Adapts Peli de Halleux's proven Squad × gh-aw (GitHub Agentic Workflows) integration from
github/gh-awinto this repo. Peli built and demonstrated it and explicitly offered it for upstreaming — this is an adaptation of his design, not a rewrite. Credit to Peli.There is no issue to close — this was dispatched directly by Brady off Peli's demonstration.
The architecture (Peli's — preserved exactly)
jobs.activation.pre-steps) runsnpx @bradygaster/squad-cli init, then uploads.squad/+.github/agents/squad.agent.mdas asquad-stateartifact.steps:) downloads and restores that artifact. The Squad CLI never runs in the agent job.This sidesteps gh-aw's network firewall, which only constrains the agent job — activation has open egress. The App-token →
SQUAD_GITHUB_TOKEN→github.tokenauth ladder is kept intact.Deliverables
.github/workflows/shared/squad.md— the importable shared component (noon:field)..github/workflows/squad-backlog-triage.md(+ compiled.lock.yml) — sampleworkflow_dispatchworkflow that imports the component and triages this repo's own issues.docs/src/content/docs/features/gh-aw.md(+ nav entry) — feature documentation.Four intentional changes from Peli's reference
shared/squad.md) and SHA-pinned remote (bradygaster/squad/.github/workflows/shared/squad.md@<sha>), verified against gh-aw's imports reference.--state-backend localpinned on the init command — the compiled agent invocation passes--disable-builtin-mcps, so Squad'sstate-mcpbridge can't load; a non-local backend would fail silently.--agent squadclaim from Peli's header comment — replaced with an accurate description of gh-aw's.github/agents/*.agent.mdsub-agent pickup (there is no--agentflag on the compiled Copilot invocation).SQUAD_CLI_VERSIONdefault kept at0.11.0with a "bump every release" note. See follow-up below.Validation
Compiled locally with
gh aw compile(gh-aw v0.81.6, strict mode, 0 errors). The compiled lock confirmed:npx … init --preset default --state-backend local(line 122)GH_AW_SUB_AGENT_DIR=".github/agents"/GH_AW_SUB_AGENT_EXT=".agent.md"pickup (lines 519–520)--disable-builtin-mcpson the agent invocation (line 814)--agentflag anywheretest/docs-build.test.tspasses 22/22; cspell + markdownlint clean. Action versions (create-github-app-token@v3.2.0,upload-artifact@v7.0.1,download-artifact@v8.0.1) match Peli's reference exactly.Known limitations (documented honestly, in the feature doc)
squad-stateartifact is a within-run handoff (retention-days: 1). Casting registry, session logs, and Scribe output don't survive between runs. Solving this (artifacts / Actions cache / dedicated branch) is unsolved and out of scope.--disable-builtin-mcps).Drive-by fix
EXPECTED_GUIDESintest/docs-build.test.tswas missingagent-framework-integration(added in #1574, never synced) — the docs-build test was already failing ondev. Fixed here since EXPECTED_* sync is FIDO's charter responsibility and the test file was already being edited.Scope / safety
repo-health-shaped: only.github/,docs/,test/, andcspell.json. Nopackages/*/src/changes → no changeset required. Reference copies under.squad/proposals/reference/were not touched.Security note (from
gh aw compile)The compile flagged two new restricted secrets —
SQUAD_GITHUB_APP_PRIVATE_KEYandSQUAD_GITHUB_TOKEN. Both come from the shared component's optional auth ladder (mint a GitHub App token / fall back to a PAT for cross-orgsquad init), are referenced only in the activation job, and default to unused (github.token) when unset. No credential exfiltration or unexpected egress introduced.Design credit: Peli de Halleux — https://github.com/github/gh-aw/blob/main/.github/workflows/shared/squad.md