Files
nixos/docs/superpowers/specs/2026-07-27-mibook-boot-desktop-choice-design.md
T
finn.markwitz ae6c81bf54 fix(mibook): boot-menu terminal choice via specialisation
The previous startOnBoot approach booted mibook headless by default and
locked the machine out: it is WiFi-only with credentials in KWallet, so
with no desktop session NetworkManager never joins the network (no SSH),
and boot stalled on NetworkManager-wait-online with the tty1 prompt
buried under service logs.

Replace it with a NixOS specialisation that adds a separate 'terminal'
GRUB entry:
- default entry boots KDE as before (identical to baseline);
- 'terminal' entry boots multi-user.target with autologin for finn and a
  'desktop' command to start SDDM on demand.
Also disable NetworkManager-wait-online so boot never stalls on the
network. Revert the kde-desktop startOnBoot option.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CfozKLQdUh5TzqyjSigLUx
2026-07-27 10:52:18 +02:00

5.0 KiB

mibook: choose terminal-only vs desktop at boot

Goal

Let mibook offer a choice, each time it boots, between the normal KDE desktop and a terminal-only ("server") mode with no graphical session — decided at boot, without rebuilding the system.

Background: why the first attempt failed

The first implementation booted mibook to a text console by default (systemd.defaultUnit = "multi-user.target", display manager not started) and provided a desktop command to start KDE on demand. On real hardware this locked the machine out:

  • No SSH. mibook is WiFi-only and its WiFi credentials are stored per-user in KWallet ("agent-owned"). NetworkManager only receives the password once a desktop session is running, so a headless boot never joins the network and the machine has no IP — nothing to SSH into.
  • No usable console. The boot appeared to "hang" with no login prompt: NetworkManager-wait-online stalled waiting for a network that never came up, and the getty login prompt on tty1 was buried under later service messages.

Conclusion: a headless WiFi laptop cannot be reached remotely, and the plain console was hard to use. The design must (a) keep the desktop as the reliable default, (b) make the terminal path a deliberate, self-sufficient choice, and (c) not depend on the network being up.

Behavior

  • The default GRUB entry boots straight into KDE — unchanged from the known-working baseline.
  • A separate GRUB entry, mibook (terminal) (a NixOS specialisation), boots to a text console with autologin for finn. From there the user can work in the shell or run desktop to bring KDE up (via SDDM).
  • The choice is made in the GRUB menu at boot — matching the original request to "decide each time I boot."
  • Booting never stalls on the network.

Known limitation (documented, not fixed in config)

In terminal mode WiFi will not connect on its own, because the password is stored per-user in KWallet. To reach mibook over SSH from terminal mode, the user must first save the WiFi as a system connection in KDE: network settings → the WiFi network → "All users may connect to this network". Until then, terminal mode is local-console-only. This is a one-time manual step outside the scope of the Nix config.

Implementation

machines/mibook/configuration.nix

  • Add a NixOS specialisation specialisation.terminal.configuration:
    • system.nixos.tags = [ "terminal" ]; — labels the generated boot entry.
    • systemd.defaultUnit = lib.mkForce "multi-user.target"; — boots to the text console. graphical.target is what pulls in the display manager (via its embedded Wants=display-manager.service), so defaulting to multi-user.target leaves SDDM installed but not started at boot.
    • services.getty.autologinUser = "finn"; — guarantees a usable shell on the console instead of a login prompt that can scroll off screen.
    • A desktop command via pkgs.writeShellScriptBin "desktop" "exec sudo systemctl start display-manager.service" in environment.systemPackages, to start KDE on demand.
  • Add systemd.services.NetworkManager-wait-online.enable = false; (applies to both the default and terminal boots) so boot never stalls waiting for the network.

Reverted from the first attempt

  • modules/environments/kde-desktop/default.nix — remove the startOnBoot option and its mkMerge/mkIf machinery; back to the original profile that simply enables SDDM + Plasma 6.
  • machines/mibook/environments.nix — remove kde-desktop.startOnBoot = false; (back to just kde-desktop.enable = true;).

Why a specialisation

A specialisation generates a second boot-menu entry automatically from a modified copy of the configuration. It is the idiomatic NixOS mechanism for a boot-time choice and avoids fragile hand-written GRUB extraEntries that would need to track kernel/initrd paths across generations. The default entry remains byte-for-byte the working desktop configuration.

Testing / verification

  • nix build '.#nixosConfigurations.mibook.config.system.build.toplevel' builds both nixos-system-mibook and nixos-system-mibook-terminal.
  • Verified on the built closures:
    • Parent default.targetgraphical.target; no console autologin (identical to the pre-change baseline).
    • Specialisation default.targetmulti-user.target; tty1 getty wrapper contains --autologin finn; desktop present in the system profile.
    • NetworkManager-wait-online disabled in both.
  • Post-switch manual check on mibook: default GRUB entry boots to KDE; the terminal entry boots to an autologged-in console; running desktop there starts SDDM and a working Plasma session.

Trade-offs

  • Autologin on the terminal console means physical access grants a shell without a password. Acceptable for a personal laptop the user controls; the desktop (default) boot is unaffected.
  • desktop relies on sudo; the user has sudo access, so no extra config is required.