Concepts
Workflow routing
Use attempt-aware runner labels to make local execution fail safe.The routing contract
GitHub cannot move a job that is already queued to a scale set onto a hosted runner. Mirage therefore makes a whole-workflow replay the fail-safe boundary.
Three supported profiles
jobs:
linux-x64:
runs-on: ${{ github.run_attempt == '1' && 'mirage-linux-x64' || 'ubuntu-24.04' }}
steps:
- run: uname -m
linux-arm64:
runs-on: ${{ github.run_attempt == '1' && 'mirage-linux-arm64' || 'ubuntu-24.04-arm' }}
steps:
- run: uname -m
macos-arm64:
runs-on: ${{ github.run_attempt == '1' && 'mirage-macos-arm64' || 'macos-26' }}
steps:
- run: swift --versionRunner profiles
| Profile | Attempt 1 | Attempt 2 | Guest |
|---|---|---|---|
| Linux x64 | mirage-linux-x64 | ubuntu-24.04 | Containerization + Rosetta |
| Linux arm64 | mirage-linux-arm64 | ubuntu-24.04-arm | Containerization |
| macOS arm64 | mirage-macos-arm64 | macos-26 | Tart |
Design for a one-slot machine
The default dogfood fleet advertises one VM slot. Chain jobs that must fit on one machine instead of starting them in parallel.
Sequential jobs
jobs:
build:
runs-on: ${{ github.run_attempt == '1' && 'mirage-linux-arm64' || 'ubuntu-24.04-arm' }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- run: pnpm build
test:
needs: build
runs-on: ${{ github.run_attempt == '1' && 'mirage-linux-arm64' || 'ubuntu-24.04-arm' }}
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
- run: pnpm testA replay applies to the whole workflow, so deploys, payments, notifications, and other side effects must remain idempotent.
Direct labels
A literal runs-on: mirage-linux-arm64 is useful for a local-only smoke test, but it cannot switch to hosted compute on a re-run.