A command line driven installer for guix (guix, nonguix, panther) with sane defaults
  • Rust 99.6%
  • Scheme 0.4%
Find a file
2026-06-09 19:18:52 +01:00
.claude/skills/guix-install-test feat: add shut down button to install-complete screen 2026-06-04 08:32:09 +01:00
.github/workflows feat: add graphical (iced) installer and split into a Cargo workspace 2026-06-03 17:52:43 +01:00
assets docs: add screenshot 2026-06-03 18:11:13 +01:00
crates chore: release v0.1.9 2026-06-09 19:18:52 +01:00
.envrc feat: add system.scm editor, install resume, and security hardening 2026-04-28 22:59:40 +01:00
.gitignore feat: initial commit 2026-04-24 21:01:20 +01:00
Cargo.lock chore: release v0.1.9 2026-06-09 19:18:52 +01:00
Cargo.toml chore: release v0.1.9 2026-06-09 19:18:52 +01:00
CHANGELOG.md chore: release v0.1.9 2026-06-09 19:18:52 +01:00
LICENSE chore: license 2026-05-13 16:36:45 +01:00
manifest.scm feat: add graphical (iced) installer and split into a Cargo workspace 2026-06-03 17:52:43 +01:00
README.md chore: release v0.1.5 2026-06-06 23:42:01 +01:00

guix-install

guix-install

Guix System installer. Boot a Guix ISO, run one binary, get a working system — libre Guix, Nonguix, PantherX, or an enterprise config from a server.

Why

The existing Python installer (px-install) had gotten hard to live with — partitioning tangled into config generation, no resume on failure, four modes bolted on with conditionals. Rewrote it in Rust with the install mode as the central axis.

Status

Pre-1.0. Runs end-to-end on the machines I've tested. Read what it's about to do before you let it touch your disk. --dry-run prints the generated system.scm (+ channels.scm) without partitioning anything.

Prebuilt static x86_64 binaries (musl, no runtime deps) are attached to each GitHub release so you can use this on a plain Guix ISO without building anything.

There's now a graphical frontend (guix-install-gui) — a second frontend over the exact same install logic, keyboard-first, built on iced. It covers the same modes, steps, and phases as the CLI.

Modes

Channel Kernel Notes
guix linux-libre Hardware preflight warns about Wi-Fi/GPU/Ethernet needing non-free firmware.
nonguix linux + microcode substitutes.nonguix.org key compiled in.
panther (default) linux + microcode Pulls nonguix transitively. Inherits %os-base from (px system os). substitutes.guix.gofranz.com key compiled in.
enterprise from remote Fetches a tarball over HTTPS by config ID. Skips locale/timezone/hostname/users/desktop.

Build

