Skip to content
pilots
Dashboard

GitHub Actions, on a machine per job

Change one line, runs-on: pilots, and every job gets a fresh machine of its own, made when the job is queued and deleted when it ends. It costs 70–74% less than GitHub’s own runners at every size, billed by the second.

Ask your agent

Pilots is driven by your agent, and runners are no different: say what you want, and the agent enables the repository, builds the image and changes the workflow.

  1. Say it

    In Claude Code, Cursor, Codex or any agent with Pilots added.

    Run the GitHub Actions jobs of this repository on Pilots runners.
  2. The agent does the rest

    It enables the repository, starts the runner image, changes runs-on in the workflow and pushes. The one screen that stays yours is GitHub’s own page for installing the pilots app, which the agent links you to the first time.

  3. Or from your terminal

    The same two commands the agent runs, then one line in a workflow.

    curl -fsSL https://pilots.run/install.sh | sh
    pilot runner enable acme/shop
.github/workflows/ci.yml
jobs:
  test:
    runs-on: pilots        # was: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - run: npm ci && npm test

A machine that was already running

A runner is not booted. It is a copy of your team’s runner image, which was photographed with the runner already loaded, so the job starts on a machine that is up from its first moment.

1.0s a runner machine made from its image, median
6s job queued to job started, median
70s the first runner on a host that does not have the image yet

Measured on the production fleet. Hover a number to see how it was taken.

Every job gets a new machine, forked from your ready image, so no job waits for another to free a shared runner and every tool below is already installed when the job starts.

What a minute costs, beside the others

A pilots runner is an ordinary machine, so it costs what any machine costs: processor and memory by the second while it runs. These are those prices multiplied out to a minute, at the sizes the others sell.

Size pilots GitHub-hosted Blacksmith Depot
2 vCPU, 8 GBpilots $0.00156$0.006$0.004$0.006
4 vCPU, 16 GBpilots-4cpu-16gb $0.00312$0.012$0.008$0.012
8 vCPU, 32 GBpilots-8cpu-32gb $0.00624$0.022$0.016$0.024
16 vCPU, 64 GBpilots-16cpu-64gb $0.01248$0.042$0.032$0.048
Free each month 600 minutes 2,000 or 3,000 minutes 3,000 minutes 2,000 minutes

pilots costs 70–74% less than GitHub’s own runners at every size, and less than Blacksmith and Depot too. Depot’s minutes come inside a monthly plan.

Every month starts with about 600 minutes of the default runner free, from the same allowance as your other machines.

pilots charges by the second. A job that takes ninety seconds on the default runner is $0.00234, and a ten-minute one is $0.0156. A runner also writes to its own disk while it exists, which is charged at the disk price for those minutes and comes to a small fraction of a cent.

Rates read from each product’s own pricing page. Hover a figure to see where and when. How runners are billed.

What is on the machine

System
Ubuntu 24.04, with git, git-lfs, the usual build tools and the GitHub CLI
Languages
Node 24, Bun, Go and Python 3 with pip and venv
Browsers
The Playwright browsers, Chromium, Firefox and WebKit, already downloaded
Containers
Docker with compose and buildx
The runner
The GitHub Actions runner, running as a user with passwordless sudo

Sizes

pilots is 2 vCPU, 8 GiB, the shape GitHub gives a private repository, so a workflow that fits there fits here. Name any other size the same way as pilots-4cpu-16gb, up to 32 vCPU, 128 GB.

The image is a template in your team, rebuilt when you ask for it with pilot runner image --fresh.

Each job is alone on its machine

  • A virtual machine per job

    Each job runs in a microVM with its own kernel, alone. It shares no file system, no process list and no network with any other job, yours or anybody else’s.

  • Made for the job, deleted after it

    The machine is made from your team’s image when the job is queued and deleted when it ends. The next job never sees what the last one left behind.

  • A registration good for one job

    GitHub hands out a just-in-time configuration bound to one runner name, usable once. It reaches the machine as the environment of one process, is never written to its disk, and is never logged. No long-lived registration token exists anywhere.

  • Only the labels the job asked for

    A runner registers with exactly its job’s labels, so it cannot take a job meant for self-hosted runners of your own.

  • Where it stops

    A runner is a machine in your team. Anybody on the team can open a shell in one while it runs, and a job’s secrets are in it while the job runs. That is why only a repository administrator can enable a repository.

Good to know

Most CI runs here unchanged. Three facts before you move a whole repository.

  • x86-64 Linux. Runners are Ubuntu 24.04 on x86-64, the platform most GitHub Actions workflows already target.
  • Docker, not nested VMs. Containers, compose and buildx work as they do on GitHub’s runners. A job that boots its own virtual machine, such as an Android emulator, keeps a bare-metal runner.
  • You choose the concurrency. 10 jobs run at once by default, and you can raise it, so a wide matrix is your choice and never a surprise on the bill.

A runner machine is deleted when its job ends, and none is kept past 6 h 15 min.

Questions people ask before moving their CI

Does it work for private repositories?
Yes. A runner is registered for the repository you enable, and the job runs the same way in a private repository as in a public one.
Do jobs on pilots use my GitHub Actions minutes?
No. GitHub does not charge minutes for a job on a self-hosted runner, which is what a pilots runner is to GitHub. You pay pilots for the seconds the machine runs.
Can I keep some jobs on GitHub-hosted runners?
Yes. runs-on is set per job, so a workflow can send one job to pilots and leave the others where they are.
What happens when a job asks for something pilots does not have?
The commit gets a status named pilots runners that says what was wrong and what to write instead. Without it the job would wait in GitHub’s queue for a day with nothing saying why.
Is a runner kept warm between jobs?
No. A runner exists from the moment its job is queued until the job ends, and it is then deleted. Nothing runs, and nothing is charged, while no job is waiting.
Who can send jobs to my team’s machines?
Only a repository somebody enabled, and only a person who administers that repository on GitHub can enable it. The pilots GitHub App is how that is checked.
Can a job use Docker?
Yes. Docker runs inside the runner, with compose and buildx, so docker build, docker compose and service containers such as a Postgres for the tests all work.
Can I install more tools in a job?
Yes. The job runs as a user with passwordless sudo, so a step can install anything with apt or any other installer, as on a GitHub-hosted runner.
Does it cache dependencies between jobs?
Only through GitHub’s own actions/cache, which works as it does anywhere. pilots has no cache storage of its own for runners, and every job starts from the same clean image.

Your app, its sandboxes and its CI on one platform, driven from one command line and on one bill. A runner is the same kind of machine your app runs on.