Skip to main content

max / alloy

Let a recipe ask for the NVIDIA layer, so astra's medium carries it astra's medium has to install alloy-nvidia rather than Alloy itself: the RTX 5070 Ti needs the open module, the module is compiled against one exact kernel, and that is why it lives in a thin derived image rather than in the shipped Containerfile at all. Nothing wired the two together, so building the medium meant remembering to derive by hand and then remembering to point the ISO at the result -- and build-iso.sh had no way to be pointed. NVIDIA is a second reserved recipe key beside ARCH, on the same reasoning: it names something the Containerfile cannot be told. build-iso.sh derives after building Alloy and before anything reads $IMAGE, so the builder's initramfs, the install source and the squashfs all come from the derived tag, and the module and the kernel it was built for cannot come apart. Deriving after the build rather than before is the part that matters. Deriving from a stale localhost/alloy:local would ship a medium whose module was built for a kernel the medium does not carry.
Co-Authored-By
Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session
https://claude.ai/code/session_013wvegQEzB5piwPowYQ3ZbV
Author: Max Johnson <me@maxj.phd> · 2026-09-04 20:50 UTC
Signed with PGP, not checked
Commit: 4fab4cdbe886b84a90e82f25dbb95bc6e74fbd31
Parent: 0175777
3 files changed, +65 insertions, -5 deletions
@@ -28,6 +28,8 @@
28 28 # build/build-iso.sh --update-target host:5000/alloy:43 # updates come from there
29 29 # build/build-iso.sh --host astra # mint with astra's recipe, arch included
30 30 # build/build-iso.sh --arch aarch64 # override the detected architecture
31 + # build/build-iso.sh --nvidia # install the derived alloy-nvidia image
32 + # build/build-iso.sh --no-nvidia # ...even if the recipe asks for it
31 33 # build/build-iso.sh --write /dev/sdX # build, then write to a device
32 34 # build/build-iso.sh --write-only --write /dev/sdX # write the ISO already built
33 35 #
@@ -83,6 +85,9 @@
83 85 # Empty means no per-machine recipe: the Containerfile's own defaults, which
84 86 # carry no compiler and no database. See build/host-recipe.sh.
85 87 HOST=""
88 + # Empty means the recipe decides, and a recipe that says nothing means no. See
89 + # --nvidia below and the NVIDIA key in build/host-recipe.sh.
90 + NVIDIA=""
86 91
87 92 BUILD_ARGS=()
88 93
@@ -126,6 +131,16 @@
126 131 --arch)
127 132 [ $# -ge 2 ] || die "--arch needs x86_64 or aarch64"
128 133 ARCH="$2"; shift 2 ;;
134 + # Build the derived alloy-nvidia image after Alloy itself and put THAT on
135 + # the medium -- as the live system and as the install source, since they are
136 + # one image here and the derived one is a superset. astra's recipe asks for
137 + # it; the flags are how a one-off says otherwise in either direction.
138 + #
139 + # The card is astra's and the module is compiled against one kernel, so this
140 + # only makes sense on the machine whose medium it is. build/build-nvidia.sh
141 + # refuses a non-aarch64 host, which is where that is enforced.
142 + --nvidia) NVIDIA=yes; shift ;;
143 + --no-nvidia) NVIDIA=no; shift ;;
129 144 # The device write. Same two flags build-image.sh takes, because the
130 145 # console emits one spelling for both artifacts.
131 146 --write) WRITE_DEV="${2:?--write needs a device path}"; shift 2 ;;
@@ -141,8 +156,9 @@
141 156 host_recipe_args "$HOST" BUILD_ARGS
142 157 # --arch wins over the recipe: the flag is how a one-off test of the boot
143 158 # chain asks for the other architecture, and the recipe is what the machine
144 - # normally takes.
159 + # normally takes. Same rule for --nvidia.
145 160 [ -n "$ARCH" ] || ARCH="$HOST_ARCH"
161 + [ -n "$NVIDIA" ] || NVIDIA="$HOST_NVIDIA"
146 162 fi
147 163
148 164 ARTIFACT="$OUTPUT/install.iso"
@@ -177,6 +193,26 @@
177 193 say "reusing $IMAGE"
178 194 fi
179 195
196 + # 1b. The NVIDIA module, as a thin image over the one just built.
197 + #
198 + # Everything below reads $IMAGE -- the builder's base, the install source, the
199 + # squashfs -- so pointing it at the derived tag here is the whole change. The
200 + # derived image is Alloy plus RPM Fusion's kmod and userspace, `FROM` the exact
201 + # digest of the image above, so the live system and the installed one carry the
202 + # same kernel as the module by construction.
203 + #
204 + # After the build and not before: build/build-nvidia.sh resolves the digest of
205 + # what it derives from, so deriving from a stale localhost/alloy:local would
206 + # produce a medium whose module was built for a different kernel than the one
207 + # it ships. Deriving here means the two cannot come apart.
208 + if [ "$NVIDIA" = yes ]; then
209 + say "deriving alloy-nvidia from $IMAGE"
210 + "$REPO_ROOT/build/build-nvidia.sh" --base "$IMAGE"
211 + IMAGE="localhost/alloy-nvidia:aarch64"
212 + privc podman image exists "$IMAGE" \
213 + || die "build/build-nvidia.sh reported success and left no $IMAGE"
214 + fi
215 +
180 216 # 2. The builder, derived from it so the initramfs matches the shipped kernel.
181 217 say "building $BUILDER"
182 218 priv podman build -t "$BUILDER" \
@@ -32,10 +32,19 @@
32 32 # because a typo'd key is silently dropped by podman and would mint exactly the
33 33 # image this file exists to prevent.
34 34 #
35 - # ARCH is the one reserved key, and it is not a build arg. build/build-iso.sh
36 - # consumes it to pick the medium's architecture; build/build-image.sh ignores
37 - # it and builds natively, per the standing rule that nothing here
38 - # cross-compiles.
35 + # Two reserved keys are not build args, because what they name is not something
36 + # the Containerfile can be told. Both are consumed by build/build-iso.sh and
37 + # ignored by build/build-image.sh.
38 + #
39 + # ARCH the medium's architecture. Not a cross-build: a machine builds its
40 + # own medium, per the standing rule that nothing here cross-compiles.
41 + # NVIDIA yes to install the derived alloy-nvidia image rather than Alloy
42 + # itself. The NVIDIA module is not a package the shipped Containerfile
43 + # can add: it has to be compiled against one exact kernel, so it lives
44 + # in a thin image `FROM` that kernel's digest (build/build-nvidia.sh,
45 + # ruled 2026-08-30 on alloy `2a382a75`). A dial would kernel-lock the
46 + # shipped image; a recipe key says which machine's medium carries the
47 + # derived one.
39 48
40 49 # Read a recipe into a BUILD_ARGS array, and set HOST_ARCH from a recipe that
41 50 # names one. Recipe args go in before anything the caller typed, so an explicit
@@ -56,6 +65,7 @@
56 65 }
57 66
58 67 HOST_ARCH=""
68 + HOST_NVIDIA=""
59 69 local recipe=()
60 70 local line key value
61 71 while IFS= read -r line || [ -n "$line" ]; do
@@ -87,6 +97,13 @@
87 97 HOST_ARCH="$value"
88 98 continue
89 99 fi
100 + if [ "$key" = "NVIDIA" ]; then
101 + case "$value" in
102 + yes|no) HOST_NVIDIA="$value" ;;
103 + *) printf 'error: %s: NVIDIA is %s; expected yes or no\n' "$file" "$value" >&2; return 1 ;;
104 + esac
105 + continue
106 + fi
90 107 grep -q "^ARG $key=" "$containerfile" || {
91 108 printf 'error: %s: %s is not an ARG the Containerfile declares\n' "$file" "$key" >&2
92 109 return 1
@@ -28,3 +28,10 @@
28 28 # validator. Found by build/preflight.sh on 2026-09-04, before astra's medium
29 29 # had ever been built for the first time (alloy `2341d23f`).
30 30 BROWSER=none
31 +
32 + # Reserved key, read by build/build-iso.sh and ignored by build/build-image.sh.
33 + # The medium installs the derived alloy-nvidia image rather than Alloy itself:
34 + # the RTX 5070 Ti needs the open module, which is compiled against one exact
35 + # kernel and so cannot be a package the shipped Containerfile adds. Ruled
36 + # 2026-08-30 (Max, alloy `2a382a75`); the layer is build/Containerfile.nvidia.
37 + NVIDIA=yes