ushr

module
v0.2.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 27, 2026 License: Apache-2.0

README

ushr

Cross-org priority scheduler for self-hosted GitHub Actions runners. Architecture in DESIGN.md.

Status: v0.2.4, Apache-2.0. Multi-host, keyless: the agent holds your GitHub App key and the control plane never sees a credential.

Run it two ways. Self-host the controller alongside the agent (ushr setup) and nothing leaves your network. Or point the agent at the hosted control plane at ushr.io (ushr login) for cross-machine scheduling and a dashboard — the key still never leaves your box.

Components

Binary Role
ushr User-facing CLI. ushr login sets a host up end to end for the hosted plane; ushr setup --org NAME creates the GitHub App and records it in agent.yaml; ushr doctor checks host health; ushr init [dir] rewrites a repo's workflow runs-on targets to ushr labels.
ushr-controller Schedules queued jobs across agents over a long-poll HTTP API (keyless: agents report metadata, the controller holds no GitHub credentials)
ushr-agent Runs on the runner host. Holds the GitHub App keys, watches GitHub for queued jobs, mints JIT configs, and uses the configured Driver (Tart on macOS, docker/podman on Linux) to provision/destroy ephemeral runners

Quick start — one command per host

Install the binaries:

curl -fsSL https://get.ushr.io | sh
# or, from a checkout: ./deploy/install.sh

Then, on the runner host:

# Hosted plane (ushr.io): guided end-to-end setup —
# config, prereq installs (tart / podman, runner image), browser
# enrollment, GitHub App creation, service install + start.
ushr login

# Local/OSS single host, no account: GitHub App + local
# controller/agent services.
ushr setup --org YOUR_ORG

Both are interactive but zero-edit: prereqs are offered as guided installs (brew install tart, image pulls, podman), the GitHub App flow is two browser clicks, and the org block is written into ~/.config/ushr/agent.yaml for you. On Linux the per-repo docker build cache is on by default.

Check a host any time:

ushr doctor

Development

make build          # bin/ushr, bin/ushr-controller, bin/ushr-agent
make test           # go test ./...
make lint           # golangci-lint run

End-to-end Tart driver smoke (requires real Tart + an org with the App installed):

go run ./cmd/integration-test -trigger-repo=example-repo

Note: mints a real org-level runner registration in GitHub, dispatches a real workflow on -trigger-repo, and deletes both on success. Don't point at a production org for casual testing.

Roadmap

Shipped: Tart / Lume / Docker / SSH drivers, polling and scaleset sources, priority + aging, multi-host, two-phase keyless dispatch, per-agent enrollment, persistent dispatch ledger, ushr cost, one-command host setup, disk-pressure gating and reclaim.

Next: Kubernetes driver, Prometheus metrics, docs site.

Auth model

  • Controller ↔ Agent: per-agent enrollment tokens minted by ushr login, scoped to the orgs the agent may serve. Self-hosted single-host instead uses a shared bearer token, or no token at all when bound to loopback.
  • Agent ↔ GitHub: GitHub App per org via ghinstallation/v2. App ID + private key path in agent.yaml; installation ID auto-discovered. The control plane never sees a GitHub credential.
  • JIT runner registration: the agent mints a fresh JIT config per dispatch via Actions.GenerateOrgJITConfig. Runner is single-use and self-removes from GitHub when the job finishes.

License

Apache-2.0.

Directories

