building
TunaOS images are built with podman and the just command runner using multi-stage Containerfiles.
Prerequisitesβ
| Tool | Minimum Version | Purpose |
|---|---|---|
| podman | 5.x | Container build engine (BuildKit) |
| just | 1.x | Command runner |
| yq | 4.x | YAML query tool for build config |
| git | 2.x | Source control + submodules |
Optional for ISO builds:
| Tool | Purpose |
|---|---|
| tacklebox | ISO generation (auto-downloaded if missing) |
| lima | VM-based image verification |
| qemu-img | QCOW2 conversion |
Quick Startβ
# Clone the repo
git clone https://github.com/tuna-os/tunaOS.git
cd tunaOS
# Build Yellowfin with GNOME desktop
just build yellowfin gnome
This produces a local image tagged localhost/yellowfin:gnome.
Build Variants and Flavorsβ
Syntaxβ
just build <variant> <flavor>
Variantsβ
| Variant | Base OS | Notes |
|---|---|---|
yellowfin | AlmaLinux Kitten 10 | Closest to upstream CentOS Stream |
albacore | AlmaLinux 10 | Stable, RHEL-compatible |
skipjack | CentOS Stream 10 | Upstream of RHEL |
bonito | Fedora 44 | Cutting-edge packages |
redfin | RHEL 10 | Subscription required, local-build only |
Flavorsβ
| Flavor | Description |
|---|---|
base | No desktop environment |
gnome | GNOME desktop |
gnome50 | GNOME 50 (latest) |
kde | KDE Plasma |
cosmic | COSMIC desktop |
niri | Niri tiling compositor |
gnome-hwe | GNOME with HWE kernel |
gnome-nvidia | GNOME with NVIDIA drivers |
gnome-nvidia-hwe | GNOME with NVIDIA on HWE kernel |
Any desktop flavor can be combined with -hwe, -nvidia, or -nvidia-hwe suffixes.
Platform Selectionβ
The build auto-detects your platform. Override with:
just build yellowfin gnome target_platform=linux/arm64
just build albacore kde target_platform=linux/amd64/v2
Build Pipelineβ
Each build runs through these stages:
- Context assembly β system files, brew files, and build scripts copied into a scratch image
- Base stage (
base-no-de) β copy files, install packages, configure services, cleanup - Hardware variant stage (optional) β
base-hweorbase-nvidiafor chain builds - DE stage β install desktop packages (
gnome.sh,kde.sh, etc.), versionlock glib2, symlink/opt β /var/opt - Chunkah rechunking β reduces image layer count for distribution efficiency
- Final stage β apply labels and OCI annotations
Containerfile Selectionβ
The Justfile automatically selects the correct Containerfile:
| Flavor suffix | Containerfile | Description |
|---|---|---|
| (none) | Containerfile | Base build with base-no-de |
-hwe | Containerfile.hwe | HWE kernel layer |
-nvidia | Containerfile.nvidia | NVIDIA driver layer |
-nvidia-hwe | Containerfile.nvidia | nvidia on HWE parent |
Building ISOsβ
Via tacklebox (recommended)β
# Build ISO for Yellowfin GNOME
just iso yellowfin gnome
# Build from GHCR images (no local build needed)
just iso yellowfin gnome repo=ghcr
This uses scripts/build-iso-tacklebox.sh which automatically downloads tacklebox if not installed.
Building QCOW2 disk imagesβ
# Build QCOW2 for Lima/QEMU
just qcow2 yellowfin gnome
Building for RHEL (Redfin)β
Redfin requires a Red Hat subscription. See Redfin Setup for prerequisites. Then:
just build redfin base
just build redfin gnome
RHSM credentials are passed via BuildKit secrets β never stored in image layers.
Using Build Cacheβ
Local builds use a shared .rpm-cache volume for DNF package caching. The cache is:
- Automatic β enabled for local builds, disabled for CI
- Shared β all variants reuse the same cache
- Persistent β survives
just clean(usejust clean-cacheto remove)
# Clean build artifacts, keep cache
just clean
# Remove cache too
just clean-cache
Switching an Existing Systemβ
If you're running a bootc-based OS:
# Switch to TunaOS
sudo bootc switch ghcr.io/tuna-os/yellowfin:gnome
Verificationβ
Test boot a QCOW2 imageβ
# Build and boot in Lima VM with automated DM check
just test-vm yellowfin gnome
# Full demo: build QCOW2, start VM, open noVNC in browser
just demo albacore gnome
Test boot an ISOβ
# Build and boot ISO in QEMU via web browser
just demo-iso skipjack gnome
Verify image signaturesβ
All published TunaOS images are signed with cosign using keyless signing (OIDC). Verify any image before use:
# Verify with OIDC identity
cosign verify \
--certificate-identity https://github.com/tuna-os/tunaOS/.github/workflows/reusable-build-image.yml@refs/heads/main \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
ghcr.io/tuna-os/yellowfin:gnome
# Verify with public key (from cosign.pub in the repo)
cosign verify --key cosign.pub ghcr.io/tuna-os/yellowfin:gnome
For local builds, images are not signed β verification applies only to published GHCR images.