| title | GitHub Action |
|---|---|
| section | Integrations |
| order | 1 |
Run SpecSync in CI with zero setup. Auto-detects OS/arch, downloads the binary, runs validation.
- uses: CorvidLabs/spec-sync@v6.1.2
with:
version: '6.1.2'
strict: 'true'
require-coverage: '100'The stable GitHub 6.1.2 binary is published. The immutable @v6.1.2 examples
explicitly select it because that tag's embedded default remains 6.1.1.
| Input | Default | Description |
|---|---|---|
version |
6.1.2 |
Release version to download. Pin an exact release for gates; latest follows the newest release and can change underneath you. The published @v6.0.0 Action tag still defaults to 6.0.0-rc.14; always pass version: '6.0.0' when using that tag. |
download-base-url |
'' |
Optional trusted release mirror URL for enterprise mirrors and release validation |
strict |
false |
Treat warnings as errors |
require-coverage |
0 |
Minimum file coverage % (0–100) |
root |
. |
Project root directory |
args |
'' |
Extra whitespace-separated CLI arguments passed to specsync check; shell quoting is not supported |
lifecycle-enforce |
false |
Run lifecycle enforcement after the strict spec check |
require-archived |
false |
Run the archive gate first. Fails before downloading or running anything when an SDD change under .specsync/changes/ is still open. Repositories without .specsync/changes/ pass. Needs python3 on the runner |
archive-gate-only |
false |
Run only the archive gate (implies require-archived) and skip the download, spec check and comment. Use it in a first job that every other job needs: |
comment |
false |
Post spec drift results as a PR comment. Requires pull_request event and write permissions |
token |
${{ github.token }} |
GitHub token for posting PR comments. Override if using a PAT for cross-repo access |
name: Spec Check
on: [push, pull_request]
jobs:
specsync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
- uses: CorvidLabs/spec-sync@v6.1.2
with:
version: '6.1.2'
strict: 'true'
require-coverage: '100'Release archives and their .sha256 files are both fetched from the selected source. A missing or mismatched checksum fails before extraction. Treat download-base-url as a trust boundary and configure it only with an organization-controlled mirror.
Pin both the Action ref and its binary version. Candidate YAML examples pin @v6.1.2 with
version: '6.1.2'. This separately verified main wrapper defaults to the published
6.1.2 binary; the immutable @v6.1.2 tag retains default 6.1.1.
- uses: CorvidLabs/spec-sync@v6.1.2
with:
version: '6.1.2'
strict: 'true'Always pass version: '6.0.0' with @v6.0.0. That tag's composite Action still embeds
default 6.0.0-rc.14 (the last RC with assets when the tag was cut). Omitting version on
that tag downloads the RC binary. Immutable @v6.1.2 retains default 6.1.1;
explicitly pass version: '6.1.2' with it for the new stable binary. This later main
wrapper defaults to 6.1.2 after actual stable asset and supported-platform Action
checks. Floating @v6 advances only after consumer checks of this exact wrapper
commit. Neither immutable @v6.1.2 nor @v6.0.0 is retargeted.
Every SDD change must be archived (specsync change ship) before a pull request
merges. The archive gate makes that the first thing CI checks: one cheap job runs
the gate, and every other job depends on it, so a commit with an open change under
.specsync/changes/ stops in seconds and nothing else runs.
name: CI
on: [push, pull_request]
jobs:
archive:
name: Archive
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
# The archive gate inputs are newer than v6.1.1, which ignores them. 6.1.2 is the
# first release that includes them.
- uses: CorvidLabs/spec-sync@v6.1.2
with:
version: '6.1.2'
archive-gate-only: 'true'
specsync:
needs: archive
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
- uses: CorvidLabs/spec-sync@v6.1.2
with:
version: '6.1.2'
strict: 'true'
require-coverage: '100'
test:
needs: archive
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- run: echo "your tests"Make a job that depends on everything the required status check. GitHub treats a
skipped job as passing, so a required check on a job that archive skipped would
let the pull request merge. Use an aggregate job with if: always() that fails
unless archive and the others succeeded.
The gate needs no SpecSync binary. It prints the same sentence as the Archive
check, naming the change to archive first and the command to run (for example
specsync change ship <id>). The step also sets the archived output to true or
false.
To gate a single job instead, add require-archived: 'true' to an ordinary
invocation. The gate then runs before the download and the spec check.
The @v6.1.1 and earlier tags predate these inputs. On those tags GitHub warns about
an unexpected input and skips nothing, so archive-gate-only would pass without
gating anything. Use @v6.1.2 or later.
With the gate in place, the lifecycle runs locally up to ship: change check <id> --commit, fledge lanes run verify, change review, then change ship.
Push the archived tip, and CI runs the full lane on it.
Post spec drift results directly on pull requests. SpecSync runs specsync comment and posts (or updates) a check-summary comment.
name: Spec Check
on:
pull_request:
types: [opened, synchronize]
jobs:
specsync:
runs-on: ubuntu-latest
permissions:
pull-requests: write
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
- uses: CorvidLabs/spec-sync@v6.1.2
with:
version: '6.1.2'
strict: 'true'
comment: 'true'How it works:
- Runs
specsync check --force(always validates all specs — the hash cache is not committed to git) - If
comment: 'true', also runsspecsync comment - Posts the markdown output as a PR comment (or updates an existing SpecSync comment)
- Requires
pull-requests: writepermission and thepull_requestevent trigger
Custom token (e.g., for private registries or cross-repo refs):
- uses: CorvidLabs/spec-sync@v6.1.2
with:
version: '6.1.2'
comment: 'true'
token: ${{ secrets.MY_PAT }}jobs:
specsync:
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v5
with:
fetch-depth: 0
- uses: CorvidLabs/spec-sync@v6.1.2
with:
version: '6.1.2'
strict: 'true'- uses: CorvidLabs/spec-sync@v6.1.2
with:
version: '6.1.2'
root: './packages/backend'
strict: 'true'- name: Install specsync
run: |
curl -sL https://github.com/CorvidLabs/spec-sync/releases/download/v6.1.2/specsync-linux-x86_64.tar.gz | tar xz
sudo mv specsync-linux-x86_64 /usr/local/bin/specsync
- name: Spec check
run: specsync check --strict --require-coverage 100| Platform | Binary |
|---|---|
| Linux x86_64 | specsync-linux-x86_64 |
| Linux x86_64 (static musl, any distro) | specsync-linux-x86_64-musl |
| Linux aarch64 | specsync-linux-aarch64 |
| macOS x86_64 | specsync-macos-x86_64 |
| macOS aarch64 (Apple Silicon) | specsync-macos-aarch64 |
Windows is not a supported target as of 6.0 — no Windows binary is published. Run SpecSync
under WSL, or build it from source with cargo install specsync.