20 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.
General instructions
This document is to be treated as an iterative work and a collaberation.
Goal for this file
Top part reusable instructions that can be transferred to other project and as away to iterativey make ai agent behave more like I prefer. Bottom part should have information specific to the project. The Plan.md file should have the project information and steps.
Programming Languages and styles
- Prefer functional style
- Guille scheme for
- Python for ai and when guile
- Bash only for short scripts
- Typescript and javascript for web
- Rust for binary tools etc
Written language and style
use Notes.md to take notes . Use a casual but knowledgeable tone. This is not a corporate project there are no audits or compliance to adhere to. More like an open source project, more like a hobby/passion project
Bottom part
itreative about the project update often
Current System Information
- Hostname: work → congenital-optimist (migration in progress)
- Current Version: NixOS 25.05 (migrated from 23.11)
- Target Version: NixOS 25.05 ✅
- Architecture: x86_64-linux
- Storage: ZFS (zpool for system, stuffpool for data)
- Hardware: AMD CPU/GPU
- Users: geir (primary), sma (admin)
- 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
│ ├── sleeper-service/
│ ├── reverse-proxy/
│ └── grey-area/
├── modules/
│ ├── common/
│ │ ├── base.nix (modern CLI tools & aliases)
│ │ ├── tty.nix (console styling with Joker theme)
│ │ └── nix.nix (flakes configuration)
│ ├── desktop/
│ │ ├── common.nix, gnome.nix, cosmic.nix, sway.nix
│ ├── development/
│ │ └── tools.nix (editors, LSPs, languages)
│ ├── hardware/
│ │ └── amd-workstation.nix
│ ├── system/
│ │ ├── applications.nix, fonts.nix, network.nix
│ ├── users/
│ │ ├── common.nix, geir.nix, sma.nix
│ └── virtualization/
│ ├── podman.nix, libvirt.nix, incus.nix
└── users/
└── geir/
└── dotfiles/ (literate org-mode configs)
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
- Git repository is initialized and up to date
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