Run CI
Run your project's CI script on your machine with sdxc ci, narrow it while you work, and sign a green commit off on GitHub so the hosted run can skip it.
Last updated
After reading this guide, you will know
- Which script
sdxc ciruns, and which workspaces a run covers - What each flag changes, and when a run signs a commit off
- How to sign off later, check a signoff, and find a run's logs
sdxc ci runs your project's CI script, the same script GitHub Actions runs, on your machine.
When every step passes on a clean tree, it marks the commit green on GitHub:
sdxc ciIt prints one line per step as it finishes, with a failed step's output under it, and exits 0 when every step passed and 1 when one failed. Writing the script itself is covered in Run CI on your machine.
Where it runs
sdxc ci looks for the script from the current directory upward: the nearest project whose
ci.script file exists wins. That is .config/sdxc/ci.ts unless
.config/sdxc.jsonc names another one. With no script at or above
the current directory, it exits 2 and names the default path.
Run it from a workspace below that project, such as one app in a monorepo, and the run keeps
that workspace's matrix entries and those of every workspace that depends on it, exactly as
--scope does:
cd apps/blog
sdxc ciBefore the script
A local run starts with the package manager's frozen-lockfile install:
bun install --frozen-lockfile, npm ci, pnpm install --frozen-lockfile or
yarn install --immutable. A lockfile out of step with a package.json fails the run before
any step starts. Pass --no-install to start from the node_modules you have.
A remote run skips the install, since the CI host's workflow installs first. A run is remote
when the CI environment variable is set to anything but 0 or false, or with
--runner remote.
Flags
--only <pattern>and--skip <pattern>keep or leave out steps, groups and matrix entries by name. Repeat them to give several.*matches across/, and a matrix entry isMatrix/key:--only "Workspaces/@acme/ui".--scope <workspace>keeps the matrix entries for a workspace, by path or name, and its dependents.--rerun-failedruns only the steps the last recorded run failed.--runner local|remoteruns as on your machine or as on a CI host.--pushpushes the tested commit to its upstream branch after a green run, then signs off, and exits 1 when either fails.--no-signoffturns the script'sci.signoffinto a plain success that posts nothing.--no-cacheruns every step, including those whose inputs match an earlier pass.--concurrency <n>caps how many steps run at once; the machine's available parallelism by default.--remote <name>is the git remote to push to and read the GitHub repository from; the upstream's by default, elseorigin.--token-env <NAME>names the variable holding the GitHub token,GITHUB_TOKENby default. When it is unset,gh auth tokensupplies one.-v, --verboseprints every step's log, passing steps included.--jsonprints the run's report as JSON, with the log folder in it.
sdxc ci --only Test
sdxc ci --skip "Workspaces/*" --no-cache
sdxc ci --pushA run narrowed by --only, --skip, --scope or --rerun-failed never signs off, so a
commit turns green only from a run of every step. A usage error, such as a filter that matches
nothing, exits 2.
Sign off
When the script calls ci.signoff on a passing local run, sdxc ci posts an sdxc/ci commit
status on GitHub. It signs off only when the run:
ran every step,
started and ended with no uncommitted or untracked files,
ended on the same commit it started on,
tested a commit GitHub already has;
--pushpushes exactly that commit first.
A run that passes these guards but finds the commit missing on GitHub keeps a record of the green run. Push the commit, then post that record without running the script again:
sdxc ci signoff
sdxc ci signoff 1d9090458It signs off HEAD, or the commit you name, and exits 1 when no green run is recorded for it.
Check a signoff
sdxc ci verify answers whether a contributor signed a commit off, which is what a hosted
workflow asks before it decides to skip its own run:
sdxc ci verify "$GITHUB_SHA" --wait 60sIt exits 0 when the commit has a successful sdxc/ci status from someone with write, maintain
or admin permission on the repository, 1 when it has none, and 2 when GitHub cannot be reached.
--wait polls until a signoff appears or the time passes (30s, 2m, 500ms), and
--repo owner/name names the repository when the git remote cannot.
List the steps
sdxc ci list prints the steps and matrix entries a fully passing run takes, running none of
them. It takes the same --only, --skip, --scope and --runner filters. With --matrix,
it prints one matrix's entry keys, which is how a GitHub Actions workflow builds its job matrix:
sdxc ci list --runner remote --matrix Workspaces --json["@acme/ui","@acme/blog"]Logs and cache
Every run keeps each step's full log in the repository's git directory, under
sdxc-ci/runs/, and prints that run's folder as its last line. The last 20 runs stay, and
--rerun-failed reads the most recent one. Cached step passes live beside them, and a pass no
run has reused in 30 days is pruned.
To start both over, remove them:
sdxc ci cleanRecorded green runs stay, so sdxc ci signoff still works for them.
Where to go next
Run CI on your machine — write the script's steps, parallel groups and workspace matrix, and set up the workflow that skips signed-off commits.
Check a project — what
sdxc doctorchecks in the script's Doctor step.Deploy — ship the commit you just signed off.
Configuration — point
ci.scriptat another file.