
- Add modular flake-based NixOS configuration - Implement GitOps foundation with CI/CD pipeline - Create comprehensive documentation and branching strategy - Add modular desktop environments (GNOME, Cosmic, Sway) - Configure virtualization stack (Incus, Libvirt, Podman) - Set up development tools and hardware-specific modules - Establish user configuration with literate programming support This commit represents the completion of Phase 1: Flakes Migration with modular configuration, virtualization, and GitOps foundation.
19 KiB
AI Agent Instructions: NixOS Flakes Migration for CongenitalOptimist
Overview
This document provides step-by-step instructions for AI agents to help migrate the CongenitalOptimist machine from traditional NixOS configuration to flakes-based configuration and upgrade to NixOS 25.05. The system already has excellent modular structure that we'll preserve and enhance.
Current System Information
- Hostname: work (consider renaming to congenital-optimist)
- Current Version: NixOS 23.11
- Target Version: NixOS 25.05
- Architecture: x86_64-linux
- Storage: ZFS (zpool for system, stuffpool for data)
- Hardware: AMD CPU/GPU
- User: geir
- Dotfiles Approach: Literate programming with Emacs org-mode (no Home Manager)
Current Module Structure
Home-lab/
├── machines/
│ ├── congenital-optimist/
│ │ ├── configuration.nix (main system config)
│ │ ├── hardware-configuration.nix
│ │ └── About.org
│ └── modules/
│ ├── common/
│ │ ├── base.nix (modern CLI tools & aliases)
│ │ └── tty.nix (console styling with Joker theme)
│ └── virtualization/
│ ├── podman.nix
│ ├── libvirt.nix
│ └── incus.nix
└── Users/
└── geir/
└── user.nix (has typo: progtams → programs)
Prerequisites Check
Before starting, verify:
- Current system is bootable and stable
- ZFS pools are healthy (
zpool status
) - All referenced modules exist and are working
- User has sudo/root access
- Fix typo in
Users/geir/user.nix
first
Step 1: Fix Existing Configuration Issues
Fix typo in user.nix
Edit Home-lab/Users/geir/user.nix
and change:
progtams.zsh.enableCompletion = true;
to:
programs.zsh.enableCompletion = true;
Step 2: Create Root Flake Structure
Create Home-lab/flake.nix
:
{
description = "CongenitalOptimist Home Lab NixOS Configuration";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-25.05";
nixpkgs-unstable.url = "github:NixOS/nixpkgs/nixos-unstable";
};
outputs = { self, nixpkgs, nixpkgs-unstable, ... }@inputs: {
nixosConfigurations = {
congenital-optimist = nixpkgs.lib.nixosSystem {
system = "x86_64-linux";
specialArgs = {
inherit inputs;
unstable = import nixpkgs-unstable {
system = "x86_64-linux";
config.allowUnfree = true;
};
};
modules = [
./machines/congenital-optimist
];
};
};
};
}
Step 3: Create Target Directory Structure
Execute these commands in the Home-lab directory:
mkdir -p machines/congenital-optimist
mkdir -p modules/{common,desktop,development,virtualization,users}
mkdir -p users/geir/dotfiles/{emacs,shell,editors}
mkdir -p overlays
mkdir -p packages
Step 4: Convert Main Configuration
Create machines/CongenitalOptimist/default.nix
by adapting the current configuration.nix
:
Key changes needed:
- Change function signature from
{pkgs, ...}:
to{ config, pkgs, inputs, unstable, ... }:
- Keep
system.stateVersion
as "23.11" (maintains compatibility with existing data) - Fix nerd-fonts syntax (changed in 25.05)
- Remove the experimental-features setting (handled by flake)
- Update module import paths for new structure
- Consolidate user package management
Nerd Fonts Fix for 25.05
Replace this section in fonts.packages:
# Old format (will break in 25.05)
nerd-fonts.meslo-lg
nerd-fonts.jetbrains-mono
nerd-fonts.fira-code
nerd-fonts.droid-sans-mono
nerd-fonts.zed-mono
nerd-fonts.iosevka
nerd-fonts.iosevka-term
nerd-fonts.hack
With:
# New format for 25.05
(nerdfonts.override {
fonts = [
"Meslo"
"JetBrainsMono"
"FiraCode"
"DroidSansMono"
"Hack"
"Iosevka"
"IosevkaTerm"
];
})
Step 5: Migrate Existing Modules
Copy existing modules to new structure:
# Copy common modules
cp Home-lab/Machines/Modules/common/base.nix modules/common/
cp Home-lab/Machines/Modules/common/tty.nix modules/common/
# Copy virtualization modules
cp Home-lab/Machines/Modules/virtualization/*.nix modules/virtualization/
Create additional common modules:
modules/common/nix.nix
:
{ config, pkgs, ... }: {
# Enable flakes system-wide
nix.settings.experimental-features = [ "nix-command" "flakes" ];
# Optimize nix settings
nix.settings = {
auto-optimise-store = true;
substituters = [
"https://cache.nixos.org/"
];
trusted-public-keys = [
"cache.nixos.org-1:6NCHdD59X431o0gWypbMrAURkbJ16ZPMQFGspcDShjY="
];
};
}
Step 6: Consolidate User Configuration
Create modules/users/geir.nix
by merging the existing user config:
{ config, pkgs, ... }: {
users.users.geir = {
isNormalUser = true;
extraGroups = [ "networkmanager" "wheel" "libvirtd" "podman" "incus-admin" ];
shell = pkgs.zsh;
packages = with pkgs; [
# Browsers
chromium
vivaldi
vivaldi-ffmpeg-codecs
nyxt
firefox
# Shell & development tools
starship
fastfetch
hyfetch
nerdfetch
nix-direnv
gh
github-copilot-cli
# Media & graphics
gimp
obs-studio
vesktop
koodo-reader
# System tools
ncpamixer
virt-manager
pavucontrol
gnome-tweaks
beauty-line-icon-theme
# Terminal multiplexer and fun
zellij
neo-cowsay
fortune
clolcat
# Emacs integration
emacsPackages.vterm
];
};
# System-wide ZSH configuration
programs.zsh = {
enable = true;
syntaxHighlighting.enable = true;
enableCompletion = true;
autosuggestions = {
enable = true;
historySearch = true;
};
history = {
enable = true;
shareHistory = true;
saveOnExit = true;
};
};
environment.systemPackages = with pkgs; [
zsh
zsh-completions
nix-zsh-completions
zsh-autocomplete
zsh-autosuggestions
zsh-syntax-highlighting
];
}
Step 7: Create Desktop Environment Modules
modules/desktop/gnome.nix
:
{ config, pkgs, ... }: {
services.xserver = {
enable = true;
desktopManager.gnome.enable = true;
xkb.layout = "no";
};
# XDG portal configuration
xdg.portal = {
enable = true;
extraPortals = [ pkgs.xdg-desktop-portal-gtk ];
};
}
modules/desktop/cosmic.nix
:
{ config, pkgs, ... }: {
services.desktopManager.cosmic.enable = true;
services.displayManager.cosmic-greeter.enable = true;
services.desktopManager.cosmic.xwayland.enable = true;
}
modules/desktop/sway.nix
:
{ config, pkgs, ... }: {
programs.sway = {
enable = true;
wrapperFeatures.gtk = true;
};
services.dbus.enable = true;
xdg.portal = {
enable = true;
wlr.enable = true;
extraPortals = [ pkgs.xdg-desktop-portal-gtk ];
};
environment.systemPackages = with pkgs; [
swaylock
swayidle
swaybg
waybar
fuzzel
gammastep
mako
flameshot
];
}
Step 8: Set Up Per-User Literate Dotfiles
Create users/geir/dotfiles/README.org
:
#+TITLE: CongenitalOptimist Dotfiles Configuration
#+DESCRIPTION: Literate programming approach to dotfiles using Emacs org-mode
#+PROPERTY: header-args :tangle yes
#+STARTUP: overview
* Introduction
This file contains all dotfiles configuration using literate programming.
Each configuration block can be tangled to its respective file using C-c C-v t.
The approach allows for:
- Self-documenting configuration with rationale
- Easy sharing and explanation of setup decisions
- Version control of configuration with full context
- Modular organization of different tool configurations
* Shell Configuration
** Zsh Configuration
#+BEGIN_SRC sh :tangle ~/.zshrc
# Generated from dotfiles/README.org - CongenitalOptimist configuration
export EDITOR="emacs"
export BROWSER="firefox"
export SHELL="/run/current-system/sw/bin/zsh"
# Enable starship prompt (configured in NixOS)
eval "$(starship init zsh)"
# Enable zoxide for smart cd
eval "$(zoxide init zsh)"
# Custom aliases (complementing those in base.nix)
alias gc='git commit'
alias gp='git push'
alias gs='git status'
alias nrs='sudo nixos-rebuild switch --flake .'
alias nrt='sudo nixos-rebuild test --flake .'
alias reload='source ~/.zshrc'
# CongenitalOptimist specific shortcuts
alias lab='cd ~/Home-lab'
alias tangle='cd ~/Home-lab/users/geir/dotfiles && emacs --batch -l org --eval "(org-babel-tangle-file \"README.org\")"'
alias dotfiles='cd ~/Home-lab/users/geir/dotfiles'
#+END_SRC
** Starship Configuration
#+BEGIN_SRC toml :tangle ~/.config/starship.toml
# Starship prompt configuration for CongenitalOptimist
format = """
$username\
$hostname\
$directory\
$git_branch\
$git_state\
$git_status\
$cmd_duration\
$line_break\
$character"""
[character]
success_symbol = "[➜](bold green)"
error_symbol = "[➜](bold red)"
[directory]
truncation_length = 3
fish_style_pwd_dir_length = 1
[git_branch]
symbol = "🌱 "
[hostname]
ssh_only = false
format = "[@$hostname](bold blue) "
[username]
show_always = true
format = "[$user](bold yellow)"
#+END_SRC
* Editor Configuration
** Emacs Configuration
#+BEGIN_SRC emacs-lisp :tangle ~/.emacs.d/init.el
;; Generated from dotfiles/README.org - CongenitalOptimist
(setq inhibit-startup-message t)
(setq ring-bell-function 'ignore)
;; Enable line numbers
(global-display-line-numbers-mode 1)
;; Enable org-babel for literate programming
(org-babel-do-load-languages
'org-babel-load-languages
'((emacs-lisp . t)
(shell . t)
(python . t)
(nix . t)))
;; Auto-tangle on save for literate config files
(defun auto-tangle-config-files ()
"Auto tangle config files when saving."
(when (string-match-p "users/.*/dotfiles.*\\.org$" (buffer-file-name))
(org-babel-tangle)))
(add-hook 'after-save-hook 'auto-tangle-config-files)
;; Better defaults
(setq-default indent-tabs-mode nil)
(setq-default tab-width 2)
(show-paren-mode 1)
(electric-pair-mode 1)
;; CongenitalOptimist theme setup
(when (display-graphic-p)
(load-theme 'deeper-blue t))
#+END_SRC
* Development Tools
** Git Configuration
#+BEGIN_SRC conf :tangle ~/.gitconfig
[user]
name = geir
email = geir@congenital-optimist.local
[init]
defaultBranch = main
[core]
editor = emacs
pager = bat
[pull]
rebase = false
[alias]
st = status
co = checkout
br = branch
unstage = reset HEAD --
last = log -1 HEAD
visual = !gitk
#+END_SRC
* Home Lab Specific Configuration
** NixOS Rebuild Aliases
These aliases make working with the flake-based configuration easier:
#+BEGIN_SRC sh :tangle ~/.config/shell/nixos-aliases
# NixOS CongenitalOptimist specific aliases
alias nix-build='cd ~/Home-lab && nix build .#nixosConfigurations.congenital-optimist.config.system.build.toplevel'
alias nix-check='cd ~/Home-lab && nix flake check'
alias nix-update='cd ~/Home-lab && nix flake update'
alias nix-clean='sudo nix-collect-garbage -d'
alias edit-dotfiles='cd ~/Home-lab/users/geir/dotfiles && emacs README.org'
#+END_SRC
Step 9: Update Main Configuration Import Structure
Create the main machine configuration in machines/CongenitalOptimist/default.nix
:
{ config, pkgs, inputs, unstable, ... }: {
imports = [
./hardware-configuration.nix
../../modules/common/base.nix
../../modules/common/tty.nix
../../modules/common/nix.nix
../../modules/virtualization/podman.nix
../../modules/virtualization/libvirt.nix
../../modules/virtualization/incus.nix
../../modules/desktop/gnome.nix
../../modules/desktop/cosmic.nix
../../modules/desktop/sway.nix
../../modules/users/geir.nix
];
# Boot configuration
boot.loader.grub = {
enable = true;
zfsSupport = true;
efiSupport = true;
efiInstallAsRemovable = true;
mirroredBoots = [
{
devices = ["nodev"];
path = "/boot";
}
];
};
zramSwap = {
enable = true;
algorithm = "zstd";
};
# Hardware
services.fwupd.enable = true;
hardware.enableRedistributableFirmware = true;
hardware.amdgpu.initrd.enable = true;
hardware.bluetooth.enable = true;
hardware.bluetooth.powerOnBoot = true;
# System settings
nixpkgs.config.allowUnfree = true;
networking.nftables.enable = true;
networking.hostName = "work"; # TODO: consider changing to "congenital-optimist"
services.tailscale.enable = true;
networking.networkmanager.enable = true;
networking.hostId = "8425e349";
time.timeZone = "Europe/Oslo";
i18n.defaultLocale = "en_US.UTF-8";
# Services
services.flatpak.enable = true;
services.emacs.enable = true;
services.pipewire = {
enable = true;
alsa.enable = true;
pulse.enable = true;
};
programs.steam.enable = true;
# Fonts (updated for 25.05)
fonts.packages = with pkgs; [
noto-fonts
noto-fonts-cjk-sans
noto-fonts-emoji
liberation_ttf
dina-font
proggyfonts
mona-sans
hubot-sans
inter-nerdfont
(nerdfonts.override {
fonts = [
"Meslo"
"JetBrainsMono"
"FiraCode"
"DroidSansMono"
"Hack"
"Iosevka"
"IosevkaTerm"
];
})
];
# System packages
environment.systemPackages = with pkgs; [
# Terminal applications
kitty
terminator
rio
dbus
greetd.tuigreet
wayland
xdg-utils
# System monitoring
glances
inxi
htop
bottom
wget
curl
git
mc
systemctl-tui
# Development tools
guile
rustup
nixd
zls
alejandra
python3Packages.python-lsp-server
gopls
luajitPackages.lua-lsp
nodePackages.bash-language-server
vimPlugins.cmp-nvim-lsp
ccls
gdb
marksman
# Editors
zed-editor
neovim
emacs
vscode
vscodium-fhs
];
# Network and security
services.openssh.enable = true;
services.zfs.autoScrub.enable = true;
services.zfs.trim.enable = true;
networking.firewall.allowedTCPPorts = [ 22 ];
networking.firewall.allowedUDPPorts = [ 22 ];
networking.firewall.enable = true;
system.copySystemConfiguration = true;
system.stateVersion = "23.11"; # DO NOT CHANGE - maintains data compatibility
}
Step 10: Copy Hardware Configuration
Copy the existing hardware configuration:
cp Home-lab/Machines/CongenitalOptimist/hardware-configuration.nix machines/CongenitalOptimist/
Step 11: Test Configuration
Before applying changes:
- Test flake evaluation:
cd Home-lab
nix flake check
- Build configuration without switching:
sudo nixos-rebuild build --flake .#congenital-optimist
- If successful, test the configuration:
sudo nixos-rebuild test --flake .#congenital-optimist
- If everything works, switch permanently:
sudo nixos-rebuild switch --flake .#congenital-optimist
Step 12: Set Up Per-User Literate Dotfiles Workflow
- Create your main org-mode configuration file:
cd users/geir/dotfiles
emacs README.org
- Use org-babel to tangle your configurations:
# In Emacs, use C-c C-v t to tangle all code blocks
# Or from command line:
cd users/geir/dotfiles
emacs --batch -l org --eval "(org-babel-tangle-file \"README.org\")"
- The provided Emacs config includes auto-tangle on save for any user's dotfiles
- Test that dotfiles are generated correctly in the user's home directory
- For additional users, create similar structure under
users/<username>/dotfiles/
Step 13: Lock and Commit
- Generate flake.lock:
nix flake lock
- Commit changes:
git add .
git commit -m "Migrate CongenitalOptimist to flakes with literate dotfiles"
Verification Steps
After switching:
- Verify system boots correctly
- Check all services are running:
systemctl --failed
- Test all desktop environments launch (GNOME, Cosmic, Sway)
- Verify virtualization:
sudo systemctl status libvirtd podman
- Check ZFS status:
zpool status
- Test network connectivity and Tailscale
- Verify user environment and all packages available
- Test modern CLI tools and aliases from base.nix
- Check console theming and TTY configuration
- Verify Emacs and literate programming workflow
Error Resolution
Common Issues:
- Boot failure: Boot from previous generation in GRUB
- Package not found: Check if package name changed in 25.05
- Service fails: Check journalctl:
journalctl -u <service-name>
- Desktop environment issues: Switch to TTY (Ctrl+Alt+F2) and debug
- Nerd fonts issues: Verify the new syntax is applied correctly
Emergency Recovery:
- Boot from previous NixOS generation in GRUB
- Use ZFS snapshots if available:
zfs rollback zpool/root@snapshot-name
- Keep live USB available for emergency repairs
Final Validation Checklist
- System boots to desktop
- All user applications launch (browsers, editors, terminals)
- Network and Tailscale functional
- Virtualization stack operational (podman, libvirt, incus)
- ZFS and NFS mounts working
- Development tools functional (editors, LSPs, languages)
- Audio system working (pipewire)
- Modern CLI tools and aliases from base.nix working
- Console theming with Joker palette preserved
- Bluetooth functional if needed
- Literate dotfiles workflow established
- Auto-tangling in Emacs working
Post-Migration Tasks
- Consider updating hostname from "work" to "congenital-optimist"
- Expand literate dotfiles in org-mode with more tools and configurations
- Create additional machine configurations in the flake
- Implement secrets management (agenix/sops-nix)
- Set up automatic updates
- Add system monitoring
- Document your literate programming workflow per user
- Consider using org-mode for documenting the entire home lab setup
- Set up org-export to generate beautiful documentation from your configs
- Create templates for common user configuration patterns
- Plan for additional users with their own dotfiles directories
- Consider shared vs user-specific configuration strategies
Notes for AI Agents
- Always preserve existing functionality - don't remove working features
- The system already has excellent modular structure - build on it
- Modern CLI tools are already configured in base.nix - don't duplicate
- Console theming is already set up - preserve the Joker palette
- Fix the typo in user.nix before proceeding
- Keep system.stateVersion as "23.11" - never change this
- Test thoroughly before committing to permanent changes
- Prioritize system stability over new features
- The literate programming approach should complement, not replace, the modular NixOS structure