runner supply for GitHub Actions
ushr schedules GitHub Actions jobs onto hardware you already own: ephemeral VMs, just-in-time runner registration, one priority queue across every org. Your workflows don't change. Your bill does.
GitHub scopes self-hosted runners to a single org. Share hardware across orgs the traditional way and you're installing a separate runner service per org on every machine, partitioning the fleet by hand, and watching one org's Macs sit idle while another org queues.
ushr unpins the hardware. One agent serves all your orgs; every job gets a fresh runner minted just-in-time into whichever org is next by priority and age. The busiest queue gets the iron.
And the iron is virtualised: each Mac hosts two isolated macOS VMs (Apple's licensing ceiling), a Linux box holds as many runners as its cores and memory allow, and the agent runs anywhere you can boot it, including inside a VM.
An M4 Pro against GitHub's 3-vCPU macOS slice isn't a fair fight: real builds finish in roughly half the wall-clock. Your jobs get whole performance cores and local NVMe, not a rented sliver of someone else's box.
Caches never cross the network either. Hosted runners start empty every run: download the tarball, unpack, re-upload. ushr keeps per-repo build caches on the machine, so warm layers load at disk speed and Docker builds skip straight to what changed.
And there's no capacity queue in front of your fleet: dispatch is measured in milliseconds, not "waiting for a runner".
The control plane is a scheduling brain, nothing more. Your agent dials out; queue metadata goes up, dispatch decisions come down. The GitHub App key stays on your machine, mints just-in-time runner tokens locally, and your runners talk to GitHub directly.
There is no credential to breach on our side, because we never hold one. That's not a policy, it's the wire protocol.
scheduler · dispatch ledger · analytics
polls GitHub · mints JIT tokens · provisions VMs
[key] never leaves this box
One line installs the CLI and agent on any Apple Silicon Mac or Linux box. No toolchain, checksummed binaries.
One guided command per machine: missing prereqs offered as installs, browser approval, your GitHub App created with the key written to your machine (not ours), agent service started. Tart, Lume or Docker isolation; each runner serves one job, then it's gone.
runs-on: [self-hosted, macos] and you're routed. ushr dispatches by label, priority and age across every org you run, from one queue.
$ curl -fsSL https://get.ushr.io | sh
==> Downloading ushr (darwin/arm64)
==> Installed ushr 0.2.3 to ~/.local/bin
$ ushr login
==> Wrote default agent config: ~/.config/ushr/agent.yaml
==> tart image "runner-mac" present ✓
==> Opening https://ushr.io/cli/auth…
==> Confirmation code: KTX-42P
==> Waiting for approval........ ✓
✓ Enrolled agent "mini-01" for org(s) acme-eng
✓ ushr-agent service running
Target jobs with: runs-on: [self-hosted, macOS, ARM64]real output, not a mockup: a fresh machine to a live runner in two commands
GitHub-hosted macOS runners bill at $0.062 a minute. A Mac mini on your shelf bills at zero. Drag the slider to your team's monthly runner-minutes and watch the invoice unhappen.
the receipts
$ ushr cost
ushr cost: last 30 days (rate $0.062/runner-min)
ORG JOBS RUNNER-MIN SAVED
acme-eng 412 9840 $610.08
acme-labs 96 2310 $143.22
TOTAL 508 12150 $753.30real subcommand, ships in the CLI
ushr.io schedules across your fleet while your hardware does the work. Keys, code and secrets never cross the wire. Early access is rolling out now.