1.4.0 (2026-09-26)
- cluster: pin the Docker context the role drives per host (63bb283)
1.3.1 (2026-09-26)
- cluster: refuse Docker Compose 2.37.1 to 2.38.x (b99ae54)
1.3.0 (2026-09-26)
1.2.2 (2026-09-26)
- arc: read the App's id from an existing App Secret (e0854d2)
1.2.1 (2026-09-26)
- arc: count this host's orgs however they were supplied (c731751)
1.2.0 (2026-09-26)
- arc: keep each org's resolved installation id to that org (6c1b65a)
- arc: let the App setup write the App Secret and remove the key (7f64f21)
- arc: measure the runner ceiling from each node's free capacity (a9a498b)
- arc: mint the image pull secret from the runners' GitHub App (6d1c8a3)
1.1.0 (2026-09-25)
- arc: describe the role's variables in an argument spec (e565cdb)
- arc: let orgs and scale-set profiles override their names and labels (5d2a9b6)
- arc: make the controller's release name and namespace configurable (619ac9e)
- arc: use an existing image pull Secret without managing it (4d2efe6)
1.0.3 (2026-09-25)
- cluster: never delete a server's Node object when clearing a stale registration (826b66e)
1.0.2 (2026-09-25)
- cluster: clear only the registrations of nodes that have not rejoined (e789205)
1.0.1 (2026-09-25)
- release: attach the collection tarball to the GitHub release (32cafd5)
- feat!: make 1Password an optional secrets adapter (f249f55)
- feat(arc)!: read each org's App key from its private_key (ac1b879)
- feat(cluster)!: keep new join keys without calling the secrets role (3befb78)
- refactor!: move ExaDev's fleet inventory and Helm values to github-runner-fleet (e08b3af)
- refactor!: render ARC values on the control node and validate before the cluster role (28d8144)
- refactor(cluster)!: ship the node runtime in the collection and run it from github_runner_cluster_dir (a30fc6c)
- advertise each host's real IP as its k3s node identity (a2514a1)
- advertise etcd peer traffic on each server's real Tailscale IP (ff99e1c)
- bootstrap the heartbeat gist only when no host in the fleet has one (b8d9024)
- build the runner image on the fleet's own builder profile (deb3480)
- cluster: let the Headscale standby tasks honour DOCKER_HOST (ddcbf3e)
- create the autoscaler-status ConfigMap only when it is absent (a5122d5)
- declare exadev-runners as a known self-hosted label for actionlint (3ebb190)
- delete stale kubeconfig on k3s start; rename .env.arc to .env (c85a6cb)
- derive the play's PATH without depending on ungathered facts (8b05856)
- detect hadolint's architecture and drop the sudo dependency (446ea2a)
- drop the global etcd-arg listen-peer-urls override (e8a6f52)
- escape the TLS SAN loop variable and soft-default cross-profile-only env vars (fc0e325)
- export variables from .env.arc so child processes see them (8c2b7a7)
- fail fast on a missing repo root, provision a venv, detect the real Docker context, and read every secret in one shell call (f17973d)
- fetch the tailnet ACL even in check mode (3a9d69c)
- give the heartbeat launchd job a PATH that includes Homebrew (dc4d1dc)
- grant autoscaler core nodes read alongside nodes.metrics.k8s.io (c672a14)
- grant autoscaler core pods read alongside pods.metrics.k8s.io (a54506e)
- heartbeat via host networking; stable k3s node name (8668334)
- keep mesh-addressed traffic from leaving a node that is off the mesh (f3d0388), closes #44
- keep the Headscale image local for in-cluster mesh recovery (a275ebf)
- keep the Headscale standby's follower out of promotion (e520ebf)
- keep the temporary Headscale server until recovery has checked it (d384e5a)
- key node names and node-password cleanup on the effective node name (8b10e8e)
- let the cluster role's Compose tasks honour DOCKER_HOST (e7b6eee)
- match --disable=traefik --disable-network-policy on joining servers (60e95d0)
- name the cluster role in the generated k3s .env header (4e5f8f7), closes #32
- only install Homebrew prerequisites on macOS hosts (ed29ad2)
- prefer prebuilt wheels when installing Ansible and the kubernetes client (6a714dc)
- read each org's private key once, from the combined secrets read (42e17b3)
- remove duplicate homebrew task, guard the node-registration poll (d36f4a7)
- report why an in-cluster mesh recovery did not bring the bootstrap server back (c1d3ade)
- require an explicit per-host repo root instead of the control node's (f4050d7)
- route required-checks through the same runner fallback (fe3634c)
- run bootstrap.sh's local play under its own venv's Python (9b58a81)
- run the role's read-only lookups under --check (6ed77c8)
- scope the autoscaler compose service to the primary profile (5fed3b4)
- set --node-ip explicitly so config.PrivateIP picks up etcd's real peer address (019b0e5)
- skip tailscale up when already authenticated, wait for real DNS before joining (026b4a1)
- source .env.arc before docker compose up, not after (eb09869)
- stop kubelet merging Tailscale's DNS search domains into pod resolv.conf (43db6ef)
- tell flannel to use the node's external IP too (f40dbaf)
- template .env from the combined secrets read, not per-field registers (f163427)
- use --node-external-ip, not --node-ip, for cross-node identity (e291eec)
- use an explicit if-block for the meminfo-read guard in autoscaler.sh (26b0afe)
- wait for a node to actually exist, not just API reachability (1e1bdc9)
- wait for the bootstrap server to be a mesh peer before joining (9c832fd)
- word the generated .env header for both deployment paths (b13ee04)
- wrap the bun install pipe in bash -c for pipefail (094ad1f)
- accept secrets supplied directly as an alternative to 1Password (8ae7572)
- add a hosted-Headscale mesh provider (ee82844)
- add a manual workflow to generate load for the autoscaler (c490889)
- add a playbook that promotes the Headscale warm standby (15f8878)
- add an ARC-only playbook for an existing cluster (5c74e03)
- add an existing-Headscale mesh provider (444099c)
- add an in-cluster Headscale mesh provider (2eeaed0)
- add ARC metrics and listener readiness and liveness probes (695e5f1)
- add CI with a Required Checks junction job (41db343), closes ExaDev/github-runner#2
- add Docker CLI and buildx plugin to the runner image (0ebce9e)
- add filters that expand ARC org profiles, derive a runner ceiling and split image references (d2bd850)
- add heartbeat health check for runner-fallback-action (d7d1091)
- add k3s agent service and TLS SAN flag to compose (1280a62)
- add self-contained Ansible inventory and playbook (d8953db)
- add the autoscaler container image and poll loop (ecfac73)
- add the usage-driven maxRunners autoscaler script (8eb8fd8)
- allow a single-server cluster on SQLite (88307c9)
- ansible: add primary/agent node role split to github_runner_arc (934b9d5)
- ansible: cache the 1Password secrets read on the control node (c517d9f)
- ansible: give each node its own node-affinitized scale-set profile (9ea16d0)
- ansible: install helm and kubectl via homebrew on primary hosts (986fedf)
- ansible: let a scale-set profile opt out of its org's shared label (b9dcb0f)
- ansible: provision the Tailscale ACL/join key and self-heal two stale-state failure modes (057ebb1)
- ansible: self-heal a scale-set listener left pointing at a deleted EphemeralRunnerSet (48275e1)
- ansible: thread K3S_NODE_IP through to every host (9ad5241)
- ansible: thread the Tailscale join key through instead of node IPs (54b035f)
- build and push all three images from the release workflow (de104de), closes #10
- check ARC secrets exist before changing anything, and support pre-created ones (63d42e7)
- ci: add commitlint, ansible-lint, and a collection build check (dda2978)
- cluster: back up Headscale with Litestream and keep a warm standby (e538f98)
- configure semantic-release for the collection version (d190ed6)
- create the runners' GitHub App through the manifest flow (9b8412f)
- define github_runner_arc role defaults (3736baf)
- generalize the primary role into server/agent plus a fleet-health installer (7aec978)
- genuine 3-node k3s embedded-etcd HA control plane (72e4b76)
- heartbeat as a docker-compose service refreshing a secret gist (9f78ea7)
- initial ExaDev self-hosted runner setup (8665b12)
- install one org's namespace, secrets, and runner scale set (42fdcf8)
- let nodes register with a control server other than Tailscale's (140163a)
- merge the k3s and k3s-server compose services into one (f13657a)
- orchestrate the github_runner_arc role's bootstrap sequence (1992d42)
- prove the image pull credential can read each image before writing it (8ee3b79)
- rebuild on Kubernetes (ARC) instead of Docker Compose fleet (ab10c64)
- republish the autoscaler status in the heartbeat gist (50feb75)
- resolve a GitHub App installation ID via a signed JWT (1244c29)
- restrict ARC pods to labelled nodes (8289cdc)
- run autoscaler as an in-cluster Deployment, read pressure cluster-wide (fac57e9)
- run heartbeat as an in-cluster Kubernetes Deployment (76e82dd)
- run more than one ARC controller replica, spread across nodes (c042bfa)
- run Tailscale inside k3s itself via k3s's native --vpn-auth (3e63834)
- run the autoscaler as a docker-compose service (3708d9a)
- template docker-compose's .env from role vars (bf29037)
- trigger an immediate autoscaler reconcile after installing an org (3728259)
- trigger an immediate autoscaler reconcile after installing an org (e53b764), closes ExaDev/github-runner#3
- unpin ordinary CI runner pods from a specific machine, replacing nodeSelector with Guaranteed QoS (8d0dd71)
- is major, feat is minor, every other conventional type (fix, perf, refactor, docs, and so on) is patch, matching commitlint.config.js's own accepted types one for one.
Its exec step runs scripts/release/stamp_version.py, which writes the new version into galaxy.yml's version field and into the arc role's two published-image tag defaults (github_runner_arc_heartbeat_image, github_runner_arc_autoscaler_image), matched by variable name rather than line number so it stays correct against concurrent edits to that file, then builds the collection tarball. The git step commits the changelog and both stamped files back to main with a skip-ci release commit; the github step attaches the tarball to the GitHub Release; the exec publish step pushes to Ansible Galaxy only when a GALAXY_API_KEY is actually configured.
- .env.bootstrap's EXADEV_APP_ID, EXADEV_APP_INSTALLATION_ID and EXADEV_APP_PRIVATE_KEY_PATH are now RUNNER_APP_ID, RUNNER_APP_INSTALLATION_ID and RUNNER_APP_PRIVATE_KEY_PATH, alongside the new RUNNER_ORG, RUNNER_IMAGE and RUNNER_VALUES_FILE or RUNNER_MAX_RUNNERS, and the autoscaler's budget, ceiling and floor no longer default to ExaDev's pool.
- github_runner_cluster_repo_root is replaced by github_runner_cluster_dir, with no alias. A host that ran Compose in a checkout keeps its cluster by setting github_runner_cluster_dir to that checkout, and, if the checkout's directory is not called github-runner, github_runner_cluster_compose_project to that directory's name.
- the github_runner_secrets role is renamed to github_runner_secrets_onepassword and runs only with github_runner_secrets_source: onepassword. Its variables are renamed (github_runner_secrets_vault, _item and _cache_path become github_runner_secrets_onepassword_vault, _item and _cache_path), and github_runner_secrets_provided is gone: set the cluster and ARC roles' variables directly.
- github_runner_cluster_create_tailscale_join_key and github_runner_cluster_create_headscale_join_key are replaced by github_runner_cluster_join_key_path and github_runner_cluster_join_key_listener.
- github_runner_arc_org_private_keys is gone. Put each org's PEM key in its private_key field instead, and drop org_private_keys from github_runner_secrets_provided.
- github_runner_arc_values_dir is a control-node path with no default; the autoscaler is installed only for a profile that sets autoscale: true; github_runner_arc_autoscaler_usable_budget_gi, _max_ceiling and _floor have no defaults; and the autoscaler image needs AUTOSCALER_NAMESPACE, AUTOSCALER_RELEASE_NAME and the pool figures set.
Release entries are generated automatically at release time and prepended above this line.