runnerd
runnerd runs ephemeral GitHub Actions runners on a Linux host: one fresh container per job, from one pool shared by the repositories you configure, kept inside a memory and CPU budget.
It is in early development: the daemon schedules runners, records every job, serves a JSON API and a web dashboard, and runnerctl reads and controls it from a terminal.
First run
On a Linux host with Docker:
|
Serve only private repositories: on a public one, anyone who opens a pull request can run code on this host (Configuration).
runnerd init writes two files and changes nothing else:
~/.config/runnerd/runnerd.toml: the repositories, and one profile with slots of up to 8G, one per 4 CPUs, inside three quarters of the host's memory (or the slice'sMemoryMaxif that is smaller), sorunnerd check-configpasses;~/.config/systemd/user/runnerd.service: a user unit runningrunnerd servewith that config.
It then runs runnerd doctor and prints what is left as commands. It prints the ones that need root and never runs
them; on a fresh host they are usually the slice, sized for this host, and Sysbox. Run the commands your init
printed, not a copy from elsewhere.
Then start the service. The config's profile runs this release's published image,
ghcr.io/ayagmar/runnerd-runner:base-<version>, which runnerd pulls before the first runner. Published images are
linux/amd64 only today, so on aarch64 runners do not start yet.
init never replaces a file unless given --force. --slice names another slice, --config writes the config
elsewhere.
Install
The installer downloads runnerd and runnerctl for Linux x86_64 or aarch64, checks their SHA-256, copies them to
~/.local/bin and runs runnerd doctor. It never uses sudo. To pick the directory or the release:
|
For v0.0.3 and earlier, run that release's own install.sh. Every release archive, install.sh and sha256.sum has
a GitHub build provenance attestation:
From crates.io the daemon is runnerd and runnerctl is in runnerd-cli. cargo install needs Rust 1.99 or later;
cargo binstall downloads the release archives instead:
Requirements
- Linux with cgroup v2, and Docker using the systemd cgroup driver.
- Sysbox, so each runner container can run its own Docker Engine without being privileged.
- A systemd slice whose
MemoryMaxis the budget for all runners;runnerd initprints one sized for the host. - The GitHub CLI, logged in with the
reposcope.
runnerd doctor checks each of these and prints the fix for what is missing.
Documentation
The site, https://ayagmar.github.io/runnerd/, has the guides:
- Install: requirements,
runnerd init's output, verifying a release. - Configuration:
runnerd.toml, profiles, runner images, the budget check, isolation. - Running: the service unit and
systemctl, how runners are scheduled and caches kept warm, the job history, and the JSON API and its events. - Dashboard and CLI: the web dashboard, every
runnerctlcommand, andrunnerctl tuiwith its keys.
ARCHITECTURE.md says where the code lives and docs/adr why.
Building
The toolchain is pinned in rust-toolchain.toml. Before sending a change, run the checks listed under "The gate" in
AGENTS.md; CI runs the same. CONTRIBUTING.md explains which CI jobs a change
triggers and how a release is cut.
The tests that start real containers are ignored by default. They need Docker with sysbox and the images:
License
MIT