The project is a Cargo workspace: guix-install-core (the library — all the install logic) plus two binaries, guix-install (CLI) and guix-install-gui (GUI). manifest.scm carries everything both need (toolchain, CC/OPENSSL_DIR exports, and the GUI's Wayland/render libs), so the workspace builds in one shot:

guix shell -m manifest.scm -- cargo build --release

Build a single binary with -p. The CLI never pulls in iced, so a CLI-only build (the static-release path) needs nothing from the GUI side:

guix shell -m manifest.scm -- cargo build --release -p guix-install        # CLI
guix shell -m manifest.scm -- cargo build --release -p guix-install-gui    # GUI

Usage

On the PantherX ISO the binary is pre-installed — just run:

guix-install

Latest PantherX ISO (2.2 GB, BIOS + UEFI, x86_64):

https://temp.pantherx.org/1xnvrrk5n25llks8pjx64f2kb3nfasn4-image.iso

Hash (Guix nix-base32, SHA-256): 0vvnfzw6y52z1qd2k60jcxw9r5y9mfvp9s1p4nj53ii4l3gyhbmg

On a plain Guix ISO (or anywhere else), grab the static musl binary from a release:

curl -L -o guix-install \
  https://github.com/franzos/guix-install/releases/latest/download/guix-install-x86_64-linux-musl
chmod +x guix-install
./guix-install

Walks through Keyboard → Network → Mode → Locale → Timezone → Hostname → Disk → Encryption → Users → Desktop → Summary. Escape goes back a step. The Network step (Ethernet/Wi-Fi via connmanctl) auto-skips once a substitute server is reachable. Enterprise mode collapses the middle to just Disk + Encryption.

Installation summary screen

Dry run (no disk touched):

guix-install --dry-run --mode nonguix --hostname mybox --disk /dev/sda \
             --filesystem btrfs --encrypt --desktop gnome

Common flags:

Flag Default
--mode panther guix, nonguix, panther, enterprise
--hostname <mode>-<6 random>
--timezone Europe/Berlin
--locale en_US.utf8
--disk /dev/sda
--filesystem ext4 or btrfs
--encrypt off LUKS on /
--username panther login name for the primary user
--keyboard none layout, e.g. us, de
--desktop none gnome, kde, xfce, mate, sway, i3, lxqt
--swap 4096 MB swap file size
--ssh-key none dropped into the user's authorized_keys
--config <ID> implies --mode enterprise
--config-url https://temp.pantherx.org/install enterprise base URL
--dry-run off print scheme, do nothing

Subcommands:

guix-install list-disks    # lsblk-style summary
guix-install wifi          # connmanctl WiFi setup

Graphical installer

guix-install-gui is the same installer with an iced frontend instead of the REPL — same modes, same steps, same 8-phase pipeline, same generated system.scm. It's keyboard-first (Tab/arrows/Enter/Esc; the pointer is optional), with a left step rail and a live progress screen for the install phases. The first step picks a keyboard layout and applies it live (by relaunching the compositor), so the rest of the interview is typed on the right keymap.

Graphical installer — Install progress screen

It runs as an ordinary window in any Wayland/X session, so you can build and try it on a normal desktop:

guix shell -m manifest.scm -- cargo run -p guix-install-gui -- --dry-run   # interview only, nothing touched
guix shell -m manifest.scm -- cargo run -p guix-install-gui                # real install (needs root + a target disk)

In the bare install environment there's no desktop, so it runs under cage (a single-window Wayland kiosk compositor) on the TTY. Baking it into the PantherX ISO and wiring that launch path is still pending — for now the CLI is what ships on the ISO.

Phases

8 phases, state persisted to /tmp/.guix-install-state after each:

  1. Partition (parted, BIOS/EFI auto-detected from /sys/firmware/efi)
  2. Format (ext4/btrfs, optional LUKS)
  3. Mount under /mnt
  4. Swap file
  5. Generate system.scm + channels.scm (or fetch enterprise tarball)
  6. Authorize substitute servers
  7. guix pull (skipped for plain Guix)
  8. guix system init, set user password

Re-running picks up at the failed phase. Change disk/mode/firmware and state is discarded.

Notes

  • Passwords never land in system.scm. SHA-512-crypted in-process, atomically written to /mnt/etc/shadow (sibling-write + fsync + rename + dir fsync). Plaintext held in Zeroizing<String>. No chroot/chpasswd.
  • Substitute keys compiled in via include_str!.
  • Enterprise tarballs streamed through ureq → flate2 → tar. No intermediate file.
  • Partition naming handles NVMe/MMC (/dev/nvme0n1p1) vs SATA (/dev/sda1) via disk::partition_path.
  • LUKS passphrases, like passwords, stay in Zeroizing<String> and reach cryptsetup over stdin (--key-file -), never argv, disk, or saved state.
  • guix pull / guix system init run through libguix for structured progress (substitute downloads, per-derivation builds) — the same in both frontends. The other shell-outs (partition/format/mount) stay direct.
  • UI is a trait (UserInterface), and the project is a workspace: guix-install-core holds all the logic, with two thin frontends — guix-install (CLI, dialoguer) and guix-install-gui (iced) — plugging in without touching step logic. The CLI build never compiles iced.

Development

Three layers of testing, in order of how often I run them.

1. Unit + golden tests. Pure-Rust assertions on the action sequences and the rendered scheme. Covers the 2×2×2×4 matrix (firmware × encryption × filesystem × mode). Fast.

guix shell rust rust:cargo gcc-toolchain -- sh -c "CC=gcc cargo test"

2. Scheme validation. Pipes each generated system.scm through guix time-machine ... system build -d to confirm Guix actually accepts it. #[ignore]d by default — first run is slow.

guix shell guix -- cargo test --test scheme_validate -- --ignored

3. Guided VM install (Claude Code). The /guix-install-test skill drives a QEMU VM end-to-end: builds the binary, boots a Guix ISO, copies the binary in over SSH, and walks through real install scenarios (mode × filesystem × encryption × firmware) with reboots between cycles. Use it when changing partition / format / mount / cow-store / pull / system-init paths.

/guix-install-test

Format:

podman run --rm -v $PWD:/work -w /work rust:latest \
  sh -c "rustup component add rustfmt && cargo fmt"