{"id":50672137,"url":"https://github.com/franzos/guix-install","last_synced_at":"2026-06-08T12:04:37.074Z","repository":{"id":354813877,"uuid":"1225042264","full_name":"franzos/guix-install","owner":"franzos","description":"A command line driven installer for guix (guix, nonguix, panther) with sane defaults ","archived":false,"fork":false,"pushed_at":"2026-06-03T20:32:13.000Z","size":1194,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"master","last_synced_at":"2026-06-03T22:13:04.852Z","etag":null,"topics":["guix","guix-configuration","installation","linux","nonguix","panther"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/franzos.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-29T22:19:46.000Z","updated_at":"2026-06-03T20:32:16.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/franzos/guix-install","commit_stats":null,"previous_names":["franzos/guix-install"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/franzos/guix-install","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/franzos%2Fguix-install","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/franzos%2Fguix-install/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/franzos%2Fguix-install/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/franzos%2Fguix-install/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/franzos","download_url":"https://codeload.github.com/franzos/guix-install/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/franzos%2Fguix-install/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34061132,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-08T02:00:07.615Z","response_time":111,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["guix","guix-configuration","installation","linux","nonguix","panther"],"created_at":"2026-06-08T12:04:35.431Z","updated_at":"2026-06-08T12:04:37.065Z","avatar_url":"https://github.com/franzos.png","language":"Rust","funding_links":[],"categories":["Tools"],"sub_categories":[],"readme":"# guix-install\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"assets/logo.svg\" alt=\"guix-install\" width=\"480\"\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n  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.\n\u003c/p\u003e\n\n## Why\n\nThe existing Python installer ([`px-install`](https://github.com/franzos/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.\n\n## Status\n\nPre-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.\n\nPrebuilt **static x86_64 binaries** (musl, no runtime deps) are attached to each [GitHub release](https://github.com/franzos/guix-install/releases) so you can use this on a plain Guix ISO without building anything.\n\nThere's now a **graphical frontend** (`guix-install-gui`) — a second frontend over the exact same install logic, keyboard-first, built on [iced](https://iced.rs). It covers the same modes, steps, and phases as the CLI.\n\n## Modes\n\n| Channel | Kernel | Notes |\n|---------|--------|-------|\n| [`guix`](https://codeberg.org/guix/guix) | linux-libre | Hardware preflight warns about Wi-Fi/GPU/Ethernet needing non-free firmware. |\n| [`nonguix`](https://gitlab.com/nonguix/nonguix) | linux + microcode | `substitutes.nonguix.org` key compiled in. |\n| [`panther`](https://codeberg.org/gofranz/panther) *(default)* | linux + microcode | Pulls nonguix transitively. Inherits `%os-base` from `(px system os)`. `substitutes.guix.gofranz.com` key compiled in. |\n| `enterprise` | from remote | Fetches a tarball over HTTPS by config ID. Skips locale/timezone/hostname/users/desktop. |\n\n## Build\n\nThe 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:\n\n```bash\nguix shell -m manifest.scm -- cargo build --release\n```\n\nBuild 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:\n\n```bash\nguix shell -m manifest.scm -- cargo build --release -p guix-install        # CLI\nguix shell -m manifest.scm -- cargo build --release -p guix-install-gui    # GUI\n```\n\n## Usage\n\nOn the **PantherX ISO** the binary is pre-installed — just run:\n\n```bash\nguix-install\n```\n\nLatest PantherX ISO (2.2 GB, BIOS + UEFI, x86_64):\n\n```\nhttps://temp.pantherx.org/1xnvrrk5n25llks8pjx64f2kb3nfasn4-image.iso\n```\n\nHash (Guix nix-base32, SHA-256): `0vvnfzw6y52z1qd2k60jcxw9r5y9mfvp9s1p4nj53ii4l3gyhbmg`\n\nOn a **plain Guix ISO** (or anywhere else), grab the static musl binary from a release:\n\n```bash\ncurl -L -o guix-install \\\n  https://github.com/franzos/guix-install/releases/latest/download/guix-install-x86_64-linux-musl\nchmod +x guix-install\n./guix-install\n```\n\nWalks 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.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"assets/installer-summary.png\" alt=\"Installation summary screen\" width=\"720\"\u003e\n\u003c/p\u003e\n\nDry run (no disk touched):\n\n```bash\nguix-install --dry-run --mode nonguix --hostname mybox --disk /dev/sda \\\n             --filesystem btrfs --encrypt --desktop gnome\n```\n\nCommon flags:\n\n| Flag | Default | |\n|------|---------|---|\n| `--mode` | `panther` | `guix`, `nonguix`, `panther`, `enterprise` |\n| `--hostname` | `\u003cmode\u003e-\u003c6 random\u003e` | |\n| `--timezone` | `Europe/Berlin` | |\n| `--locale` | `en_US.utf8` | |\n| `--disk` | `/dev/sda` | |\n| `--filesystem` | `ext4` | or `btrfs` |\n| `--encrypt` | off | LUKS on `/` |\n| `--username` | `panther` | login name for the primary user |\n| `--keyboard` | none | layout, e.g. `us`, `de` |\n| `--desktop` | none | `gnome`, `kde`, `xfce`, `mate`, `sway`, `i3`, `lxqt` |\n| `--swap` | `4096` MB | swap file size |\n| `--ssh-key` | none | dropped into the user's `authorized_keys` |\n| `--config \u003cID\u003e` | | implies `--mode enterprise` |\n| `--config-url` | `https://temp.pantherx.org/install` | enterprise base URL |\n| `--dry-run` | off | print scheme, do nothing |\n\nSubcommands:\n\n```bash\nguix-install list-disks    # lsblk-style summary\nguix-install wifi          # connmanctl WiFi setup\n```\n\n## Graphical installer\n\n`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.\n\n\u003cp align=\"center\"\u003e\n  \u003cimg src=\"assets/installer-gui.png\" alt=\"Graphical installer — Install progress screen\" width=\"720\"\u003e\n\u003c/p\u003e\n\nIt runs as an ordinary window in any Wayland/X session, so you can build and try it on a normal desktop:\n\n```bash\nguix shell -m manifest.scm -- cargo run -p guix-install-gui -- --dry-run   # interview only, nothing touched\nguix shell -m manifest.scm -- cargo run -p guix-install-gui                # real install (needs root + a target disk)\n```\n\nIn the bare install environment there's no desktop, so it runs under [`cage`](https://github.com/cage-kiosk/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.\n\n## Phases\n\n8 phases, state persisted to `/tmp/.guix-install-state` after each:\n\n1. Partition (parted, BIOS/EFI auto-detected from `/sys/firmware/efi`)\n2. Format (ext4/btrfs, optional LUKS)\n3. Mount under `/mnt`\n4. Swap file\n5. Generate `system.scm` + `channels.scm` (or fetch enterprise tarball)\n6. Authorize substitute servers\n7. `guix pull` (skipped for plain Guix)\n8. `guix system init`, set user password\n\nRe-running picks up at the failed phase. Change disk/mode/firmware and state is discarded.\n\n## Notes\n\n- **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\u003cString\u003e`. No `chroot`/`chpasswd`.\n- **Substitute keys compiled in** via `include_str!`.\n- **Enterprise tarballs streamed** through `ureq → flate2 → tar`. No intermediate file.\n- **Partition naming** handles NVMe/MMC (`/dev/nvme0n1p1`) vs SATA (`/dev/sda1`) via `disk::partition_path`.\n- **LUKS passphrases**, like passwords, stay in `Zeroizing\u003cString\u003e` and reach `cryptsetup` over stdin (`--key-file -`), never argv, disk, or saved state.\n- **`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.\n- **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.\n\n## Development\n\nThree layers of testing, in order of how often I run them.\n\n**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.\n\n```bash\nguix shell rust rust:cargo gcc-toolchain -- sh -c \"CC=gcc cargo test\"\n```\n\n**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.\n\n```bash\nguix shell guix -- cargo test --test scheme_validate -- --ignored\n```\n\n**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.\n\n```\n/guix-install-test\n```\n\nFormat:\n\n```bash\npodman run --rm -v $PWD:/work -w /work rust:latest \\\n  sh -c \"rustup component add rustfmt \u0026\u0026 cargo fmt\"\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffranzos%2Fguix-install","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ffranzos%2Fguix-install","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ffranzos%2Fguix-install/lists"}