Path Synopsis
cmd
agent command
controller command
integration-test command
Command integration-test exercises the Tart driver end-to-end against a real paddo-runner-mac image.
Command integration-test exercises the Tart driver end-to-end against a real paddo-runner-mac image.
ushr command
Command ushr is the user-facing CLI.
Command ushr is the user-facing CLI.
internal
agent
Package agent runs the long-poll loop on the runner host.
Package agent runs the long-poll loop on the runner host.
api
Package api defines the control-plane<->agent HTTP protocol.
Package api defines the control-plane<->agent HTTP protocol.
disk
Package disk reports free space on a runner host's image store.
Package disk reports free space on a runner host's image store.
dispatch
Package dispatch is the controller's persistent record of in-flight dispatches.
Package dispatch is the controller's persistent record of in-flight dispatches.
dispatch/pg
Package pg is a Postgres-backed dispatch.Store for the hosted control plane.
Package pg is a Postgres-backed dispatch.Store for the hosted control plane.
domain
Package domain holds neutral types shared across components.
Package domain holds neutral types shared across components.
driver/docker
Package docker implements the Driver interface by running each ephemeral runner as a container via the Docker or Podman CLI (autodetected, or pinned via Options.Runtime — the two are drop-in for the subcommands used here).
Package docker implements the Driver interface by running each ephemeral runner as a container via the Docker or Podman CLI (autodetected, or pinned via Options.Runtime — the two are drop-in for the subcommands used here).
driver/factory
Package factory builds a Driver from agent config.
Package factory builds a Driver from agent config.
driver/lume
Package lume binds the lume CLI (MIT, Apple Virtualization.framework) to the generic VM driver in internal/driver/vmdriver.
Package lume binds the lume CLI (MIT, Apple Virtualization.framework) to the generic VM driver in internal/driver/vmdriver.
driver/sshrunner
Package sshrunner holds the SSH-based runner bootstrap shared by the macOS drivers (tart, lume).
Package sshrunner holds the SSH-based runner bootstrap shared by the macOS drivers (tart, lume).
driver/tart
Package tart binds the tart CLI (Apple Virtualization.framework) to the generic VM driver in internal/driver/vmdriver.
Package tart binds the tart CLI (Apple Virtualization.framework) to the generic VM driver in internal/driver/vmdriver.
driver/vmdriver
Package vmdriver provides a generic ephemeral-VM Driver shared by the macOS drivers (tart, lume).
Package vmdriver provides a generic ephemeral-VM Driver shared by the macOS drivers (tart, lume).
enroll
Package enroll handles agent authentication for the hosted control plane: per-agent enrollment tokens (validated against Neon) and the browser-session + PKCE handshake behind `ushr login`.
Package enroll handles agent authentication for the hosted control plane: per-agent enrollment tokens (validated against Neon) and the browser-session + PKCE handshake behind `ushr login`.
jit
Package jit mints GitHub Actions runner JIT configs per org installation.
Package jit mints GitHub Actions runner JIT configs per org installation.
ledger
Package ledger is an append-only store of completed ushr jobs.
Package ledger is an append-only store of completed ushr jobs.
source/github
Package github implements a polling Source backed by the GitHub Actions API.
Package github implements a polling Source backed by the GitHub Actions API.
source/scaleset
Package scaleset implements a Source backed by GitHub's Runner Scale Set API (the mechanism behind actions-runner-controller, via the standalone actions/scaleset client).
Package scaleset implements a Source backed by GitHub's Runner Scale Set API (the mechanism behind actions-runner-controller, via the standalone actions/scaleset client).
svc
Package svc installs and controls the ushr launchd/systemd user services, so the CLI can take a host from enrolled to running without a repo checkout or hand-run launchctl/systemctl incantations.
Package svc installs and controls the ushr launchd/systemd user services, so the CLI can take a host from enrolled to running without a repo checkout or hand-run launchctl/systemctl incantations.
telemetry
Package telemetry persists the dispatch story the control plane otherwise drops: finished jobs (job_runs), agent liveness (agent_status), and a live transition feed (dispatch_events).
Package telemetry persists the dispatch story the control plane otherwise drops: finished jobs (job_runs), agent liveness (agent_status), and a live transition feed (dispatch_events).
webhook
Package webhook receives GitHub workflow_job events and feeds completed jobs run on ushr runners into the ledger.
Package webhook receives GitHub workflow_job events and feeds completed jobs run on ushr runners into the ledger.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL