Skip to main content

max / everycycle

Retarget the reference platform from Ubuntu LTS to a Fedora downstream The Ubuntu pin predates Alloy. It was written when the plan was to standardize on the distro MNW production runs, and the reference host is Fedora-derived now. Max, 2026-08-21. Loosely is deliberate: the reference host is where EveryCycle is built and probed first, not a supported-platform contract, and the codebase stays generic Linux with everything else best-effort. Six sites: the platform bullets and implementation-languages line in the roadmap, the platform paragraph and build line in the README, the executor isolation rationale, and the deprecation-window example in api-stability. Two things recorded rather than quietly dropped. The Ubuntu bullet carried its own justification, that it matched the MNW production server so one test matrix covered infra and inference. MNW production is Ubuntu 24.04, so that rationale does not survive and the matrices are separate now. Written into the roadmap as an accepted cost: EveryCycle's target is the box with the GPUs in it, and the two were the same distro by coincidence. Immutability is the one part that is genuinely different, and it is the part a GPU project cares about. An image-based host has no DKMS at update time, so vendor kernel modules are baked into the image or layered as akmods instead of being built on the machine. The rest is friendlier than it sounds and is now said so explicitly: /opt and /usr/local are /var-backed and writable so the CUDA and ROCm installers land where they expect, /etc and /var persist, and systemd, udev and /dev are unchanged. The executor-isolation argument is unchanged in substance. It turned on glibc rather than on which distro ships it, so it survives the move; the wording now says that. docs/appraisal.md needed no edit. It names the host and the card and never named the distro.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Author: Max Johnson <me@maxj.phd> · 2026-08-21 21:18 UTC
Signed with PGP, not checked
Commit: f954f6e3c815d2ba14aec6be20a972487d80f3cc
Parent: e2d7f9b
3 files changed, +9 insertions, -7 deletions
M README.md +2 -2
@@ -53,11 +53,11 @@
53 53
54 54 **Linux only by design.** macOS-native is not on the roadmap. Apple Silicon may eventually be supported via Asahi Linux as the project's GPU stack matures.
55 55
56 - **Pinned to Ubuntu LTS (24.04).** Ubuntu LTS is the single supported distro, the only target that gets formal support, the same distro MNW production servers run on. The codebase is generic Linux and should work elsewhere, but issues outside Ubuntu LTS are addressed best-effort. Executor isolation (in-process vs sidecar) is a per-executor choice driven by vendor SDK stability and crash blast-radius, not by libc compatibility.
56 + **A Fedora downstream is the reference target.** Loosely, and deliberately so: it is where EveryCycle is built and probed first, not a supported-platform contract. The codebase is generic Linux and should work elsewhere; issues off the reference host are addressed best-effort. One caveat worth knowing up front, because it is the only one that bites a GPU project: an image-based host has no DKMS, so vendor kernel modules are baked into the image or layered as akmods rather than built on the machine. Executor isolation (in-process vs sidecar) is a per-executor choice driven by vendor SDK stability and crash blast-radius, not by libc compatibility.
57 57
58 58 ## Building
59 59
60 - Standard Cargo. Rust 1.85+ (edition 2024). Built and tested on Ubuntu LTS 24.04.
60 + Standard Cargo. Rust 1.85+ (edition 2024). Built and tested on the reference host, aarch64 Linux.
61 61
62 62 ```
63 63 cargo build --release
@@ -67,7 +67,7 @@
67 67 **Major releases** (`X.0.0`) are reserved for changes that cannot be expressed under the additive rules above. A major release requires:
68 68
69 69 - A migration document published with the release notes, with side-by-side before/after for every breaking change.
70 - - A deprecation window of **at least one full release cycle on every supported distro** before the deprecated surface is removed. "Release cycle" means the cadence of the underlying distro (e.g. Ubuntu LTS point releases), not the daemon's own.
70 + - A deprecation window of **at least one full release cycle on every supported distro** before the deprecated surface is removed. "Release cycle" means the cadence of the underlying distro (e.g. Fedora's release cadence), not the daemon's own.
71 71 - The previous major version's daemon binary remains buildable from source for the duration of the deprecation window, so operators can run both side-by-side during migration.
72 72 - A bump in `API_VERSION` to the new major (`"2"`, `"3"`, ...).
73 73
M docs/roadmap.md +6 -4
@@ -39,8 +39,10 @@
39 39 ## Platform and distribution
40 40
41 41 - **Linux only by design.** macOS-native is not on the roadmap. Apple Silicon support, if it comes, comes via Asahi Linux.
42 - - **Pinned to Ubuntu LTS (24.04).** One supported distro across the whole project — matches the MNW production server target, so one test matrix covers infra and inference. Other distros are best-effort, no support commitment.
43 - - **Glibc build, .deb packaging.** The daemon is a standard glibc binary packaged as a .deb for Ubuntu LTS. Executor isolation (in-process dlopen vs out-of-process sidecar) is decided per executor by vendor SDK stability and crash blast-radius, not by libc compatibility.
42 + - **A Fedora downstream is the reference target, loosely.** Changed 2026-08-21. This line read "Pinned to Ubuntu LTS (24.04)" and was written before Alloy existed; the reference host is a Fedora-derived image now. Loosely is the operative word: the codebase is generic Linux, the reference host is where it is built and probed first, and nothing here is a hard pin. Other distros stay best-effort.
43 + - **What the change costs, stated.** The Ubuntu line justified itself as matching the MNW production server, so that one test matrix covered infra and inference. MNW production is Ubuntu 24.04, so that no longer holds and the two matrices are separate. Accepted deliberately: EveryCycle's target is the box with the GPUs in it, not the box serving the website, and those were only ever the same distro by coincidence.
44 + - **Glibc build, RPM packaging.** The daemon is a standard glibc binary. Executor isolation (in-process dlopen vs out-of-process sidecar) is decided per executor by vendor SDK stability and crash blast-radius, not by libc compatibility.
45 + - **Immutability is the one thing that is genuinely different, and it is a kernel-module question.** An image-based host (bootc, rpm-ostree) has no DKMS at update time, so a vendor kernel module cannot be built on the machine the way `nvidia-dkms` does on Ubuntu. It has to be baked into the image or layered as an akmod. Everything else about an immutable host is friendlier than it sounds: `/opt` and `/usr/local` are `/var`-backed and writable, so CUDA and ROCm install where their installers expect, `/etc` and `/var` persist, and systemd, udev and `/dev` are unchanged. Treat the module delivery path as real work and the rest as packaging format.
44 46
45 47 ## Threads
46 48
@@ -167,7 +169,7 @@
167 169 - **Client API stability is a sacred commitment.** Once Thread I reaches v1 freeze, the client-facing API follows strict semver: minor versions are additive, patch versions are bug-fix-only, major versions require a migration document and a deprecation window of at least one full release cycle on every supported distro. Before v1 freeze, the API is explicitly marked unstable and may break on any release. The freeze is the line that turns EveryCycle from a tool into a platform; everything downstream (compatibility shims, third-party clients, distro defaults) depends on this commitment being honored.
168 170 - **Multi-client is the default, not a feature.** The daemon assumes concurrent clients from A1, even when only one is connected. The internal data model, scheduler, and audit surface are designed around N clients sharing M devices under policy; the N=1 case is just the limit. This is the structural difference between a system service and a runtime library.
169 171 - **Compatibility shims are clients, not daemon code.** Each protocol shim (OpenAI, llama.cpp, Ollama, vLLM, ComfyUI) is a separate process that speaks the native EveryCycle client API. The shims do not get privileged access to internals. This forces the native API to be expressive enough that the shims are thin — and keeps the daemon free of protocol-specific code paths.
170 - - **Implementation languages.** Main binary is Rust, built natively for Ubuntu LTS 24.04 (glibc, .deb-packaged). Module boundary is a **stable C ABI** from a reasonable point — early enough that the second executor doesn't lock the trait shape into Rust-internals. Module *implementations* may be in any language that emits a C-ABI shared library (Rust, Zig, C). The BMC agent is a separate binary and is the leading candidate for being written in Zig rather than Rust; that decision deferred until the agent is real.
172 + - **Implementation languages.** Main binary is Rust, built natively for the reference Fedora downstream (glibc, RPM-packaged). Module boundary is a **stable C ABI** from a reasonable point — early enough that the second executor doesn't lock the trait shape into Rust-internals. Module *implementations* may be in any language that emits a C-ABI shared library (Rust, Zig, C). The BMC agent is a separate binary and is the leading candidate for being written in Zig rather than Rust; that decision deferred until the agent is real.
171 173 - **Crate naming.** The daemon-internal native client API lives in `crates/api/` (renamed from `crates/serving/` on 2026-06-21). Thread J shims (OpenAI, llama.cpp, Ollama, vLLM, ComfyUI) will land as their own crates (`crates/shim-openai`, etc.) when they ship — they are not modules of `crates/api`. The HTTP "serving" framing is gone from the daemon by design.
172 174
173 175 ## Model stance
@@ -186,7 +188,7 @@
186 188
187 189 ## Open questions (will be resolved iteratively)
188 190
189 - - Executor isolation: in-process dlopen + watchdog threads + structured panic handling, or out-of-process with local-socket IPC. Per executor, driven by vendor SDK stability and crash blast-radius. In-process is the default for executors that behave; out-of-process when an executor empirically destabilizes the host process. The Ubuntu LTS / glibc pin removes libc compatibility as a forcing factor — CUDA and ROCm SDKs target glibc natively, so sidecar separation is now a stability choice, not a packaging workaround.
191 + - Executor isolation: in-process dlopen + watchdog threads + structured panic handling, or out-of-process with local-socket IPC. Per executor, driven by vendor SDK stability and crash blast-radius. In-process is the default for executors that behave; out-of-process when an executor empirically destabilizes the host process. Standardizing on one glibc reference host removes libc compatibility as a forcing factor, since CUDA and ROCm SDKs target glibc natively, so sidecar separation is a stability choice rather than a packaging workaround. That argument was made for Ubuntu and survives the move unchanged: it turns on glibc, not on which distro ships it.
190 192 - CPU executor placement: statically linked into the base binary (always-present fallback) vs another module
191 193 - A1 dispatch planner: greedy heuristic only, or invest in a real optimizer up front
192 194 - BMC agent's actual A1-equivalent role: just enumerate Redfish, or already running on flashed OpenBMC