॥ श्री ॥

Build Pipeline

Architecture 2026-08-28

Shanios images are produced by a multi-stage build pipeline that takes a package list, an overlay filesystem, and a profile-specific customization script, and outputs a compressed Btrfs send-stream (.zst), an ISO, or both. The entire pipeline runs inside a privileged Docker container so the host system is never modified.

Overview

The pipeline is driven by build.sh in shani-install-media. It dispatches to specialized sub-scripts for each stage:

build.sh <command> -p <profile>

Commands

CommandWhat it doesOutput
imagePacstraps packages, applies overlay, runs customization, snapshots to .zst<date>/<os>-<date>-<profile>.zst + .sha256 + .asc
flatpakBuilds a Flatpak image from flatpak-packages.txtflatpakfs.zst
snapBuilds a Snap seed image from snap-packages.txtsnapfs.zst
isoRuns mkarchiso with base + optional Flatpak/Snap images<date>/<os>-<date>-<profile>.iso
repackSigns the ISO for Secure Boot and generates torrentsigned_<os>-<date>-<profile>.iso + .torrent
uploadUploads artifacts to SourceForge and Cloudflare R2Remote artifacts
releaseCreates latest.txt or stable.txt channel manifestsChannel files
promote-stablePromotes current latest to stable after verificationUpdated channel files
verifyChecks remote artifacts against local checksumsPass/fail
testInstalls/boots/updates/rolls back on loop-mounted disksTest report

Compound Commands

CommandPipeline
allimage → release latest → upload image
fullimage → flatpak → snap → iso → repack → release latest → upload all
iso-onlyDownload from R2 → build ISO → repack → upload iso
publishrelease → upload (for promoting pre-released artifacts)

Build Stages

1. Base Image (build-base-image.sh)

The core stage. Creates a Btrfs subvolume, pacstraps the package list from image_profiles/<profile>/Packages-{Base,Desktop,Extras}, applies the shared overlay (base configs, systemd units), then runs the profile-specific customization script:

  • gnome-customization.sh — enables GNOME services, installs GNOME-specific Flatpaks
  • plasma-customization.sh — enables KDE services, Kvantum theme override
  • cosmic-customization.sh — enables COSMIC services
  • kiosk-customization.sh — enables Cage + labwc, configures unattended GDM autologin, mounts tmpfs home
  • server-customization.sh — enables cloud-init, sshd, firewalld, disables GUI services

The result is snapshotted as a Btrfs send-stream and compressed with Zstandard.

2. Flatpak Image (build-flatpak-image.sh)

If flatpak-packages.txt exists for the profile, this stage creates a separate Btrfs subvolume, installs all listed Flatpaks, and produces a flatpakfs.zst that is bundled into the ISO.

3. Snap Image (build-snap-image.sh)

Same pattern as Flatpak — if snap-packages.txt exists, builds a snapfs.zst with pre-installed snaps.

4. ISO (build-iso.sh)

Runs mkarchiso using the base image and optional Flatpak/Snap images as source. The --from-r2 flag allows building the ISO without the base image locally — it downloads from Cloudflare R2 instead.

5. Repack (repack-iso.sh)

Signs the ISO with sbsign for Secure Boot, generates .sha256 and .asc files, and creates a BitTorrent file for distribution.

6. Upload (upload.sh)

Pushes artifacts to SourceForge (primary download) and Cloudflare R2 (build cache and CDN). Uses rclone for R2 and rsync/sftp over SSH for SourceForge (there is no lftp in the upload script).

Image Profiles

Each profile has its own directory under image_profiles/:

ProfileDirectoryDesktopPackage count
gnomeimage_profiles/gnome/GNOME25 meta-packages + Flatpaks
plasmaimage_profiles/plasma/KDE Plasma25 meta-packages + Flatpaks
cosmicimage_profiles/cosmic/COSMIC25 meta-packages + Flatpaks
kioskimage_profiles/kiosk/Cage + labwc (Firefox)17 packages
serverimage_profiles/server/None (headless)170 explicit packages
Note: The "25 meta-packages" for gnome/plasma/cosmic are defined in image_profiles/<profile>/Packages-{Base,Desktop,Extras}. Each meta-package (e.g., shani-core, shani-desktop-gnome) pulls in many transitive dependencies via shani-pkgbuilds PKGBUILDs and .install scripts, resulting in hundreds of total packages installed on the final image.

Shared packages across all profiles are in image_profiles/shared/.

Docker Environment

All build steps run inside the shrinivasvkumbhar/shani-builder Docker image (built from shani-builder/docker/). The container is privileged because image assembly requires Btrfs operations, loop mounts, and chroot — all of which need host-level access.

See Fleet Deployment for how OEMs use this pipeline to build custom images.

CI/CD

Two GitHub Actions workflows in shani-builder automate the pipeline:

  • build-image.yml — builds the OS image on push to main or manual dispatch
  • promote-stable.yml — promotes latest to stable after verification

Both use AWS OIDC for authentication (no long-lived keys).

See Also