Baremetal documentation
What will you use this computer for?
Your terminal
Manage Baremetal from this computer
See queues, investigate jobs and manage your fleet with the CLI. Sign in with your account; this computer stays a client.
Set up the CLI →Your runner host
Run CI jobs on this computer
Connect an Apple Silicon Mac, Linux KVM host or Proxmox node. Its host agent or connector provides capacity for runner VMs.
Connect a runner host →One computer can have both roles. Each has its own setup, credentials and lifecycle.
Manage Baremetal with the CLI
Install baremetal on the computer where you use your terminal or AI tools. The CLI installation does not add a machine, install virtualization or start a host service.
curl -fsSL https://baremetal.run/cli/install.sh | sh
The current published CLI requires Node.js 22 or newer. Standalone installers are not yet released.
baremetal --help baremetal login baremetal status --json
AI integrations give tools such as Codex and Claude Code instructions for using the CLI. They are separate from the host agent that runs jobs. See the CLI guide for the currently available integrations.
CLI logout or replacement does not disconnect a runner host. A host uses its own machine identity and continues without a personal CLI session.
Statistics, comparisons & Wrapped
The Statistics tab records jobs that can be matched to a Baremetal runner, with its pool, machine and allocated resources. Monthly totals use UTC completion dates. Missing events or jobs from before collection may be absent. A GitHub reconciliation scan can repair accessible history for runners already recorded by Baremetal.
Choose your comparison runner and full own costs before using savings figures. Comparisons assume the same job duration, round each job up to a minute, and exclude GitHub storage and subscriptions. Standard public runners are free; larger runners are paid. Linux x64 standard can use your plan allowance; other standard comparisons require an explicit available credit. These are estimates, not a reproduction of your invoice.
Share cards are private until you publish their preview. Public snapshots exclude repository, workflow and machine names. Shared links can be revoked; downloaded images cannot. Monthly Wrapped emails are optional, independently of operational emails, and include an unsubscribe link. Go to Team & settings to choose recipients.
Everything you need to point the Macs and Linux machines you own at GitHub and start running ephemeral CI in minutes.
Overview
Baremetal runs your GitHub Actions jobs on Macs and Linux machines you own, as ephemeral, single-use VMs. You bring a GitHub org or repo and your hardware; Baremetal connects them, scales runners to demand, and tears each VM down after its job.
The moving parts: an account (your sign-in), a workspace (a shared fleet and its members), one or more connected orgs (GitHub organizations or repositories), machines (runner hosts), and pools (how many runners of which image to keep warm).
Requirements
macOS runners need:
- An Apple Silicon Mac (M1 or newer) running a recent macOS.
- Homebrew installed (for Tart and Node, which the agent uses).
- The Mac plugged into power — sleep is disabled so runners stay available.
Linux runners need any Linux box with KVM (hardware virtualization, /dev/kvm) and QEMU — the installer provisions these. Each job runs in a fresh, ephemeral KVM virtual machine with its own kernel, so Docker, service containers, and nested KVM all work inside it (no Apple hardware needed).
You connect either a whole GitHub organization or a single repository (including a private repo on a personal account) that you can administer — that’s where the GitHub App is created. Intel Macs and Windows are not supported as native runner hosts. Windows runner guests run on Linux/KVM; CLI client support is a separate requirement.
1 · Connect a GitHub account
- Sign in and open your workspace, then go to Connect.
- Choose your runner target — an organization (runners shared by every repo) or a single repository — then follow the guided flow. It creates a GitHub App scoped to exactly that target with only the permissions needed to register self-hosted runners.
- Install the app on your org or repo when prompted.
The app’s private key stays in restricted storage on the control plane, separate from the product database and your runner machines. You can rotate or revoke it from GitHub at any time. See the security model for details.
2 · Connect a runner host
In your workspace, open Add machine and mint a one-time join token. Run the generated command on the computer that will run CI jobs, which may be a different computer from your terminal. The installer detects the platform automatically.
curl -fsSL https://baremetal.run/install.sh | bash -s -- cjt_your_token
No CLI installation or personal account login is required on this host. The one-time token verifies the target workspace. Before system changes, the installer displays the computer, workspace and planned services.
macOS (Apple Silicon): runs the agent under launchd. It clones an ephemeral Tart VM per job, runs the runner inside with a single-job config, and destroys it afterwards. Requires Tart and Node; disables idle sleep on power so runners stay online.
Linux: runs the agent as a systemd service, which boots an ephemeral KVM virtual machine per job (a copy-on-write clone of a cloud image), runs the runner inside it, and destroys it afterwards. Requires KVM (/dev/kvm) and QEMU, which the installer provisions.
The machine appears on your dashboard within a minute. Join tokens are single-use and expire after 15 minutes — mint a fresh one per machine.
3 · Pools & images
A pool tells Baremetal how many runners of a given image to keep ready for an org. Set the image (for example a macOS Tahoe base image), the VM size (CPU and memory), and the desired count.
A pool is demand, not hardware. You don’t attach machines to a pool — your machines are shared capacity for the whole workspace, and Baremetal schedules each pool’s runners onto whichever machines have a free slot. One machine can run runners for two different pools or orgs at once; a pool’s runners can land on any of your machines of the matching platform.
Each pool has a platform, chosen when you create it: macOS (an ephemeral Tart VM per job, on your Macs) or Linux (an ephemeral KVM virtual machine per job, on your Linux boxes).
- Desired count — the warm-runner target. Set it to zero if runners should be created only when jobs arrive; a positive target keeps idle runners ready when capacity permits.
- Labels — the runner labels your workflows target with
runs-on. - Image — a macOS pool takes any Tart-compatible macOS image; a Linux pool takes a cloud image (an Ubuntu cloud
qcow2URL). Images are cached on your machines so jobs start fast.
Sizing & capacity
Each Mac contributes up to two concurrent macOS VMs. The resource scheduler also checks the host’s CPU, memory, configured reserves and per-machine ceiling. Size guests for the build and leave resources for the host operating system.
On Linux, concurrency is bounded by CPU, memory and configured per-machine limits. If there is no room for a runner, the job waits for capacity; adding demand does not create more physical resources.
4 · Run a workflow
Point a workflow at your pool’s labels and push:
jobs:
build:
runs-on: [self-hosted, macos, arm64]
steps:
- uses: actions/checkout@v4
- run: xcodebuild test ...Each run is handed a fresh VM. When the job ends, the VM — and everything in it — is destroyed. Watch live workers, VMs, and capacity on your dashboard.
If a job does not start, follow the queued-job troubleshooting checklist to check labels, repository access and available capacity.
Before migrating more workflows, review what survives an ephemeral runner job and compare the options with the runner cost calculator.
How it works
The flow for a single job:
- A workflow needs a runner with your pool’s labels.
- Baremetal mints a just-in-time, single-job runner registration token using your GitHub App key (which never leaves the backend).
- The Baremetal agent on one of your machines boots a fresh runner environment — a Tart VM on macOS, a KVM VM on Linux.
- It registers as an ephemeral runner and executes the job.
- The environment is destroyed; the registration is cleaned up.
Everything is outbound: your machines dial the cloud; nothing reaches in, so there are no inbound ports to open. macOS runners are built on the open-source Tart VM engine; Linux runners on QEMU/KVM and the official actions/runner.
Public repositories
A workflow triggered by a pull request on a public repo runs the contributor’s code — anyone on the internet can open a PR, so treat it as untrusted. Baremetal contains this on the runner side: every VM runs on an isolated, egress-filtered network (Linux via nftables, macOS via Tart Softnet), so a job can reach the public internet and DNS but not your LAN, internal services, the cloud metadata endpoint, the host, or other runners. It’s single-use and destroyed after one job.
A few controls live on GitHub’s side, not Baremetal’s — set these on any public repo that uses self-hosted runners:
- Require approval for fork PRs. Settings → Actions → “Fork pull request workflows” → require approval for all outside collaborators (ideally all external contributors), so a runner only starts after a maintainer eyeballs the PR.
- Restrict the runner group. Keep public-repo runners in their own group so a public repo can’t grab a runner meant for private work.
- Default
GITHUB_TOKENto read-only —permissions: contents: read— and grant more only where a job needs it. - Never combine
pull_request_targetwith a checkout and build of the PR head — that runs untrusted code with write-scoped secrets.
Removing a machine
To take a machine out of your fleet, run the installer's uninstall mode on that machine:
curl -fsSL https://baremetal.run/install.sh | bash -s -- uninstall
This removes the Baremetal agent (its systemd or launchd service, saved identity, and any in-flight runners) and deregisters the machine from your workspace — it disappears from the dashboard and its GitHub runner registrations are cleaned up. QEMU, Tart, and Node are left installed.
No longer have access to the host? You can also revoke a machine from Overview → Machines in the dashboard — the agent stops itself on its next check-in. Running uninstall on the host is still the way to remove the local agent and its files.
Troubleshooting
- My Mac isn’t showing up
- For an enrolled Mac, use the installer’s
repairmode to preserve its identity. For a first installation, use a fresh join token (single-use, valid for 15 minutes). Check the agent logs — on macOS at~/.baremetal/agent.log, on Linux withjournalctl -u baremetal-agent. - Jobs queue but never pick up
- Check that the workflow’s
runs-onlabels match an enabled pool and that a compatible runner host or Proxmox connection is online with available capacity. The warm-runner target can be zero: queued jobs still trigger runner creation. Usebaremetal why <run-or-job-URL> --jsonto inspect the queue’s current reason. - “Integration not found” when connecting
- The GitHub App wasn’t fully created or installed. Re-run Connect and complete both the create and install steps.
- Runners stop overnight
- The Mac is sleeping. Keep it on power; the installer disables idle sleep, but a closed lid can still suspend it.