Every job on a machine no other job has touched.
Runners are single-use microVMs. They boot for one job, receive that job's secrets directly from GitHub, and are deleted when it ends.
The life of a job
- 1
Queued
GitHub sends a workflow_job webhook for a job with one of our labels.
- 2
Single-use registration
A just-in-time runner config that can serve this one job only.
- 3
Fresh microVM
A Firecracker VM boots from a clean image, with its own kernel, disk and network.
- 4
Your steps run
Secrets go from GitHub straight to the VM. Nothing from another job is there.
- 5
Destroyed
The VM and its disk are deleted, and the job is billed by the second.
Isolation boundaries
What separates your job from everyone else's, layer by layer.
- Kernel
- Each job has its own Firecracker microVM and guest kernel. Jobs never share a kernel, a container runtime or a process namespace.
- Disk
- A copy-on-write disk over a read-only base image, created for the job and deleted with it.
- Network
- A separate network namespace per VM. VMs cannot reach each other or our management network. Outbound internet only.
- Runner credential
- A just-in-time GitHub runner configuration that registers one runner for one job and expires with it.
Data we keep, and data we do not
The control plane only needs to know that a job ran, where, and for how long.
- We store
- Job metadata from GitHub webhooks: repository, workflow and job name, label, status, timestamps, run URL. Account settings and billing records.
- We never store
- Source code, logs, artifacts, caches, or repository secrets. Logs and artifacts stay on GitHub. The migration wizard reads workflow files when you open it and keeps nothing.
- Payments
- Card details are handled by Stripe. We keep the Stripe customer ID and the ledger of credits.
- Sign-in
- GitHub OAuth. We keep your GitHub user ID, login, name and avatar, and a session cookie that is HttpOnly and Secure.
GitHub App permissions
Every permission the app asks for, and what it is used for. GitHub does not let apps read repository or organization secrets, and the app only acts on jobs whose runs-on uses a Runloft label.
You can install it on selected repositories only, and change that later in GitHub's settings.
- Organization self-hosted runnersRead and write
- Register a just-in-time runner for each job and remove it afterwards. Also how we tell organization owners from members at sign-in.
- AdministrationRead and write
- The same for repositories on personal accounts, where runners are registered per repository.
- ActionsRead
- Job status and timing, which is what billing is computed from.
- Contents, Workflows, Pull requestsRead and write
- Only for the migration wizard: read workflow files when you open it, and open a pull request that changes runs-on when you ask. Nothing is committed to a default branch.
- MetadataRead
- Repository names, required by GitHub for every app.
Access and accounts
Dashboard access follows GitHub. Organization owners on GitHub are owners in Runloft; other organization members can view jobs and usage. Removing someone from the GitHub organization removes their access here within an hour.
API tokens are shown once at creation, stored as hashes, and can be revoked at any time from the dashboard.
Found something? Email security@runloft.dev with steps to reproduce. We reply to every report and do not pursue good-faith research.