# Runner labels

Choose a runs-on label: each provider’s resources, fallback label, limits, and runner image.

A job’s `runs-on` label selects its provider, operating system, architecture, and resources.
This page lists the recommended labels and what each one provides.

To route jobs in an existing workflow, open a [setup pull request](https://mirageci.com/docs/ci-providers.md#adapt-a-job)
instead of editing `runs-on` yourself. Mirage writes the routing for each job you select and
keeps the runner it uses today as its fallback. Use the labels below when you write a
workflow by hand, as in [Configure workflows](https://mirageci.com/docs/workflow-routing.md), or to check what a
job will get.

## Available labels

### Your machines

| Label | OS and architecture | Default resources per job | GitHub fallback | Limits |
| --- | --- | --- | --- | --- |
| `mirage-linux-arm64` | Linux arm64 | 2 CPUs, 8 GiB memory, 6 GiB disk | `ubuntu-24.04-arm` | Docker supported. systemd is not guaranteed. |
| `mirage-linux-x64` | Linux x64 | 2 CPUs, 8 GiB memory, 6 GiB disk | `ubuntu-24.04` | Docker supported. systemd is not guaranteed. A Mac needs Rosetta. |
| `mirage-macos-arm64` | macOS 26 arm64 | 4 CPUs, 4.5 GiB memory, 8 GiB disk | `macos-26` | Needs a ready macOS profile. |

These labels use the **Local infrastructure** provider. They run on any machine available to
your account whose matching profile is Ready: a paired Mac, a Linux host, or a Proxmox
cluster. Jobs ask for their own sizes on hosts with resource allocations; set them in **Job routes**
in Repos. Whoever controls the machine changes its budget in **Settings** on the machine page.

The GitHub fallback is the hosted label to use in the attempt expression for the same
operating system and architecture; see [How fallback works](https://mirageci.com/docs/workflow-routing.md#fallback).
A literal `mirage-*` label never falls back: a job on one fails if no machine takes it within
the repository’s [queue timeout](https://mirageci.com/docs/workflow-routing.md#queue-timeout).
A job that asks only for Mirage labels and names an unsupported label, such as
`mirage-windows-x64`, fails within seconds with an error that lists the supported labels.

### Cloudflare

| Label | vCPU | Memory | Disk |
| --- | --- | --- | --- |
| `mirage-cloudflare-lite` | 1/16 | 256 MiB | 2,000 MB |
| `mirage-cloudflare-basic` | 1/4 | 1,024 MiB | 4,000 MB |
| `mirage-cloudflare-standard-1` | 1/2 | 4,096 MiB | 8,000 MB |
| `mirage-cloudflare-standard-2` | 1 | 6,144 MiB | 12,000 MB |
| `mirage-cloudflare-standard-3` | 2 | 8,192 MiB | 16,000 MB |
| `mirage-cloudflare-ubuntu-latest` | 2 | 8,192 MiB | 16,000 MB |
| `mirage-cloudflare-standard-4` | 4 | 12,288 MiB | 20,000 MB |

Every Cloudflare label runs Linux x64 with no GitHub fallback. Cloudflare runners do not
support Docker or fork pull requests. You can also request a [custom
size](#cloudflare-sizes).

## Choose an architecture

Choose the architecture your toolchain supports, then use the matching fallback label. On an
Apple-silicon Mac:

- **Linux arm64 runs natively.** Prefer `mirage-linux-arm64` when your tools, dependencies,
  and container images publish arm64 builds.
- **Linux x64 runs through Rosetta.** Install Rosetta on the Mac before using
  `mirage-linux-x64`, and expect x64 jobs to run slower than arm64 jobs. Use it when a tool
  or dependency only ships for x64.

A Linux host runs only its own architecture, and a Proxmox connector runs the architecture
of its template. Cloudflare runners are Linux x64 only. See [Set up a
Mac](https://mirageci.com/docs/local-mac.md#runner-profiles) to install Rosetta or enable macOS runners.

## Limits by provider

- **Local Linux:** each job gets a disposable Linux guest with Docker and passwordless
  `sudo`. Docker commands, service containers, job containers, and Docker container actions
  work. A job must not assume that systemd is PID 1; see [Tools, secrets, and
  caches](https://mirageci.com/docs/workflow-routing.md#dependencies).
- **macOS:** the Mac must have macOS runners enabled and the profile Ready, which needs an
  active desktop login. A Mac runs at most two macOS jobs at once.
- **Cloudflare:** Linux x64 only. Docker commands, Docker container actions, service
  containers, and job containers are not supported. Fork pull requests are not admitted, and
  the repository needs Cloudflare turned on in [Repos](https://mirageci.com/repos). See [Cloudflare
  runners](https://mirageci.com/docs/cloudflare.md#when-to-use).

Every Mirage label works only in private repositories connected to the Mirage GitHub App.

## Cloudflare sizes

Select one Cloudflare label for each job. `mirage-cloudflare-ubuntu-latest` is an alias for
standard-3, not a promise of GitHub’s Ubuntu image contents. Account quotas may limit which
sizes or how many concurrent jobs you can run.

For a custom size, use whole-number vCPU, memory in MiB, and disk in MB:

Custom Cloudflare runner · 2 vCPU, 8 GiB memory, 16 GB disk:

```yaml
runs-on: mirage-cloudflare-vcpu:2-memory_mib:8192-disk_mb:16000
```

Custom sizes allow 1–4 vCPUs, at least 3,072 MiB memory per vCPU, and at most 12,288 MiB
memory. Disk is capped at 20,000 MB and 2 GB per GiB of memory. A job whose Cloudflare
labels are invalid, or name more than one size, fails before its steps run; its log lists
the problem.

## What the runner image includes

### Linux on your machines

Linux jobs on your machines run in Mirage’s runner image. It is based on GitHub’s official
`ghcr.io/actions/actions-runner` image, which uses Ubuntu 24.04, and adds:

- Docker Engine and CLI, Buildx, and Compose;
- passwordless `sudo`;
- Git, Git LFS, the GitHub CLI (`gh`), `jq`, `yq`, and ShellCheck;
- SSH, transfer, and archive tools such as `curl`, `wget`, `rsync`, `zip`, `xz`, and `zstd`;
- Python 3 with `pip` and `venv`;
- build-essential, CMake, Ninja, Clang, LLD, autotools, `pkg-config`, and common
  native-library headers.

It is not a copy of GitHub’s `ubuntu-latest` image. Select language versions with setup
actions such as `actions/setup-node`, `actions/setup-python`, `actions/setup-java`, and
`actions/setup-go`, or a Rust toolchain action. Install other packages in the job with
`sudo apt-get install`.

The image is not available to pull. To try a build in a similar environment, start from
Ubuntu 24.04 and install the same packages. This does not include the Actions runner or
Mirage’s start-up scripts.

Dockerfile · approximate the Linux runner image:

```dockerfile
FROM ubuntu:24.04
RUN apt-get update && apt-get install -y --no-install-recommends \
    autoconf automake bc build-essential busybox-static bzip2 \
    ca-certificates clang cmake curl docker-buildx docker-compose-v2 \
    docker.io file gh git git-lfs gnupg jq libbz2-dev libffi-dev liblzma-dev \
    libreadline-dev libsqlite3-dev libssl-dev libtool libyaml-dev lld \
    locales make ninja-build openssh-client openssh-server patch pkg-config python3 \
    python3-pip python3-venv rsync shellcheck software-properties-common \
    sudo tar unzip util-linux wget xz-utils yq zip zlib1g-dev zstd
```

### Cloudflare

Cloudflare runners use a separate, smaller Ubuntu 24.04 image. Jobs run as an unprivileged
user without `sudo`, so they cannot install system packages. The image includes Git, Git LFS,
Node.js 22 with Corepack, Python 3, build-essential, CMake, Ninja, `pkg-config`, `jq`,
`curl`, `wget`, `rsync`, SSH, and archive tools. Setup actions that download a tool, such as
`actions/setup-node`, work as usual. The `docker` command exits with an error.

### macOS

macOS jobs run in a macOS 26 virtual machine with Xcode installed. The job’s user has
passwordless `sudo`.

## Lint workflows with actionlint

[actionlint](https://github.com/rhysd/actionlint) reports runner labels it does not know,
such as `mirage-linux-arm64`. Declare Mirage’s labels as self-hosted runner labels in
`.github/actionlint.yaml`:

.github/actionlint.yaml:

```yaml
self-hosted-runner:
  labels:
    - mirage-linux-x64
    - mirage-linux-arm64
    - mirage-macos-arm64
    - mirage-cloudflare-*
```

actionlint accepts glob patterns in this list, so `mirage-cloudflare-*` covers the preset
and custom Cloudflare sizes.
