Skip to main content

max / alloy

Let a recipe name its update target, so no mint can forget one Without an update target the installer writes the compiled-in public registry, which install/image.rs calls a deliberate dead end, and updates_scheduled() leaves bootc-fetch-apply-updates.timer disabled because it reads the same absent kernel parameter. A machine minted that way cannot take a fix without a `bootc switch` typed at it or a second medium, at the point it is newest. It was reachable only as --update-target, a thing to remember at every mint, while every other per-machine dial already lives in the recipe. UPDATE_TARGET joins ARCH and NVIDIA as a reserved key: build-iso.sh reads it, build-image.sh ignores it, and an explicit --update-target still wins, the same rule the other two follow. fw13 and fw12 both take fw13:5000/alloy:local, the tag dev-push.sh publishes. fw13 builds its own image and serves it to itself; the tag carries the host name so one registry also feeds fw12 over the LAN. astra takes none: the registry it would name is the one moving off astra ahead of its own cut, and a destination baked in before that move is built is a guess in a medium. docs/IMAGE.md said ARCH was the one reserved key, which NVIDIA had already made wrong; it now lists all three and what the three recipes say today.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session
https://claude.ai/code/session_01WFBzMprSmNCfvdj2cGZyka
Author: Max Johnson <me@maxj.phd> · 2026-09-05 15:08 UTC
Signed with PGP, not checked
Commit: f2c6f9994bdd73e54fa905ccbd27a8dc706a690e
Parent: 3c15574
5 files changed, +64 insertions, -6 deletions
@@ -26,6 +26,7 @@
26 26 # build/build-iso.sh --fast # iteration: cheap compression, keeps source
27 27 # build/build-iso.sh --fast --skip-source # boot chain only, cannot install
28 28 # build/build-iso.sh --update-target host:5000/alloy:43 # updates come from there
29 + # # (or UPDATE_TARGET in the host recipe)
29 30 # build/build-iso.sh --host astra # mint with astra's recipe, arch included
30 31 # build/build-iso.sh --arch aarch64 # override the detected architecture
31 32 # build/build-iso.sh --nvidia # install the derived alloy-nvidia image
@@ -159,6 +160,7 @@
159 160 # normally takes. Same rule for --nvidia.
160 161 [ -n "$ARCH" ] || ARCH="$HOST_ARCH"
161 162 [ -n "$NVIDIA" ] || NVIDIA="$HOST_NVIDIA"
163 + [ -n "$UPDATE_TARGET" ] || UPDATE_TARGET="$HOST_UPDATE_TARGET"
162 164 fi
163 165
164 166 ARTIFACT="$OUTPUT/install.iso"
@@ -38,6 +38,14 @@
38 38 #
39 39 # ARCH the medium's architecture. Not a cross-build: a machine builds its
40 40 # own medium, per the standing rule that nothing here cross-compiles.
41 + # UPDATE_TARGET where `bootc upgrade` fetches from on a machine installed
42 + # from this medium. Without one the installer writes the compiled-in
43 + # public registry, which install/image.rs calls a deliberate dead
44 + # end, and updates_scheduled() leaves the timer disabled because it
45 + # reads the same absent kernel parameter. So a machine minted without
46 + # it cannot be fixed without a `bootc switch` typed at the machine or
47 + # a second medium, at the moment it is newest. It was a flag anyone
48 + # could forget; a recipe key is a machine's own answer, kept.
41 49 # NVIDIA yes to install the derived alloy-nvidia image rather than Alloy
42 50 # itself. The NVIDIA module is not a package the shipped Containerfile
43 51 # can add: it has to be compiled against one exact kernel, so it lives
@@ -66,6 +74,7 @@
66 74
67 75 HOST_ARCH=""
68 76 HOST_NVIDIA=""
77 + HOST_UPDATE_TARGET=""
69 78 local recipe=()
70 79 local line key value
71 80 while IFS= read -r line || [ -n "$line" ]; do
@@ -97,6 +106,10 @@
97 106 HOST_ARCH="$value"
98 107 continue
99 108 fi
109 + if [ "$key" = "UPDATE_TARGET" ]; then
110 + HOST_UPDATE_TARGET="$value"
111 + continue
112 + fi
100 113 if [ "$key" = "NVIDIA" ]; then
101 114 case "$value" in
102 115 yes|no) HOST_NVIDIA="$value" ;;
M docs/IMAGE.md +30 -6
@@ -273,18 +273,42 @@
273 273 Format is `KEY=VALUE`, one per line, with `#` comments. Every key must name an
274 274 `ARG` the Containerfile declares, checked against the Containerfile itself when
275 275 the recipe is read, because podman drops an unknown build arg silently and a
276 - typo would mint exactly the image the file exists to prevent. `ARCH` is the one
277 - reserved key: `build-iso.sh` uses it to pick the medium's architecture and
278 - `build-image.sh` ignores it, since nothing here cross-compiles.
276 + typo would mint exactly the image the file exists to prevent.
277 +
278 + Three keys are reserved, because what each names is not something the
279 + Containerfile can be told. All three are read by `build-iso.sh` and ignored by
280 + `build-image.sh`.
281 +
282 + | key | what |
283 + |-----|------|
284 + | `ARCH` | the medium's architecture. Not a cross-build: a machine builds its own medium. |
285 + | `NVIDIA` | `yes` installs the derived `alloy-nvidia` image rather than Alloy itself, since the module compiles against one exact kernel. |
286 + | `UPDATE_TARGET` | where `bootc upgrade` fetches from on a machine installed from this medium. |
287 +
288 + `UPDATE_TARGET` is the one whose absence is expensive and silent. Without it the
289 + installer writes the compiled-in public registry, which `install/image.rs` calls
290 + a deliberate dead end, and `updates_scheduled()` leaves
291 + `bootc-fetch-apply-updates.timer` disabled because it reads the same absent
292 + kernel parameter. So a machine minted without it cannot take a fix at all
293 + without a `bootc switch` typed at the machine or a second medium, at the moment
294 + it is newest. It was reachable only as `--update-target`, which is a thing to
295 + remember per mint; as a recipe key it is the machine's own answer, kept.
279 296
280 297 Recipe values go in ahead of anything typed on the command line, so an explicit
281 298 `--build-arg` overrides the recipe rather than racing it.
282 299
283 - What the three recipes say today: fw13 takes `LANGS=rust,js` and
284 - `DB=postgres16` for the build-host role; astra takes those plus
285 - `PROFILE=server` and `ARCH=aarch64`; fw12 sets no dials at all and carries only
300 + What the three recipes say today: fw13 takes `LANGS=rust,js`, `DB=postgres16`
301 + and `GUI=tauri` for the build-host role; astra takes those plus `PROFILE=server`,
302 + `ARCH=aarch64` and `NVIDIA=yes`; fw12 sets no dials at all and carries only
286 303 identity and answers, below.
287 304
305 + fw13 and fw12 both take `UPDATE_TARGET=fw13:5000/alloy:local`, the tag
306 + `build/dev-push.sh` publishes: fw13 builds its own image and serves it to
307 + itself, and the tag carries the host name so one registry also feeds fw12 over
308 + the LAN. astra takes none, because the registry it would name is the one moving
309 + off astra ahead of its own cut, and naming a destination before that move is
310 + built would bake a guess into a medium.
311 +
288 312 ## Preflight
289 313
290 314 `build/preflight.sh <host>` answers, before any mint, what a mint would otherwise
@@ -44,3 +44,10 @@
44 44 # No. The lookup sends this machine's address to a third party, and a machine
45 45 # that comes up UTC can be fixed in `alloy settings` in a second.
46 46 ALLOY_LOCATE_TIMEZONE=no
47 +
48 + # Where `bootc upgrade` fetches from. fw13 serves this tag out of the registry
49 + # build/dev-push.sh publishes to, so a fix reaches fw12 over the LAN without a
50 + # second medium. Without this key the installer writes the compiled-in public
51 + # registry, which does not exist yet, and leaves the update timer disabled: a
52 + # machine that cannot be fixed except by typing `bootc switch` at it.
53 + UPDATE_TARGET=fw13:5000/alloy:local
@@ -24,3 +24,15 @@
24 24 # 2026-09-04 that a glibc 2.42 floor is acceptable and backwards compatibility
25 25 # is not a goal, which retired the only reason the box existed.
26 26 GUI=tauri
27 +
28 + # Where `bootc upgrade` fetches from, and the whole of fw13's fix loop after the
29 + # cut: build/dev-push.sh publishes this tag to a registry on fw13 itself, so the
30 + # machine builds its own image and serves it to itself with no second box in
31 + # play. The tag carries the host name so one medium also serves fw12.
32 + #
33 + # Without this key the installer writes the compiled-in public registry, which
34 + # install/image.rs calls a deliberate dead end, and leaves
35 + # bootc-fetch-apply-updates.timer disabled because it reads the same absent
36 + # kernel parameter. That is a machine with no way to take a fix, at the point it
37 + # is newest. Measured 2026-09-05.
38 + UPDATE_TARGET=fw13:5000/alloy:local