2.8.0 (2026-10-22)
- arc: copy capability payloads once per node into a capability store (d35960c)
- arc: prune capability store entries no scale set or pod uses (8da1713)
- arc: check the capability store's settings in validation as well as at render (543e66a)
- arc: choose the capability store settings inside each filter call (09ecadd)
- arc: copy a tool or version directory that is a link as the link in the pod's tool cache (1bb2b62)
- arc: copy an aliased tool-cache arch directory as the link instead of linking to the store's (2975f73)
- arc: copy an image shared by two capabilities once into the store (8b9c129)
- arc: flush capability store entries before publishing and rebuild a pod's partial copy on rerun (5872044)
- arc: keep a pod's cached tool trees writable when the capability store is on (ba28499)
- arc: keep capability store entries a departed profile's pods still use (6d523ee)
- arc: keep the pruner's capability store grants to the namespaces it reads (7445765)
- arc: make a pod's linked tool trees owner-writable whatever mode the store's directories have (523cf4c)
- arc: merge a system-library entry once when two capabilities share its image (5da86af)
- arc: mount only the store entries a pod uses on its runner container (345c629)
- arc: mount the store's externals entry in a dind native sidecar as well as a dind container (d7ec22f)
- arc: name capability store entries for their payload kind as well as the image digest (a048e89)
- arc: prepare the capability store before the dind externals copy (ff82dbd)
- arc: publish a payload whose root is read-only and say why a rename failed (63bb70e)
- arc: refuse a capability whose init container would take a store init container's name (b4c6a29)
- arc: refuse a node cache and capability store that share or contain a directory (fe8ba4e)
- arc: refuse to start the node cache pruner with a store root and no store namespaces (9630e65)
- arc: remove a pod's capability store copy even when it holds read-only directories (093428a)
- arc: replace a read-only completeness marker when the tool cache is linked again (99742c4)
- arc: validate the node label key when a node cache or the store needs the pruner (44ac928)
- arc: stop registering the capability store key function as a filter no task uses (55453d4)
- arc: declare the capability store's profile key and settings in the argument specification (ef229ca)
- arc: describe the kind test in its own section and its store case in the store section (709c1df)
- arc: limit the store's dind externals copy to values that write the sidecar out (fe8420f)
- arc: list exactly the applets the capability store image's scripts use (126ec04)
- arc: name the init containers that write to the store and the one that only reads it (af05fa7)
- arc: state chmod in the capability image and store image contracts (60bb6d3)
- arc: state that a store switched off fleet-wide keeps its entries for the operator to delete (eccceb6)
- arc: state that the store's flush before publishing is host-wide and why that is accepted (03e3997)
- arc: state the capability store's copy cost on a cold node and its disk footprint exactly (d6fce81)
- arc: state the store's copy container, first-wave copying and burst nodes as the code has them (bd1746d)
- arc: state the store's pruner, grants and dind limit as the code has them (32a0341)
- tool-images: list chmod among the applets the init containers run from busybox (e610f49)
- arc: build the pruner image from the repository root (0dcb312)
- arc: count lines in the capabilities test without relying on wc's padding (ce282d0)
- arc: cover a tool alias that sorts before its target in the tool-cache link script (824bc07)
- arc: fail the log wait only when the pod has ended (1482d67)
- arc: name the pruner test's store entries as the role does (032fab6)
- arc: run two capability store pods and the pruner against real mounts in kind (53e3072)
2.7.10 (2026-10-22)
- mesh: wait for what a step needs before the regrade scenario takes it (e052424)
2.7.9 (2026-10-21)
- mesh: check a server stepped down to etcd-only gives the Lease back (d976df7)
2.7.8 (2026-10-21)
- arc: check orgs per cluster and refuse a scale set registered from two clusters (26230fe), closes #130
- arc: name every scale set after its release whatever a values file says (73cde13)
2.7.7 (2026-10-21)
- cluster: write the kubeconfig with a permission mode, not the API port (f841b5d)
2.7.6 (2026-10-21)
- cluster: stop two recreate tests assuming which server takes the first turn (fe5065d)
2.7.5 (2026-10-20)
- autoscaler: count a runner pod with no metrics yet at its limit, keep a slot per set (01d41fd), closes #134
2.7.4 (2026-10-20)
- cluster: leave a level someone else changed for the cooldown (8f9257e)
- mesh: count only a known reduced level as a server having stepped (9c3d075)
- mesh: print what regrading recorded for each node when a scenario fails (458a474)
- mesh: wait for a level to read instead of asserting one read (6bef0c6)
2.7.3 (2026-10-20)
- release: list every conventional commit type in the release notes (99e6a6d)
- changelog: backfill the commits earlier notes left out (69b855d)
2.7.2 (2026-10-20)
- autoscaler: say why a runner pod's CPU request was not halved (c0475c7)
2.7.1 (2026-10-20)
- mesh: read a joining server's whole log for the wait's line (105eb45)
2.7.0 (2026-10-20)
- arc: grant the autoscaler its ceiling read and make the ceiling a bound (11e99e4), closes #120
- autoscaler: work the ceiling out from the nodes every poll (5eaff58), closes #120
2.6.1 (2026-10-20)
- mesh: keep a stepped-down server at its level through a restart and a recreate (a5b53d5)
2.6.0 (2026-10-20)
- cluster: apply regrade levels to a Docker node (8284a4d)
- cluster: let the cluster role run the regrade service (ce4ff38)
- cluster: let the regrade core step a server back up by itself (a45e7fb)
- cluster: ship the platform-neutral regrade core and its tests (7db7948)
- cluster: stop the regrade service on a kernel without memory pressure (acf2c7c)
- heartbeat: publish a stepped-down server's level and spare it from the alert (d69f7c7)
- cluster: name the Compose profile in the regrade service's commands (bc34378)
- cluster: check the version arguments only of services built from the k3s context (058480d)
- cluster: give the instance entrypoint harness the regrade flags (6b6c2fd)
- cluster: give the regrade entrypoint harness the API port flag (7f25f47)
- cluster: order the regrade service after the serialised server start (41d4940)
- mesh: step a server down and back up through the regrade service (80b65bf)
- mesh: stop the watcher by pid and judge a stepped-down rerun by the recap (09b80a9)
- mesh: wait for the refusal that names the stepped-down server (0454e95)
- regrade: allow the indirectly called functions older shellcheck reports as unreachable (44d3711)
2.5.0 (2026-10-20)
- cluster: describe a new Tailscale join key in characters the API accepts (a6d2bee), closes #118
- cluster: wait for the join host after k3s's own tailscale up (6fae111), closes #116
- cluster: give the etcd timing tests' entrypoint harness the API port flag (7e6c245)
- mesh: name each test node's container through the role's variable (272cc6c)
2.4.0 (2026-10-20)
- arc: delete no node unless three Ready etcd members would remain (bcfe065)
- arc: let the node recovery watcher delete a labelled node that stayed Unknown (80fa540)
- arc: confine the node-deleting watcher pod to control-plane nodes (3d57b9e)
- arc: default the prune label to the fleet's node label domain (f15e146)
- arc: keep the removable worker second so kind names it as the test expects (282c05d)
- arc: prune a stopped, labelled worker in the node recovery kind test (17d70dd)
- arc: read each watcher pod's log on its own (3de565d)
- arc: read the prune log from every watcher pod after the rollout (364dfef)
- arc: wait for the prune threshold before expecting the voters refusal (5463601)
2.3.0 (2026-10-20)
- cluster: keep a node's password in a volume across container recreation (e64284e)
- cluster: recreate servers one at a time and only while the others are Ready (c2f356d)
- cluster: wait for the recreated server heartbeat and relax the check before anything joined (46cf254)
- cluster: describe the heartbeat wait and the bring-up exception (d1d7fbe)
- cluster: document the node password volume and the servers' turns (1c5a445)
- cluster: count a server's turn as its Compose start in the end-check order (e43c851)
- mesh: recreate a joined server and check it keeps its node password (c1e169d)
- mesh: recreate the joined server after the scenario's other steps (23e3ed9)
- mesh: reuse the restart test's echo pod helper (684b763)
- mesh: wait for the recreated node's echo pod before checking the mesh (a060aa7)
- run the unit tests in shards of their own job (95d6657)
2.2.0 (2026-10-20)
- cluster: make etcd's heartbeat and election timeouts configurable (0811f20)
- cluster: document the etcd timing settings (2c05e63)
- mesh: restart an initialised etcd datastore with the timing set (0b37335)
- mesh: wait for the restarted server's pod to restart before probing (3e0221e)
2.1.0 (2026-10-20)
- cluster: derive the container runtime from the Docker context (a6b4bf8)
- cluster: start Colima at login on macOS hosts and check the runtime (a9dd023)
- examples: add a scheduled workflow that runs fleet-alert.sh off the fleet (5a28c7f)
- heartbeat: add fleet-alert.sh to announce a fleet that has been down (9324f94)
- heartbeat: publish not-Ready nodes and when each problem began (36eae9b)
- cluster: read the host's operating system instead of assuming gathered facts (e7a3d83)
- heartbeat: judge a node Ready by its Ready condition (276bee6)
- heartbeat: document the fleet-down notification and where it must run (bb35601)
2.0.1 (2026-10-19)
- arc: render helm diff through an upgrade dry run in the role's helm tasks (2c7cc5e)
2.0.0 (2026-10-18)
- cluster: a github_runner_cluster_dir or github_runner_cluster_compose_files path with a colon in it is refused, since COMPOSE_FILE separates paths with colons. Move the file or directory to a path without one.
- cluster: a cluster that runs a newer k3s than the version the role is given, such as one built from latest before the pins, is refused until github_runner_cluster_k3s_version names the tag it runs. A deliberate downgrade, a cluster being replaced or one that cannot be read needs -e github_runner_cluster_allow_k3s_version_jump=true for that run.
- cluster: latest is no longer accepted for github_runner_cluster_k3s_version or K3S_VERSION in .env.bootstrap. Set the rancher/k3s tag the cluster runs (k3s --version in a node's container, with + written as -), once for the whole group, or leave it unset for the default; set github_runner_cluster_tailscale_version if the nodes run another Tailscale. The next run rewrites each node's .env and recreates nothing.
- cluster: name the node's Compose files and project in its .env (88f7e9c)
- cluster: pin the k3s and tailscale images every node is built from (1a37eac)
- cluster: refuse a k3s version outside the upgrade path from what runs (cc7255c)
- cluster: document the version pins, their checks and an upgrade (d70a5ad)
- bootstrap: check bootstrap.sh leaves unset image versions to the role (04350ce)
- renewal: suspend the renewer's CronJob while the test runs its Jobs (adca1e1)
- run the unit tests' playbooks with the ansible-core their filters import (381db70)
1.31.4 (2026-10-18)
- github-runner-arc: name the pnpm store with a variable pnpm does not read (96afd9c)
- github-runner-arc: read the pnpm store variable in the install step's shell (74970f4)
1.31.3 (2026-10-15)
- github-runner-arc: drop a private repository reference from the burst-node note (c2f4400)
1.31.2 (2026-10-15)
- arc: drop FOWNER from the node-cache init container and document its capabilities (e641d8f)
- arc: keep DAC_OVERRIDE and FOWNER on the node-cache init container (320c3e5)
- arc: fail the node-cache step on any assertion and explain the single init container (7f718fd)
- arc: print the seeded pod's end marker from the step (1778f86)
- arc: run a node-cache capability's init container in kind under a non-root pod context (b8c69ce)
- arc: show every container's log when the capabilities test pod fails before its step (7db8a42)
- arc: start a node-cache pod on a directory the runner user already owns (07f7ad6)
1.31.1 (2026-10-15)
- arc: bound the pruner's numeric settings so its arithmetic cannot wrap, in the role too (e7d4e1f)
- arc: build node cache paths from one canonical root and report what the pruner could not do (d44aba0)
- arc: empty a node cache atomically, drain a node past its hard limit, and narrow the pruner (886b4b4)
- arc: keep a departed profile's pod access while the pruner runs, and match only the role's own (7439708)
- arc: refuse a pruner start with an invalid limit, and name the cause when a final list fails (8d53e99)
- arc: remove only the cluster role 1.31.0 made, report why rmdir failed, and guard empty arrays (ad1edc3)
- arc: report a busy node cache over its hard limit instead of cordoning, and gate each rename (0c4e3fc)
- arc: tell a refused pod list from a failed one, and build images from the release tag (6ad1ea4)
- arc: treat the 1.31.0 cluster role and binding together, and say what the cleanup needs (949ebb2)
- arc: reword the 1.31.0 cleanup note, and tidy the new tests' style findings (394d74b)
- arc: say that burst nodes are not pruned, and drop a duplicate comment (814f9a5)
1.31.0 (2026-10-14)
- arc: add a node-cache capability that shares a node directory between a profile's pods (39c55dc)
1.30.1 (2026-10-14)
- arc: leave the runners a pod capacity bounds out of the safety margin (ce759b1)
1.30.0 (2026-10-14)
- arc: bound each node's measured runners by its pod capacity (ccf41b4)
1.29.0 (2026-10-14)
1.28.0 (2026-10-14)
- arc: run the controller and listeners under the platform priority class when asked (c90738f), closes #84
1.27.0 (2026-10-14)
- arc: let a profile name tolerations, and count the nodes they let its pods use (1bacb38)
1.26.4 (2026-10-13)
- arc: force field conflicts when Helm 4 upgrades the controller and scale sets (1aaa0f8)
- arc: pass neither server-side option to the helm module on Helm 3 (6ebef08)
- ci: install the lowest kubernetes.core even when it is also the newest (3a424fc)
- arc: say which server-side option the helm module refuses on Helm 3 (ea6b69a)
- arc: read the kubernetes.core floor in one place and report a wrong one once (fb95bf8)
- arc: run the Helm apply phases with the lowest accepted kubernetes.core too (fabca3d)
- arc: run the role's scale-set helm task with Helm 3 and Helm 4 in kind (3f1058b)
- pin the Helm archive digests the Helm apply workflow checks (a1ac5a1)
1.26.3 (2026-10-13)
- autoscaler: keep kubectl's error when reading node metrics fails (96b0fb6)
- autoscaler: read memory pressure only from the nodes runner pods may use (583aa42)
- autoscaler: describe when kubectl reports the metrics API as unavailable (afb6813)
- autoscaler: name each error kubectl top nodes can fail with (da2901a)
- autoscaler: fail safe when a node inside the selector reports no metrics (145320d)
1.26.2 (2026-10-09)
- arc: stop the registry cache install loop resolving the container resources setting (eb1c865), closes #71
1.26.1 (2026-10-08)
- arc: keep the sysroot's pkg-config files visible after actions/setup-python (779c361)
1.26.0 (2026-10-08)
- arc: add a runner reaper pass for runners that outlive their job (f66a9c5)
- arc: install an optional runner reaper CronJob in each runner namespace (a60458f)
- arc: set activeDeadlineSeconds on runner pods when configured (7964cbd)
- arc: share the App installation token minting between jobs (58e29be)
- arc: word a refused token mint for any permission (77cecc7)
- arc: document the runner reaper, its bound, permission and safety (2578475)
- arc: check the reaper reads only the assigned runners' runs by run id (c9d7f3b)
- arc: show the runner reaper deleting stuck runners in kind (8b37eab)
1.25.0 (2026-10-08)
- arc: add an optional pull-through registry cache for dind runners (223786b)
- arc: let the registry cache answer referrers lookups (3d1dc84)
- arc: document the registry cache, its pull paths and its security (670dd87)
- arc: make the registry cache test independent of the host's Docker (62c3cfc)
- arc: prove pulls go through the registry cache and fail open in kind (0bb0dcf)
- capabilities: ignore Helm 4's pull notice when reading the rendered chart (159ae13)
- run the registry cache integration test on pull requests (7553f15)
1.24.0 (2026-10-08)
- tool-images: add a build runner image with a C toolchain (6df87bf)
- tool-images: add GLPK and MariaDB Connector/C system-library images (3d9e6b6)
1.23.0 (2026-10-08)
- arc: run public images without a pull Secret (f5fe08f)
1.22.1 (2026-10-08)
- arc: pin the capability example to the published tool images (d00c919)
- drop the note that no release has run yet (8245c61)
1.22.0 (2026-10-07)
- cluster: register a node with taints set per host (85171e6)
1.21.0 (2026-10-07)
- install a standalone Python on hosts that have none (fb1b5d0)
1.20.0 (2026-10-07)
- autoscaler: move a slot to a saturated pooled profile when the pool is at its ceiling (0e75801)
- autoscaler: count runners from ephemeral runners and patch the state ConfigMap from a file (0da00e9)
1.19.0 (2026-10-07)
- arc: add system-library capabilities (fab2a78)
- tool-images: add reference system-library payload images (4b2b973)
- describe system-library capabilities and the payload contract (7111ffa)
- capabilities: carry a system-library capability through kind (d0ae25a)
- capabilities: prove each system-library payload works relocated (5abdb4e)
- add a workflow that publishes the reference tool images (e190279)
- publish-tool-images: check the pinned version with an if rather than && and || (05d233a)
1.18.0 (2026-10-07)
- arc: add capabilities to scale-set profiles (e0e6ce9), closes #55
- tool-images: add reference tool-cache capability images (f33107f), closes #55
1.17.2 (2026-10-07)
- document the br_netfilter requirement after a Colima VM restart (09471b0)
1.17.1 (2026-10-04)
- release: commit the cluster role's stamped version with the release (1f335cd)
1.17.0 (2026-10-04)
- cluster: let a host without API access skip the node version stamp (5d3829b)
- publish each scope's deployed collection version in fleet-health.json (485ea54)
- arc: restore the collection version and deployed-state defaults the release stamps (beeba32)
- name the deployed-state ConfigMap in the heartbeat's RBAC summary (7427102)
1.16.0 (2026-10-04)
- heartbeat: show how broad and how long the measured peaks are (a9d8076)
1.15.0 (2026-10-03)
- heartbeat: publish the distribution of measured job peak memory (9434c80)
1.14.0 (2026-10-03)
- arc: let runner pods create events so jobs can record their peak memory (8fcfe9d)
- autoscaler: collect the peaks the runners measured (b72bf02)
- runner: record each job's peak memory from a job-completed hook (850bbd8)
1.13.0 (2026-10-03)
- autoscaler: record each job's observed peak memory (77ac920)
1.12.0 (2026-10-03)
- arc: refuse a controller version change while runners are running (eeb7259)
1.11.1 (2026-10-03)
- arc: record how to upgrade ARC on a live fleet (ca76881)
1.11.0 (2026-10-03)
- arc: apply the controller chart's CRDs before installing or upgrading it (78ae73c)
- arc: keep helm's warnings out of the manifests sent to the API server (3d9bdd7)
- arc: name the controller service account when rendering the scale-set chart (4f768c5)
1.10.4 (2026-10-03)
- autoscaler: lower a pooled total that is above the ceiling (473e733)
1.10.3 (2026-10-03)
- image: install python3-venv so actions that build a virtualenv can run (4cb7352)
1.10.2 (2026-10-03)
- autoscaler: read an absent currentRunners as zero running runners (6149ed2)
1.10.1 (2026-10-03)
- heartbeat: stop vouching for the fleet when a scale set or its listener is missing (6bbe74f)
- heartbeat: assert what each tick writes to the gist (64dda97)
1.10.0 (2026-10-03)
- cluster: prune stale build cache and dangling images on every host (e683de7)
- cluster: leave the docker-prune container unnamed so projects on one daemon do not collide (1a7133e)
1.9.0 (2026-10-03)
- heartbeat: publish why the fleet is unhealthy and which nodes are under pressure (56cb613)
- platform: run the platform pods above runner pods with a local-storage request (d6d4a69)
- platform: render the priority class as a template the node recovery test also applies (bcbdab7)
- platform: cover the autoscaler and heartbeat decisions against a scripted kubectl (f697649)
1.8.1 (2026-10-03)
- hooks: run commitlint on every commit message locally (1682bab)
1.8.0 (2026-10-03)
- heartbeat: stop vouching for the fleet while runner pods cannot be scheduled (f875714)
- autoscaler: read every target before failing safe, lower on unschedulable runner pods (9c3a824)
1.7.0 (2026-09-30)
- arc: let a profile run on burst nodes only (44de91b)
1.6.0 (2026-09-30)
- arc: let a sized profile's runner pods overflow onto burst nodes (94a0b2b)
1.5.2 (2026-09-28)
- register gcc-11/g++-11 as the generic gcc/g++/cc/c++ alternatives (ebfd896)
1.5.1 (2026-09-28)
- install make in the runner image for native addon builds (e53aad6)
1.5.0 (2026-09-28)
- arc: pool multiple autoscaled profiles into one shared budget (82eddac)
-
arc: drop unnecessary
$/$ {} on arithmetic array subscripts (78be6df)
1.4.0 (2026-09-26)
- cluster: pin the Docker context the role drives per host (63bb283)
- cluster: prove a pinned Docker context wins over the current one (794a6a6)
- cluster: return the playbook status from the mesh harness run_role (eab77e0)
1.3.1 (2026-09-26)
- cluster: refuse Docker Compose 2.37.1 to 2.38.x (b99ae54)
- mesh: cover both sides of the faulty Compose range (224dfac)
1.3.0 (2026-09-26)
- arc: prove node recovery by stopping a worker in a kind cluster (6476a2f)
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: 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)
- arc: keep each org's resolved installation id to that org (6c1b65a)
- arc: run the pull secret renewal CronJob in a kind cluster (45807a9)
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)
- 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.
- cluster: 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.
- cluster: 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.
- arc: 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.
- choose k3s servers and agents from the inventory
- split cluster, ARC, secrets and k8s client roles
- move roles and playbook to an Ansible collection layout
- 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)
- arc: read each org's App key from its private_key (ac1b879)
- 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)
- choose k3s servers and agents from the inventory (e2386c2)
- ci: add commitlint, ansible-lint, and a collection build check (dda2978)
- cluster: back up Headscale with Litestream and keep a warm standby (e538f98)
- cluster: keep new join keys without calling the secrets role (3befb78)
- 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)
- make 1Password an optional secrets adapter (f249f55)
- 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)
- 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)
- cluster: ship the node runtime in the collection and run it from github_runner_cluster_dir (a30fc6c)
- move ExaDev's fleet inventory and Helm values to github-runner-fleet (e08b3af)
- move roles and playbook to an Ansible collection layout (e2963cc)
- render ARC values on the control node and validate before the cluster role (28d8144)
- route the tailscale mesh through a provider interface (8ec62ed)
- run bootstrap.sh through the Ansible role instead of duplicating it (802d41c)
- sign the GitHub App JWT with a tested script instead of inline shell (e356764)
- split cluster, ARC, secrets and k8s client roles (88ed5cc)
- add a changelog file for the collection (3d1b428)
- add ansible-vault, env and 1Password example inventories (184e969)
- anchor determine-runner on exadev-runners as a deliberate choice (1a8ab81)
- correct the runner image build instructions (562e93c), closes #10
- describe bootstrap.sh as a local wrapper around the Ansible role (5b06538)
- describe the ARC role's profiles, validation, sizing and App setup (ffc708a)
- describe the collection without ExaDev's own hosts (e929d19)
- describe the two-role model and in-cluster fleet-health platform (e1bd85b)
- document Headscale backups, the warm standby and their RTO and RPO (e713ead)
- document node roles, scale-set profiles, and Ansible's verified status (bc1216b)
- document the Ansible deployment path (25a9e1d)
- document the mesh providers and add example inventories (ca4d2f0)
- document the release process and drop the stale ubuntu-latest claim (4078490), closes #10
- document the stale AutoscalingListener EphemeralRunnerSet-not-found trap (85ed7ac)
- document the Tailscale vpn-auth setup and its DNS search-domain pitfall (94d2449)
- document the three node roles and the etcd-over-Tailscale HA gotchas (e02e222)
- document the usage-driven autoscaler (b6dbf61)
- drop references to issues from before the repository was published (8e830a1)
- point stale build-runner-image.yml references at release.yml (46432fe)
- restructure README into standard getting-started/architecture/conventions sections (4019942)
- say the k3s runtime files are mounted from the role's project directory (13b2368)
- symlink AGENTS.md and CLAUDE.md to README.md (d5fe140)
- add the second space before the requirements comment (42203b8)
- put two spaces before the release workflow's permission comments (abf1182)
- add a Headscale mesh integration test (9551c78)
- add a permanent smoke-test workflow for the ARC scale set (88f9f05)
- drop the egress and network-state probes from the mesh test (8f17f0d)
- exercise Litestream replication and Headscale standby promotion (0e2449b)
- give the Litestream test a port of its own (d10dd48)
- probe which runner picks up runs-on: ubuntu-latest (2a6d8c9)
- record the runner's egress throughout the mesh test (878c444)
- run the mesh test against the role-managed cluster directory (df42184)
- snapshot the Docker host's network before the cold restart and on failure (a24809b)
- wait for the mesh to converge before failing a pod reachability check (41b9205)
- add semantic-release and commitlint devDependencies (09d5539)
- release: bump docker/metadata-action to its current major (9770bc9)
- always install the pinned Docker Compose for the mesh and Litestream tests (ee9ddcd)
- drop the input that ran the mesh test on ubuntu-latest (7c56ba2)
- let a manual mesh integration run choose ubuntu-latest (282de72)
- lint the collection with ansible-lint's production profile (1698dd2)
- push release commits with a deploy key instead of a GitHub App token (4dcd7b2)
- run CI, mesh and Litestream tests on GitHub-hosted runners (47f9077)
- run commitlint from the repo and put ansible-lint on PATH (e49cc21)
- run the release and image builds on GitHub-hosted runners (cccdfc6)
- syntax-check every top-level playbook (dc26796), closes #30
- add a yamllint config for this project's own conventions (d635bf1)
- declare the collection's Ansible requirement and the secrets role's cross-role facts (633fd4c)
- exclude release tooling from the built collection and git (ce9e4b5)
- license the project under MIT (29913c3)
- unignore CLAUDE.md and AGENTS.md (981f79b)
Release entries are generated automatically at release time and prepended above this line.