@r5n/hydra
v0.9.3
Published
A tool for spawning multiple local GitHub self-hosted runners
Downloads
1,203
Maintainers
Readme
Hydra
Spawn and manage local self-hosted GitHub Actions runners.
Hydra registers runners against a GitHub repository or organization and runs them as background processes on the machine it runs on. All state lives in a .hydra/ directory relative to your current working directory, so each directory you run it from is its own isolated runner fleet.
Requirements
- Bun (the published CLI runs on Bun)
ghCLI, installed and authenticated (gh auth login) — Hydra mints runner registration and removal tokens viagh api; it never asks for or stores a token itself. Repository runners need admin access to the repository; organization runners need theadmin:orgscope.bash,curl,tar- macOS (Apple Silicon) or Linux (x64). A
win-x64runner download mapping exists in the code, but registration and startup shell out tobash config.sh/bash run.sh, so Windows is not actually supported.
Install
bun add -g @r5n/hydraQuick start
mkdir ~/runners && cd ~/runners
hydra init https://github.com/owner/repo -c 2
hydra create
hydra start
hydra statusBare hydra prints help. hydra -i opens an interactive menu that walks through the same commands with prompts. hydra help <command> or hydra <command> --help shows per-command usage.
Commands
init
hydra init [url] writes a profile to .hydra/config.json. The first profile becomes the default. Run with no arguments it opens an interactive form; when any positional or piped input is involved the URL is required.
-p, --profileprofile name (default:default)-n, --namebase name for runners (default:runner)-c, --runnersnumber of runners (default: 1)-l, --labelscomma-separated extra labels-f, --forceoverwrite an existing profile
create
hydra create [profile] [count] downloads the latest actions/runner release (once per version, shared across runners), then registers runners named <name>-1, <name>-2, … It tops up to the target count: if the profile already has enough runners recorded, it does nothing. count overrides the profile's numberOfMachines.
start / stop
hydra start [profile] [ids...] launches each runner's run.sh as a detached background process and records its pid. hydra stop [profile] [ids...] kills them. Omit the ids to target every runner in the profile; omit the profile to use the default. Runners do not survive a reboot — run hydra start again.
status
hydra status lists every profile's runners with their state (running with pid, registered, or unknown). State is determined locally from pid liveness and the runner's .runner file; no API calls.
logs
hydra logs [id] tails the newest job log (Worker_*.log) from the runner's _diag directory. If no job has run yet it falls back to the runner daemon log with a warning. The id can be omitted when there is exactly one runner.
-n, --lineslines to tail (default: 100)-r, --runnershow the runner daemon log (Runner_*.log) instead of the job log-l, --listlist available log files with timestamps and sizes-o, --openopen the log in$EDITOR(falls back toopenon macOS)
cleanup
hydra cleanup frees disk space. By default it prunes _diag log files older than 7 days (always keeping the newest runner and worker log per runner) and removes shared runner versions no runner's externals link points to (the newest installed version is always kept). _work holds job checkouts and caches, so it is never cleaned by default — pass -w explicitly. Runners that are currently running are skipped for _work cleanup.
-l, --logsprune old_diaglog files-w, --workdelete_workcontents of stopped runners-s, --sharedremove unused shared runner versions-d, --daysage threshold in days for log pruning (default: 7, orcleanup.olderThanDays)-n, --dry-runlist what would be deleted with sizes, delete nothing-y, --yesskip confirmation prompts
Passing any of -l/-w/-s cleans only those targets; with none, the targets come from the cleanup config section (default: logs and shared).
update
hydra update checks the latest actions/runner release, and if it differs from the installed version, swaps the binaries for every runner. Runners that were running are stopped, updated, and restarted.
remove
hydra remove [profile] [ids...] stops the runners, deregisters them from GitHub, and deletes their directories.
profile
hydra profile list— profiles with URL, OS, and created/running countshydra profile default <name>— set the default profilehydra profile remove <name>— remove a profile; if it has runners, stops and deregisters them first (after confirmation)
Configuration
.hydra/config.json, resolved relative to the working directory. Hydra writes it; the profiles section is safe to edit by hand:
{
"defaultProfile": "default",
"profiles": {
"default": {
"url": "https://github.com/owner/repo",
"name": "runner",
"numberOfMachines": 2,
"labels": "macOS,ARM64",
"directory": ".hydra/runners",
"os": "osx",
"provider": "github",
"overwrite": false,
"run": false
}
},
"runners": []
}os is one of osx | linux | windows (auto-detected by init). An optional runnerGroup string is passed through to config.sh --runnergroup; runner groups only apply to organization runners. The runners array is Hydra's record of what it created — leave it alone.
An optional cleanup section controls hydra cleanup and automatic cleanup:
"cleanup": { "auto": true, "intervalHours": 24, "olderThanDays": 7, "targets": ["logs", "shared"] }All fields are optional; the values above (with auto: false) are the defaults. With auto enabled, hydra start and hydra update run a cleanup afterwards whenever the last run is more than intervalHours ago. Automatic runs never prompt and only touch the configured targets — work only if you list it explicitly. Hydra records lastRun itself; leave it alone.
The url is either a repository URL (https://github.com/owner/repo) or an organization URL (https://github.com/org). Repository URLs mint tokens from the repository endpoint (requires repo admin); organization URLs use the organization endpoint (requires the admin:org scope).
How it works
Runner binaries are downloaded once per version into .hydra/shared/github/<version>. Each runner directory under .hydra/runners/<id> gets hardlinks for bin, a symlink for externals, and its own copies of the shell scripts, so ten runners cost roughly one copy of the runner distribution on disk. Start/stop is plain process management: a detached bash run.sh plus a pid file per runner.
License
Apache-2.0 — see LICENSE
