#!/usr/bin/env bash set -e # Nomarchy TTY Installer # Golden path: BTRFS + LUKS2 encryption # # This is a minimal, single-path installer designed for TTY-only environments. # For a customized installation, manually set up your disk and use the generated # flake configuration as a starting point. # Colors and styling RED='\033[0;31m' GREEN='\033[0;32m' BLUE='\033[0;34m' YELLOW='\033[1;33m' CYAN='\033[0;36m' NC='\033[0m' # No Color BOLD='\033[1m' # Installer state NOMARCHY_REPO="" TARGET_DRIVE="" USERNAME="" LUKS_PASSWORD="" USER_PASSWORD="" TIMEZONE="UTC" HARDWARE_MODULES="" NOMARCHY_HW_OPTS="" ENABLE_IMPERMANENCE="false" # ============================================================================ # UTILITY FUNCTIONS # ============================================================================ # Helper to run commands via nix run nrun() { local pkg="$1" shift nix run --extra-experimental-features "nix-command flakes" "nixpkgs#$pkg" -- "$@" } header() { clear nrun gum style \ --foreground 212 --border-foreground 212 --border double \ --align center --width 60 --margin "1 2" --padding "2 4" \ "NOMARCHY INSTALLER" "NixOS with Omarchy flavor" echo "" } section() { echo "" nrun gum style --foreground 14 --bold "━━━ $1 ━━━" echo "" } success() { nrun gum style --foreground 10 "✓ $1" } error() { nrun gum style --foreground 9 "✗ $1" } info() { nrun gum style --foreground 12 "→ $1" } # ============================================================================ # STEP 1: ENVIRONMENT CHECK # ============================================================================ check_environment() { section "Environment Check" # Check for root if [[ $EUID -ne 0 ]]; then error "This installer must be run as root (use sudo)" exit 1 fi success "Running as root" # Find Nomarchy repo if [[ -d "/etc/nomarchy" ]]; then NOMARCHY_REPO="/etc/nomarchy" elif [[ -d "$(dirname "$0")/.." ]] && [[ -f "$(dirname "$0")/../flake.nix" ]]; then NOMARCHY_REPO="$(realpath "$(dirname "$0")/..")" fi if [[ -z "$NOMARCHY_REPO" ]]; then error "Nomarchy repository not found" exit 1 fi success "Found Nomarchy at $NOMARCHY_REPO" # Check internet gum spin --spinner dot --title "Checking internet connection..." -- sleep 1 while ! ping -c 1 -W 2 1.1.1.1 &>/dev/null; do error "No internet connection" local choice choice=$(gum choose "Open Network Manager (nmtui)" "Retry" "Exit") case "$choice" in *nmtui*) nmtui ;; *Exit*) exit 1 ;; esac done success "Internet connection verified" } # ============================================================================ # STEP 2: DISK SELECTION # ============================================================================ select_disk() { section "Disk Selection" info "Available drives:" echo "" lsblk -d -n -p -o NAME,SIZE,MODEL | grep -v loop echo "" local drives drives=$(lsblk -d -n -p -o NAME,SIZE | grep -v loop) TARGET_DRIVE=$(echo "$drives" | gum choose --header "Select target drive" | awk '{print $1}') if [[ -z "$TARGET_DRIVE" ]]; then error "No drive selected" exit 1 fi echo "" gum style --foreground 9 --bold "⚠ WARNING: All data on $TARGET_DRIVE will be DESTROYED!" echo "" if ! gum confirm "Are you sure you want to use $TARGET_DRIVE?"; then error "Aborted" exit 1 fi success "Selected: $TARGET_DRIVE" } # ============================================================================ # STEP 3: LUKS PASSPHRASE # ============================================================================ get_luks_passphrase() { section "Disk Encryption" info "Your disk will be encrypted with LUKS2." info "Enter a strong passphrase (you'll need this at every boot)." echo "" local pass1 pass2 while true; do pass1=$(gum input --password --placeholder "Enter LUKS passphrase") [[ -z "$pass1" ]] && continue pass2=$(gum input --password --placeholder "Confirm passphrase") if [[ "$pass1" == "$pass2" ]]; then LUKS_PASSWORD="$pass1" break else error "Passphrases do not match. Try again." fi done success "Encryption passphrase set" } # ============================================================================ # STEP 4: USER CONFIGURATION # ============================================================================ configure_user() { section "User Configuration" USERNAME=$(nrun gum input --placeholder "Enter username (lowercase, no spaces)") if [[ -z "$USERNAME" ]] || [[ ! "$USERNAME" =~ ^[a-z][a-z0-9_-]*$ ]]; then error "Invalid username" exit 1 fi success "Username: $USERNAME" # User password (can be same as LUKS or different) info "Set a password for your user account" local pass1 pass2 while true; do pass1=$(nrun gum input --password --placeholder "Enter user password") [[ -z "$pass1" ]] && continue pass2=$(nrun gum input --password --placeholder "Confirm user password") if [[ "$pass1" == "$pass2" ]]; then USER_PASSWORD="$pass1" break else error "Passwords do not match. Try again." fi done success "User password set" } # ============================================================================ # STEP 5: TIMEZONE # ============================================================================ select_timezone() { section "Timezone" local timezones timezones=$(timedatectl list-timezones 2>/dev/null || echo "UTC") TIMEZONE=$(echo "$timezones" | gum filter --placeholder "Search timezone...") [[ -z "$TIMEZONE" ]] && TIMEZONE="UTC" success "Timezone: $TIMEZONE" } # ============================================================================ # STEP 6: HARDWARE VENDOR # ============================================================================ select_hardware() { section "Hardware Configuration" local product_name cpu_vendor product_name=$(cat /sys/class/dmi/id/product_name 2>/dev/null || echo "Unknown") cpu_vendor=$(lscpu 2>/dev/null | grep "Vendor ID" | awk '{print $3}' || echo "Unknown") info "Detected: $product_name" info "CPU: $cpu_vendor" echo "" # Set CPU-specific module if [[ "$cpu_vendor" == "AuthenticAMD" ]]; then HARDWARE_MODULES="inputs.nixos-hardware.nixosModules.common-cpu-amd" elif [[ "$cpu_vendor" == "GenuineIntel" ]]; then HARDWARE_MODULES="inputs.nixos-hardware.nixosModules.common-cpu-intel" fi local vendor vendor=$(gum choose --header "Select hardware vendor" \ "Generic (Auto-detect)" \ "Framework" \ "Dell" \ "Lenovo" \ "Apple (T2 Mac)" \ "Microsoft Surface" \ "Other...") case "$vendor" in *Framework*) local model model=$(gum choose "16-7040-amd" "13-7040-amd" "13-intel-13th-gen" "13-intel-12th-gen") HARDWARE_MODULES="$HARDWARE_MODULES\n inputs.nixos-hardware.nixosModules.framework-$model" NOMARCHY_HW_OPTS="nomarchy.hardware.isFramework = true;" ;; *Dell*) local model model=$(gum choose "xps-15-9500" "xps-15-9510" "xps-13-9310" "xps-13-9380" "precision-5530") HARDWARE_MODULES="$HARDWARE_MODULES\n inputs.nixos-hardware.nixosModules.dell-$model" [[ "$model" == *"xps"* ]] && NOMARCHY_HW_OPTS="nomarchy.hardware.isXPS = true;" ;; *Lenovo*) local model model=$(gum choose "thinkpad-x1-carbon-gen10" "thinkpad-t14-amd" "thinkpad-t480" "thinkpad-x1-extreme") HARDWARE_MODULES="$HARDWARE_MODULES\n inputs.nixos-hardware.nixosModules.lenovo-$model" ;; *Apple*) NOMARCHY_HW_OPTS="nomarchy.hardware.isT2Mac = true;" ;; *Surface*) local model model=$(gum choose "surface-pro-9" "surface-pro-8" "surface-laptop-4") HARDWARE_MODULES="$HARDWARE_MODULES\n inputs.nixos-hardware.nixosModules.microsoft-$model" ;; *Other*) info "Enter nixos-hardware module path (or leave empty):" local custom_mod custom_mod=$(gum input --placeholder "e.g., inputs.nixos-hardware.nixosModules.asus-zephyrus-ga401") [[ -n "$custom_mod" ]] && HARDWARE_MODULES="$HARDWARE_MODULES\n $custom_mod" ;; esac success "Hardware configuration set" } # ============================================================================ # STEP 7: IMPERMANENCE (OPTIONAL) # ============================================================================ configure_impermanence() { section "Impermanence (Optional)" info "Impermanence erases your root filesystem on every boot." info "Only explicitly persisted files survive reboots." info "This provides a clean, reproducible system." echo "" if gum confirm "Enable Impermanence?"; then ENABLE_IMPERMANENCE="true" success "Impermanence enabled" else info "Impermanence disabled (traditional persistent root)" fi } # ============================================================================ # STEP 8: REVIEW & CONFIRM # ============================================================================ review_configuration() { section "Review Configuration" echo " Drive: $TARGET_DRIVE (BTRFS + LUKS2)" echo " Username: $USERNAME" echo " Timezone: $TIMEZONE" echo " Impermanence: $ENABLE_IMPERMANENCE" echo "" nrun gum style --foreground 9 "This will DESTROY all data on $TARGET_DRIVE" echo "" if ! nrun gum confirm "Proceed with installation?"; then error "Aborted" exit 1 fi } # ============================================================================ # STEP 9: EXECUTION # ============================================================================ execute_installation() { section "Installing Nomarchy" # 9.1 Partition with disko info "Partitioning disk..." local disko_file tmp_disko disko_file="$NOMARCHY_REPO/installer/disko-golden.nix" tmp_disko=$(mktemp --suffix=.nix) sed "s|@TARGET_DRIVE@|${TARGET_DRIVE}|g" "$disko_file" > "$tmp_disko" # Provide the LUKS passphrase via a temporary file for disk encryption echo -n "$LUKS_PASSWORD" > /tmp/secret.key disko --mode disko "$tmp_disko" rm /tmp/secret.key success "Disk partitioned" # 9.2 Generate hardware config info "Generating hardware configuration..." mkdir -p /mnt/etc/nixos nixos-generate-config --root /mnt success "Hardware configuration generated" # 9.3 Generate flake configuration info "Creating system configuration..." generate_flake_config success "Configuration generated" # 9.4 Initialize git repo info "Initializing git repository..." ( cd /mnt/etc/nixos nrun git git init -q nrun git git add . nrun git git config user.name "Nomarchy Installer" nrun git git config user.email "installer@nomarchy" nrun git git commit -qm "Initial Nomarchy configuration" ) success "Git repository initialized" # 9.5 Handle impermanence if [[ "$ENABLE_IMPERMANENCE" == "true" ]]; then info "Setting up impermanence..." mkdir -p /mnt/persist/etc mv /mnt/etc/nixos /mnt/persist/etc/ mkdir -p /mnt/etc ln -s /persist/etc/nixos /mnt/etc/nixos success "Impermanence configured" fi # 9.6 Install info "Running nixos-install (this will take a while)..." nixos-install --flake /mnt/etc/nixos#default --no-root-passwd success "Installation complete!" } # ============================================================================ # GENERATE FLAKE CONFIGURATION # ============================================================================ generate_flake_config() { local impermanence_opt="" [[ "$ENABLE_IMPERMANENCE" == "true" ]] && impermanence_opt="nomarchy.system.impermanence.enable = true;" # flake.nix cat > /mnt/etc/nixos/flake.nix << 'FLAKE_EOF' { description = "My Nomarchy Configuration"; inputs = { nixpkgs.url = "github:nixos/nixpkgs/nixos-25.11"; nomarchy.url = "github:bemagri/nomarchy"; nixos-hardware.url = "github:NixOS/nixos-hardware/master"; home-manager = { url = "github:nix-community/home-manager/release-25.11"; inputs.nixpkgs.follows = "nixpkgs"; }; }; outputs = { self, nixpkgs, nomarchy, home-manager, nixos-hardware, ... }@inputs: { nixosConfigurations.default = nixpkgs.lib.nixosSystem { specialArgs = { inputs = nomarchy.inputs // inputs; }; modules = [ { nixpkgs.hostPlatform = "x86_64-linux"; } ./hardware-configuration.nix ./hardware-selection.nix nomarchy.nixosModules.system ./system.nix ]; }; homeConfigurations.@USERNAME@ = home-manager.lib.homeManagerConfiguration { pkgs = nixpkgs.legacyPackages.x86_64-linux; extraSpecialArgs = { inputs = nomarchy.inputs // inputs; }; modules = [ nomarchy.nixosModules.home ./home.nix { home.username = "@USERNAME@"; home.homeDirectory = "/home/@USERNAME@"; home.stateVersion = "25.11"; } ]; }; }; } FLAKE_EOF sed -i "s/@USERNAME@/$USERNAME/g" /mnt/etc/nixos/flake.nix # hardware-selection.nix cat > /mnt/etc/nixos/hardware-selection.nix << EOF { inputs, ... }: { imports = [ $HARDWARE_MODULES ]; $NOMARCHY_HW_OPTS } EOF # system.nix — curated system-level options. Uncomment what you want and # run \`sudo nixos-rebuild switch --flake /etc/nixos#default\` to apply. cat > /mnt/etc/nixos/system.nix << EOF { pkgs, ... }: { time.timeZone = "$TIMEZONE"; $impermanence_opt # System-wide packages. Most tools belong in home.nix instead — only put # things here that need to be available to all users or to root (e.g. CLI # tools used by sudo, system admin utilities). environment.systemPackages = with pkgs; [ home-manager # --- CLI tools useful as root --- # wget # curl # rsync # htop # tree # tmux ]; services.displayManager.autoLogin.enable = true; services.displayManager.autoLogin.user = "$USERNAME"; users.users."$USERNAME" = { isNormalUser = true; initialPassword = "$USER_PASSWORD"; extraGroups = [ "networkmanager" "wheel" "video" "audio" "render" ]; }; # --- Optional system services --- # Uncomment to enable. Some require extra groups on your user (see below). # Containers / virtualization # virtualisation.docker.enable = true; # adds "docker" group # virtualisation.libvirtd.enable = true; # adds "libvirtd" group — needed for virt-manager # Networking / sync # services.tailscale.enable = true; # services.syncthing = { # enable = true; # user = "$USERNAME"; # dataDir = "/home/$USERNAME"; # }; # Printing # services.printing.enable = true; # Flatpak (alternative app delivery) # services.flatpak.enable = true; # xdg.portal.enable = true; # Gaming (system-level — pairs with home.packages.steam) # programs.steam.enable = true; # programs.gamemode.enable = true; system.stateVersion = "25.11"; } EOF # home.nix — curated app menu. Uncomment what you want and run # `nomarchy-env-update` to apply. cat > /mnt/etc/nixos/home.nix << 'EOF' { pkgs, ... }: { # User-level packages (Home Manager). # # Nomarchy already ships a minimal desktop (firefox, thunar, mpv, imv, mako, # hyprlock, swww, wl-clipboard, grim, slurp, rofi-wayland, etc.). The list # below is a menu of extras — uncomment what you want and run # `nomarchy-env-update`. home.packages = with pkgs; [ # --- Enabled by default --- btop # Resource monitor (TUI) fastfetch # System info at login chromium # Secondary browser # --- Editors & dev --- # vscode # jetbrains.idea-community # neovide # zed-editor # lazygit # gh # GitHub CLI # docker-compose # postman # dbeaver-bin # --- Productivity --- # obsidian # libreoffice # thunderbird # zathura # PDF viewer # zotero # xournalpp # --- Media --- # vlc # obs-studio # gimp # inkscape # kdenlive # spotify # audacity # yt-dlp # --- Comms --- # discord # telegram-desktop # signal-desktop # slack # zoom-us # --- Security --- # keepassxc # bitwarden-desktop # _1password-gui # --- Gaming --- # steam # lutris # heroic # --- CLI / utilities --- # ripgrep # fd # bat # eza # zoxide # fzf # httpie # tldr ]; # Extra Home Manager modules go here (program configs, services, etc.). } EOF } # ============================================================================ # FINISH # ============================================================================ finish() { header nrun gum style --foreground 10 --bold --align center "INSTALLATION COMPLETE!" echo "" echo "Nomarchy has been successfully installed." echo "" echo "Next steps:" echo " 1. Remove the installation media" echo " 2. Reboot your computer" echo " 3. Log in with username: $USERNAME" echo " 4. Your configuration is at /etc/nixos/" echo "" echo "Tip: run 'nomarchy-themes-prebuild' once to pre-cache every theme" echo " variant. Theme switches after that are instant (no rebuild)." echo "" if nrun gum confirm "Reboot now?"; then reboot fi } # ============================================================================ # MAIN # ============================================================================ main() { header check_environment select_disk get_luks_passphrase configure_user select_timezone select_hardware configure_impermanence review_configuration execute_installation finish } main "$@" finish } main "$@"