Skip to main content
A GitHub Actions job moves to Zode by changing its runs-on. Nothing else in the workflow changes: the runner image looks like GitHub’s ubuntu-24.04, the job runs as the runner user in /home/runner/work, and actions/cache, the cache: option of the setup-* actions and Buildx type=gha keep working.

Before you start

An owner or admin installs the Zode GitHub App once, in the console under Configure, CI, and picks the repositories. See CI for the app’s permissions and the monthly cap.

The one-line switch

That line alone gets you:
  • Standby runners. A repository that ran a job in the last 30 minutes keeps a runner already started and connected to GitHub, so the next job of that size starts without waiting for a machine. Standby time is not billed.
  • Warm snapshots. A green job on the default branch leaves its caches, checkout, tool cache and Docker images on a disk the next job of the same key starts from. See Warm snapshots for what is kept and who may write it.
  • A local Actions cache. Each node answers GitHub’s cache API, so restores come from the node’s disk instead of GitHub’s storage, with GitHub’s branch rules.
Use ubuntu-24.04, not ubuntu-latest, as the GitHub side when you compare: GitHub’s ubuntu-latest moved to Ubuntu 26.04, and Zode’s CI image is 24.04.

The second line: zode-ci test

Sharding and test selection need to know which command runs the tests. Wrap it:
zode-ci is on every Zode runner. It runs the command unchanged, passes its output through, exits with the command’s exit code and stores every test’s result and duration. Nothing zode-ci does on its own (no token, the API down, a report it cannot parse) changes the job’s result. See zode-ci test.

A complete workflow

This is the workflow zodeops/ci-bench runs on Zode for its own tests, as written here:
.github/workflows/test.yml
fetch-depth: 0 gives zode-ci the history it needs to work out what a pull request changed, for test selection. Without it the job still runs and passes; selection just records a full run. At the end of the step the log shows one line per run, for example:

What differs from GitHub-hosted runners

  • Packages installed with apt are not kept between jobs; only the warm disk is.
  • A job that uses actions/setup-go should set cache: false on Zode: the warm disk already has the module cache, and the action’s own restore made helm’s Setup Go 2 to 3 times slower. See Warm snapshots.
  • What the CI image still lacks against GitHub’s is published with every image release in PARITY.md.
  • Speed: a job that finds a ready standby runner starts in about 4 s. Run time per step is still slower than GitHub-hosted on many workloads; we are working on it.