genpack is a suite of tools for declaratively building, distributing, and booting purpose-built immutable system images based on Gentoo Linux. Rather than following the traditional approach of "install an OS and then customize it," genpack adopts an image factory philosophy: build the entire OS image from a blueprint (JSON5).
What Docker achieved for application containers, genpack aims to achieve at the entire OS level, spanning bare-metal machines, virtual machines, and embedded devices.
| Component | Language | Role | Repository |
|---|---|---|---|
| genpack | Python + C++ | Generate SquashFS images from JSON5 definitions | wbrxcorp/genpack |
| genpack-overlay | Gentoo ebuild/profile | Package definitions, profile hierarchy, and initialization scripts | wbrxcorp/genpack-overlay |
| genpack-init | C++ + Python (pybind11) | Configure the system at every boot based on system.ini | wbrxcorp/genpack-init |
| genpack-install | C++ | Deploy images to disk/ISO/ZIP with self-update capability | wbrxcorp/genpack-install |
| vm | C++ | Run and manage genpack images on QEMU/KVM | shimarin/vm |
| genpack-artifacts | JSON5 + shell scripts | Collection of concrete image definitions | genpack-artifacts (GitHub Org) |
genpack is the core build engine of the toolchain. It takes a declarative configuration file called genpack.json5 as input and produces optimized SquashFS images using Gentoo Linux's stage3 and Portage.
genpack uses a two-layer lower/upper architecture for building.
systemd-nspawn containerThis design ensures that compilers, header files, and other build-time-only files remain in the lower layer and are never included in the final image. A minimal runtime image is obtained naturally.
{
name: "nextcloud",
profile: "paravirt",
packages: [
"www-apps/nextcloud",
"dev-db/mysql",
"dev-lang/php",
"net-misc/redis"
],
services: ["apache2", "mysqld", "redis"],
users: [{ name: "nextcloud", uid: 1000 }],
use: {
"dev-lang/php": "+mysql +curl +gd +xml +zip"
},
compression: "xz"
}
Package lists, enabled services, user definitions, USE flags, and even kernel configuration are all consolidated in this single file. This eliminates manual system construction and achieves fully reproducible builds.
| Command | Function |
|---|---|
genpack build | Full build (lower → upper → pack) |
genpack lower | Build/rebuild the lower layer |
genpack upper | Build/rebuild the upper layer |
genpack pack | Generate the SquashFS image |
genpack bash | Interactive shell inside the lower layer |
genpack archive | Create a tar.gz archive of the configuration |
x86_64, aarch64 (ARM64), i686, and riscv64 are supported. Architecture-specific settings can be managed through the arch section of genpack.json5.
GitHub: wbrxcorp/genpack-overlay
genpack-overlay is a Gentoo Portage overlay that provides the building blocks for genpack images: metapackages that bundle related functionality and a profile hierarchy that abstracts away deployment target differences.
genpack/base (common to all targets: kernel, init, base tools)
├── genpack/systemimg (bare-metal: hardware detection, storage tools)
│ └── systemimg/baremetal (BIOS/UEFI, device drivers)
├── genpack/paravirt (virtualized: QEMU guest agent, virtio)
├── genpack/gnome (GNOME desktop)
└── genpack/weston (Wayland compositor)
Image definitions simply specify profile: "paravirt" or profile: "gnome/baremetal", and the appropriate base environment is selected automatically.
Each package can place initialization scripts under /usr/lib/genpack/package-scripts/. Package-specific setup tasks are defined here, such as MySQL data directory initialization, Docker storage configuration, and SSH host key generation.
genpack-init is a hybrid initialization system written in C++ and Python (pybind11). It starts as PID 1 and, at every boot, reads system.ini from the boot partition and executes Python scripts to configure the system.
/run/initramfs/boot/system.ini (located on the FAT partition)configure(ini) function in each module under /usr/lib/genpack-init/*.py/sbin/init = systemd) via execThrough pybind11, genpack-init exposes the following low-level operations to Python scripts:
The most important design characteristic of genpack-init is that a single system.ini on the FAT partition is all it takes to customize the entire system's behavior.
The genpack image's initramfs detects the presence of a data partition on the boot storage (or a data virtual disk in the case of QEMU) at startup and dynamically determines the upper layer of the overlayfs root filesystem:
This mechanism allows the same image to exhibit different operational characteristics depending on the deployment configuration. A setup without a data partition enables "reset every reboot" operation suited for kiosk terminals and demo environments, while a setup with a data partition enables persistent operation suited for servers. In either case, genpack-init reads system.ini and configures the system at every boot, so changes to system.ini are always reflected on the next startup.
GitHub: wbrxcorp/genpack-install
genpack-install writes the generated system image to physical storage and makes it bootable.
| Mode | Purpose |
|---|---|
--disk=<device> | Install to a physical disk (partitioning + bootloader setup) |
| Self-update | Atomically replace the image on a running system |
--cdrom=<file> | Create a bootable ISO 9660 image |
--zip=<file> | Create a ZIP archive |
genpack-install generates and installs GRUB bootloaders for BIOS / UEFI (x86_64, i386, ARM64, RISC-V) / Raspberry Pi boot methods. El Torito CD/ISO booting is also supported.
Image updates on a running system are performed through the following atomic rename sequence:
system → system.cur (back up the current image)
system.new → system (activate the new image)
system.cur → system.old (retain the previous generation = rollback possible)
vm is a command-line tool for running and managing genpack system images as virtual machines on QEMU/KVM.
| Command | Function |
|---|---|
vm run <image> | Boot a VM from a system image |
vm service | Run VMs as services based on vm.ini |
vm console <name> | Connect to a VM's serial console |
vm stop <name> | Graceful shutdown via QMP protocol |
vm list | List running VMs |
vm ssh user@vm | SSH into a VM via vsock |
vm usb | Enumerate USB devices (with XPath query support) |
GitHub Organization: genpack-artifacts
genpack-artifacts is a collection of concrete system image definitions built with the genpack toolchain. Each artifact is managed as an individual repository.
artifact-name/
├── genpack.json5 # Declarative image definition
├── files/ # Files merged into the root filesystem
│ ├── build.d/ # Scripts executed at build time
│ ├── etc/ # Configuration files
│ └── boot/ # Boot configuration (grub.cfg, etc.)
├── kernel/ # Kernel customization (optional)
│ └── config.d/ # Kernel configuration fragments
└── savedconfig/ # Portage savedconfig (per architecture)
| Category | Artifact | Purpose |
|---|---|---|
| Desktop | gnome, streamer | GNOME desktop, OBS streaming workstation |
| ML/AI | torch | PyTorch + ROCm/CUDA machine learning environment |
| Cloud | nextcloud, owncloud | Self-hosted cloud storage |
| Project management | redmine | Redmine project management |
| Networking | vpnhub, walbrix | VPN gateway, network appliance |
| Security | suricata, borg | IDS, backup server |
| Embedded | camera | Motion-detection camera system |
| Utilities | rescue, stub | System recovery, multi-distribution VM provisioning |
From minimal configurations (rescue: a dozen or so packages) to full desktops (gnome: hundreds of packages), everything is defined using the same genpack.json5 + files/ pattern.
Every image is declaratively defined in genpack.json5. Packages, USE flags, users, services, and kernel configuration are all consolidated in a single file, enabling reproducible builds with no manual intervention.
The final artifact is a read-only SquashFS image. System updates are performed not by modifying the running environment but by building a new image and atomically swapping it in. The runtime root filesystem is composed using overlayfs, where the upper layer is automatically backed by either persistent storage or tmpfs depending on whether a data partition exists. Without a data partition, the system boots clean every time, making configuration drift structurally impossible. With a data partition, persistent operation suitable for server workloads is available.
The OS image (SquashFS) is immutable; user configuration (system.ini) is a plain text file on the FAT partition. Because these two are completely separated, OS updates never destroy configuration, and modifying settings requires no Linux expertise.
genpack-init reads system.ini and configures the system not just on the first boot, but on every boot. This ensures that changes to system.ini are always reflected on the next startup. Furthermore, in transient mode (no data partition), the overlayfs upper layer is backed by tmpfs, so runtime changes vanish on reboot and the system always starts from a clean state plus the system.ini configuration.
By separating the lower layer (build environment) from the upper layer (runtime), compilers and headers that are unnecessary at runtime are naturally excluded.
Choosing Gentoo as the base distribution provides:
The toolchain provides cross-cutting support for x86_64 / aarch64 / i686 / riscv64 architectures and BIOS / UEFI / Raspberry Pi boot methods.
genpack.json5 definitiongenpack build
system-x86_64.squashfsgenpack-install --disk=/dev/sdX — Physical diskgenpack-install --cdrom=out.iso — ISO imagevm run system-x86_64.squashfs — Virtual machineMany tools exist with similar goals, and most of them are more mature than genpack.
| Tool | Approach | Base |
|---|---|---|
| NixOS | Declarative OS configuration with hash-based reproducibility | Nix package manager |
| Yocto / OpenEmbedded | Embedded Linux image generation from source | BitBake build system |
| Buildroot | Simple embedded Linux builder | Custom Kconfig-based |
| mkosi | Official systemd image builder | Binary packages from Debian/Fedora/Arch, etc. |
| OSTree (Silverblue, etc.) | Immutable OS + atomic delta updates | Fedora/RHEL |
| Ignition (CoreOS/Flatcar) | First-boot provisioning | Container Linux |
| cloud-init | Cloud-oriented first-boot configuration | Various distributions |
genpack has neither the theoretical rigor of NixOS, nor the enterprise readiness of Yocto, nor the delta update efficiency of OSTree. Yet it occupies a distinctive position for the following reasons.
| Tool | Configuration Interface | Required Environment for Editing |
|---|---|---|
| NixOS | configuration.nix (Nix language) | Understanding of Nix + text editor |
| Ignition | JSON (machine-readable) | Typically generated by another tool |
| cloud-init | YAML | Text editor + YAML knowledge |
| Kairos / Talos | YAML API | Dedicated CLI / API |
| genpack | INI on FAT32 | Windows Notepad |
Many immutable OSes use YAML or JSON to convey configuration, but these are interfaces designed by engineers for engineers. cloud-init is powerful, but a YAML indentation mistake mercilessly rejects beginners. Ignition is not even intended to be written by hand.
genpack intentionally keeps its configuration interface far from technical sophistication. FAT32 is the one filesystem that can be mounted by any OS, and INI is the simplest structured format that can be edited in Notepad without breaking anything. This combination is a deliberate design choice to hand operational control of a highly optimized Linux system to non-technical users.
Ignition is designed to run only on the first boot, reflecting the cloud-native assumption that "provisioning happens once and that's enough." cloud-init follows essentially the same model.
genpack-init runs on every boot. Moreover, it automatically determines whether the overlayfs upper layer should use persistent storage or tmpfs based on the physical presence or absence of a data partition (or virtual disk).
Switching between these modes requires no configuration change whatsoever — it is determined entirely by the hardware setup. Simply "removing the data disk" as a physical operation is enough to turn a server into a kiosk. This is an idea not found in Ignition or cloud-init.
Gentoo is known as the distribution where "you customize everything yourself, continuously" — the quintessential mutable system. genpack uses this very Gentoo as raw material for immutable images.
Yocto also "builds from source to create immutable images," but BitBake's proprietary build system and recipe format impose a steep learning curve. genpack leverages Gentoo's existing ecosystem (Portage, ebuilds, profiles, USE flags) as-is without inventing any new package format or build system. This allows the advantages of Gentoo — source-level optimization control, precise dependency reduction through USE flags, and a vast package repository — to be enjoyed directly in the context of immutable images.
Docker's multi-stage build requires an explicit operation to "separate the build stage from the runtime stage." Nix automatically tracks runtime dependencies through closure analysis, but this relies on Nix's sophisticated machinery.
genpack's lower/upper separation is a more straightforward yet effective technique. The lower layer installs all packages (including build dependencies) and records the file lists. The upper layer then selectively copies only files belonging to runtime packages. Files from packages designated as buildtime_packages are not copied to the upper layer, preventing GCC and header files from contaminating the final image. This is a minimization mechanism unique to genpack, built on Portage's per-package file tracking capability.
cloud-init is written in Python, but extending its modules requires understanding cloud-init itself. Ignition is a monolithic Go binary that fundamentally does not anticipate extension. Many embedded init systems are shell-script-based.
genpack-init implements low-level operations (disk manipulation, coldplug, mount) in C++ and exposes them to Python via pybind11. The provisioning logic itself is written as Python scripts with a configure(ini) function, placed in /usr/lib/genpack-init/ as plugins. Adding new configuration capabilities is as simple as writing a single Python file and placing it in the designated directory — no C++ recompilation needed. This achieves both the performance of native hardware operations and the ease of writing configuration logic.
What makes genpack distinctive is not any single technical advantage, but rather the way ideas like "INI files on FAT32," "automatic operating mode selection based on hardware configuration," "repurposing the Gentoo ecosystem for immutable images," and "plugin-based init via pybind11" are combined under a coherent design philosophy aimed at "distributing highly optimized Linux images as appliances that non-technical users can operate." The essential uniqueness lies not in technical edge, but in a consistent concern for "who will actually be touching this system."