No description
  • Nix 79%
  • Just 14.4%
  • Shell 6.2%
  • Dockerfile 0.4%
Find a file
2026-03-26 09:18:23 +00:00
home feat: add user avatar for login/lock screen 2026-03-25 10:25:22 +00:00
hosts chore: Replacing UUID placeholders with actual values for electra 2026-03-25 08:51:17 +00:00
justfiles feat(electra): add just recipe to re-enrol TPM2 LUKS keys 2026-03-25 09:23:14 +00:00
manual docs: synchronise README and manual with current codebase 2026-03-23 12:39:54 +00:00
modules feat: add user avatar for login/lock screen 2026-03-25 10:25:22 +00:00
packages chore: remove unused function arguments from nix module files 2026-03-05 20:46:01 +00:00
potential fix: remove unused inputs argument in potential/lyra/default.nix 2026-03-23 12:40:53 +00:00
scripts chore: improve portability and add personalisation script 2026-03-17 20:57:33 +00:00
secrets feat: add WireGuard VPN profile for electra and lena 2026-03-24 21:04:54 +00:00
users feat: replace RSA key for media3 with ed25519, add Yubikey nano key 2026-03-18 21:03:54 +00:00
.gitignore chore: tidy up .gitignore 2026-03-05 21:05:21 +00:00
.sops.yaml chore: Remove all references to decommissioned moxie host 2026-03-09 12:39:15 +00:00
CLAUDE.md docs: pull before committing to avoid cache server conflicts 2026-03-17 21:00:03 +00:00
flake.lock Chore: manual flake update 2026-03-26 09:18:23 +00:00
flake.nix chore: remove Crush AI agent and disable ollama/open-webui on electra 2026-03-23 11:18:02 +00:00
Justfile refactor: Split Justfile into per-group subfiles 2026-03-14 20:33:54 +00:00
QWEN.md docs: update CLAUDE.md, README, replace QWEN.md with symlink 2026-03-03 20:38:24 +00:00
README.md docs: synchronise README and manual with current codebase 2026-03-23 12:39:54 +00:00

NixOS Configuration

Multi-host NixOS configuration with modular structure.

Commands

Use just to manage your NixOS configuration. Run just or just --list to see all available recipes.

Common recipes:

  • just check — Validate flake syntax
  • just deploy — Deploy current configuration (auto-detects specialisation)
  • just deploy igpu — Deploy and activate a specific specialisation
  • just switch-spec igpu — Switch specialisation without rebuilding
  • just plasma-capture — Capture current KDE Plasma settings to home/plasma.nix
  • just diff-last-update — Show package changes from the last update
  • just generations — List system generations (before rollback)
  • just gc — Run garbage collection
  • just firmware-update — Update firmware via LVFS

Timer management:

  • just restic-snapshots — List restic backups
  • just restic-unlock — Remove stale restic locks
  • just restic-logs — Show restic backup logs
  • just restic-last-run — Show last restic backup run details
  • just restic-run-now — Trigger restic backup immediately
  • just nixos-gc-last-run — Show last GC run details
  • just nixos-gc-run-now — Trigger GC immediately
  • just nixos-auto-update-last-run — Show last auto-update run details
  • just nixos-auto-update-run-now — Trigger auto-update immediately

Directory Structure

nixos-config/
├── flake.nix                      # Flake definition (inputs & host configs)
├── flake.lock                     # Locked dependency versions
├── .sops.yaml                     # SOPS age key configuration for secrets
│
├── home/
│   ├── nimmo.nix                  # Home-manager config for nimmo (all hosts)
│   └── plasma.nix                 # Declarative KDE Plasma settings (via plasma-manager)
│
├── hosts/
│   ├── common/                    # Shared across ALL hosts
│   │   ├── default.nix            # Bootloader, networking, imports shared modules
│   │   ├── nix-settings.nix       # Flakes, build parallelism, caches
│   │   └── locale.nix             # Timezone, locale, keyboard layout
│   │
│   ├── electra/                   # Framework 16 laptop
│   │   ├── default.nix            # Unified config: base=battery, specialisations=igpu,dgpu
│   │   ├── hardware.nix           # Host-specific hardware imports (base)
│   │   ├── hardware-dgpu.nix      # NVIDIA/AMD Prime offload (dgpu specialisation)
│   │   └── framework-16.nix       # AMD GPU, fingerprint, PipeWire, zram, Framework tools
│   │
│   ├── lena/                      # Lenovo Ideapad 5 2-in-1 (Gen 9)
│   │   ├── default.nix            # Tablet mode, fingerprint, touchscreen
│   │   ├── disko.nix              # Btrfs partitioning layout
│   │   └── hardware-configuration.nix  # Auto-generated hardware config
│   │
│
├── modules/                       # Reusable feature modules
│   ├── common/
│   │   ├── default-config.nix     # Portability options (user, email, paths)
│   │   └── sops-host.nix          # sops-nix key source (host SSH key)
│   ├── boot/
│   │   └── silent-boot.nix        # Plymouth splash, quiet kernel parameters
│   ├── desktop/
│   │   ├── plasma.nix             # KDE Plasma 6 desktop environment
│   │   ├── apps.nix               # Desktop applications (Kate, LibreOffice, VLC, etc.)
│   │   └── fonts.nix              # Font packages and fontconfig defaults (desktop only)
│   ├── hardware/
│   │   ├── bluetooth.nix          # Bluetooth with experimental features
│   │   ├── printing.nix           # CUPS with Brother printer drivers, Avahi discovery
│   │   ├── removable-storage.nix  # udisks2, NTFS support, polkit mount rules
│   │   └── expansion-card-mount.nix  # 1TB expansion card automount (electra only)
│   ├── maintenance/
│   │   ├── garbage-collection.nix # Daily cleanup (3-day age limit)
│   │   └── btrfs-maintenance.nix  # Monthly btrfs scrub (all hosts)
│   ├── networking/
│   │   └── wifi-networks.nix      # WiFi network definitions (home + other known networks)
│   ├── power/
│   │   ├── auto-power-profile.nix # Automatic power profile switching
│   │   └── battery-mode.nix       # Locked power-saver + iGPU runtime PM (battery spec)
│   ├── profiles/
│   │   ├── gaming.nix             # Steam, Gamemode, Discord, MangoHUD, powertop (enable opt)
│   │   ├── ai-tools.nix           # Claude Code, Qwen Code, desktop launcher (enable opt)
│   │   ├── ai-development.nix     # ai-tools.nix + Ollama service (electra)
│   │   ├── maker.nix              # Cura, OpenSCAD (3D printing/CAD) (enable opt)
│   │   └── server-base.nix        # Common server CLI tools and SSH config (unused)
│   ├── services/
│   │   ├── nixos-auto-update.nix  # Daily auto-update with rollback
│   │   ├── btrbk-home.nix         # Hourly btrfs snapshots of /home (electra)
│   │   ├── ollama.nix             # AMD Ollama + Open WebUI (electra)
│   │   ├── ollama-common.nix      # Shared ollama user/group definition
│   │   ├── ollama-nvidia.nix      # NVIDIA Ollama supplement (dgpu only)
│   │   ├── ollama-rocm.nix        # AMD ROCm Ollama + Open WebUI (unused)
│   │   └── restic-backup.nix      # Automated backups every 6 hours (sops-nix secrets)
│   └── virtualization/
│       ├── docker.nix             # Base Docker with Btrfs
│       ├── docker-amd.nix         # Docker with AMD GPU (ROCm) support
│       └── docker-nvidia.nix      # Docker with NVIDIA Container Toolkit
│
├── packages/
│   └── system.nix                 # System-wide packages (all users, all hosts)
│
├── users/
│   ├── nimmo.nix                  # Admin user account definition
│   └── claire.nix                 # Standard user (lena only, no sudo)
│
├── secrets/
│   ├── secrets.yaml               # Encrypted secrets (sops-nix, age-encrypted)
│   └── README.md                  # Secrets management documentation
│
├── scripts/
│   └── check-flake.sh             # Container-based flake validation (podman fallback)
│
└── manual/                        # NixOS training manual (learning path)
    ├── README.md                  # Start here for the learning path index
    ├── 01-configuration-structure.md    # How this repo is organized
    ├── 02-workflows.md            # Step-by-step common tasks
    ├── 03-host-configurations.md  # Multi-host design decisions
    ├── 04-specialisations.md      # Electra's three boot tiers
    ├── 05-package-management.md   # Installing and finding software
    ├── 06-secrets-management.md   # sops-nix encrypted secrets
    ├── 07-troubleshooting.md      # Debugging and recovery
    ├── 08-quick-reference.md      # Command cheat sheet
    ├── 09-nix-language.md         # Nix syntax and data types
    ├── 10-declarative-configuration.md  # Why NixOS is declarative
    ├── 11-flakes.md               # Flake structure and reproducibility
    ├── 12-modules.md              # Module system deep dive
    └── 13-specialargs.md          # How flake inputs reach modules

How It All Fits Together

Understanding the import chain is key to knowing where to make changes. Each host pulls in only what it needs:

flake.nix
  └── hosts/electra/default.nix             (or lena)
        ├── hosts/common/default.nix         (shared across ALL hosts)
        │     ├── nix-settings.nix
        │     ├── locale.nix
        │     ├── modules/common/default-config.nix
        │     ├── modules/common/sops-host.nix
        │     ├── modules/maintenance/garbage-collection.nix
        │     └── modules/maintenance/btrfs-maintenance.nix
        ├── hosts/common/desktop.nix         (desktop hosts only: electra, lena)
        │     ├── modules/desktop/fonts.nix
        │     ├── modules/hardware/printing.nix
        │     └── modules/hardware/removable-storage.nix
        ├── hardware-configuration.nix
        ├── hardware.nix                     (imports framework-16.nix)
        ├── framework-16.nix                 (AMD GPU, fingerprint, PipeWire, zram)
        ├── modules/boot/silent-boot.nix
        ├── modules/desktop/plasma.nix
        ├── modules/desktop/apps.nix
        ├── modules/power/battery-mode.nix
        ├── modules/hardware/bluetooth.nix
        ├── modules/hardware/expansion-card-mount.nix
        ├── modules/services/restic-backup.nix
        ├── modules/services/btrbk-home.nix
        ├── modules/services/nixos-auto-update.nix
        ├── modules/networking/wifi-networks.nix
        ├── modules/profiles/ai-development.nix
        │     ├── modules/profiles/ai-tools.nix
        │     └── modules/services/ollama.nix
        ├── modules/profiles/maker.nix
        ├── modules/virtualization/docker-amd.nix
        ├── packages/system.nix
        ├── users/nimmo.nix
        ├── specialisation.igpu.configuration:
        │     ├── modules/power/auto-power-profile.nix
        │     ├── modules/profiles/gaming.nix
        │     └── modules/profiles/maker.nix
        └── specialisation.dgpu.configuration:
              ├── hardware-dgpu.nix          (NVIDIA/AMD Prime offload)
              ├── modules/services/ollama-nvidia.nix
              ├── modules/virtualization/docker-nvidia.nix
              ├── modules/virtualization/docker-amd.nix
              ├── modules/power/auto-power-profile.nix
              └── modules/profiles/gaming.nix

This means: if you want to change something for all hosts, edit hosts/common/. If you want to change something for electra only, edit hosts/electra/default.nix. If you want to change something for the dgpu specialisation only, edit hosts/electra/default.nix under specialisation.dgpu.configuration.

Home-Manager Integration

Home-manager manages user-level configuration declaratively across all hosts. It's integrated directly into the NixOS configuration (not standalone).

What's Managed by Home-Manager

User Packages (via capability profiles and home-manager):

  • AI tools (Claude Code, Qwen Code) — via modules/profiles/ai-tools.nix
  • Gaming packages (Discord, MangoHUD, powertop) — via modules/profiles/gaming.nix on electra
  • 3D printing/CAD (Cura, OpenSCAD) — via modules/profiles/maker.nix
  • Desktop apps (Element, Trilium, etc.) — via modules/desktop/apps.nix
  • Conditional packages (only on unstable channel): opencode-desktop, whosthere

Shell Environment (programs.bash):

  • Bash-it framework with rjorgenson theme
  • Custom nixos-rebuild-auto function (rebuilds and reactivates current specialisation)
  • History search with up/down arrows
  • Shell initialization

Development Tools:

  • Git configuration (unified email across hosts)
  • Direnv with nix-direnv integration

System Monitoring:

  • btop with ROCm/libdrm wrapper for GPU monitoring
  • Shows gpu0 and gpu1 slots; btop silently omits any GPU it cannot detect

Firefox (programs.firefox):

  • Declarative default profile with privacy/security hardening
  • Extensions from NUR: Bitwarden, Consent-O-Matic
  • Full telemetry/tracking/study opt-out, HTTPS-only mode, Pocket disabled

Desktop Optimization:

  • Autostart applications with delays (Nextcloud delayed 15s)
  • Disabled applications (Discover update notifier)
  • Faster login performance

Configuration Files

  • home/nimmo.nix - Main home-manager configuration
  • ~/.bash_it - Symlinked from Nix store (managed by bash-it flake input)
  • Firefox extensions - Declarative via NUR (inputs.nur); manually-managed extensions: Floccus, Karakeep

KDE Plasma Configuration (plasma-manager)

KDE Plasma settings are declaratively managed via home/plasma.nix using the plasma-manager flake input. This file is generated by capturing the current Plasma state:

just plasma-capture

This captures themes, keybindings, window behaviour, panel configuration, and other Plasma settings into a Nix file that is applied on rebuild. To make Plasma changes:

  1. Adjust settings via the KDE System Settings GUI
  2. Run just plasma-capture to capture the changes
  3. Review the diff, rebuild, commit

What's NOT Managed by Home-Manager

  • Application-specific configurations (managed via GUI)
  • Runtime user data and state

Updating User Configuration

Edit home/nimmo.nix and rebuild:

# Edit configuration
vim home/nimmo.nix

# Apply changes
nixos-rebuild-auto

Changes to home-manager configuration take effect immediately on rebuild - no reboot required.

Common Tasks

Check Configuration Syntax

Validate the flake without building. Note: New untracked files must be staged with git add first, as Nix flakes only see files tracked by git.

git add <new-files>  # If you created new files
nix flake check

Test Configuration

Build and activate without adding to boot menu (reverts on reboot):

sudo nixos-rebuild test --flake .#electra

Deploy Configuration

Build, activate, and add to boot menu:

# Auto-detect hostname and reactivate current specialisation (recommended)
nixos-rebuild-auto

# Or specify explicitly
sudo nixos-rebuild switch --flake .#electra
sudo nixos-rebuild switch --flake .#lena

The nixos-rebuild-auto command runs nixos-rebuild switch using the current hostname as the flake target, then reactivates the current specialisation (if any). All three boot entries (base, igpu, dgpu) are always built together in a single rebuild. It is defined as a bash function in home/nimmo.nix.

Switch Mode (Electra Specialisations)

Select the desired boot entry from the systemd-boot menu at startup. The bootloader uses @saved so it remembers your last selection across reboots.

  • Base entry (electra-battery): AMD iGPU, vanilla kernel, locked power-saver, no gaming/maker profiles — default mode
  • Specialisation entry (electra-igpu): AMD iGPU only, stock kernel, dynamic power profile, gaming/maker profiles
  • Specialisation entry (electra-dgpu): NVIDIA + AMD hybrid, Zen kernel — use when the NVIDIA expansion bay is installed

Update All Packages

Updates run automatically at 03:00 daily (both hosts, pull-only mode). To trigger manually:

just nixos-auto-update-run-now       # Normal run (respects 6h freshness window)
sudo nixos-auto-update --force       # Force update regardless of lock age

To see what changed after an update:

just diff-last-update

Adding Packages

There are three places to add packages, depending on scope:

System Packages (available to all users, all hosts)

Edit packages/system.nix. These are available system-wide via environment.systemPackages:

environment.systemPackages = with pkgs; [
  # Add your package here
  neovim
];

User Packages (nimmo, all hosts)

Edit home/nimmo.nix. These are managed by home-manager and available to nimmo on every host:

home.packages = with pkgs; [
  # Add your package here
  spotify
];

Capability Profiles

modules/profiles/ bundles related system and user-level config into a single import:

Profile What it enables Enable option
gaming.nix Steam, Gamemode, Discord, MangoHUD, powertop Import to enable
ai-tools.nix Claude Code, Qwen Code, Claude Code desktop launcher profiles.aiTools.enable (default: true)
ai-development.nix ai-tools.nix + Ollama service + Open WebUI Import to enable
maker.nix Cura, OpenSCAD (3D printing/CAD) Import to enable

Add a profile to a host by importing it in that host's default.nix:

imports = [
  # ...
  ../../modules/profiles/gaming.nix
];

For packages that don't fit an existing profile, add them directly to that host's default.nix (e.g. hosts/electra/default.nix or hosts/lena/default.nix).

Desktop Applications (all desktop hosts)

Edit modules/desktop/apps.nix. These are system-wide packages for desktop/laptop use (Kate, LibreOffice, VLC, Okular, Nextcloud, Bitwarden, etc.). Both electra and lena import this module.

Finding Package Names

Search for packages:

nix search nixpkgs firefox
nix search nixpkgs --json firefox | jq  # Detailed output

Or browse https://search.nixos.org/packages

Adding External Flakes

1. Add the input to flake.nix

inputs = {
  # ... existing inputs ...

  # New flake
  some-tool.url = "github:owner/repo";
  some-tool.inputs.nixpkgs.follows = "nixpkgs";  # Use our nixpkgs
};

2. Pass it through specialArgs

Already configured - all inputs are passed via specialArgs = { inherit inputs; }.

3. Use the package

In any module that has inputs in its arguments:

{ pkgs, inputs, ... }:

{
  environment.systemPackages = [
    inputs.some-tool.packages.${pkgs.stdenv.hostPlatform.system}.default
  ];
}

4. Update the lock file

nix flake update some-tool

Adding a New Host

1. Create host directory

mkdir -p hosts/newhostname

2. Generate hardware config on the new machine

nixos-generate-config --show-hardware-config > hosts/newhostname/hardware-configuration.nix

3. Create host default.nix

{ config, pkgs, inputs, ... }:

{
  imports = [
    ../common
    ./hardware-configuration.nix
    # Add modules as needed
    ../../modules/boot/silent-boot.nix
    ../../modules/desktop/plasma.nix
    ../../modules/desktop/apps.nix
    ../../packages/system.nix
    ../../users/nimmo.nix
  ];

  networking.hostName = "newhostname";

  system.stateVersion = "25.11";  # Set to your NixOS version
}

4. Add to flake.nix

nixosConfigurations = {
  electra = nixpkgs.lib.nixosSystem { ... };

  newhostname = nixpkgs.lib.nixosSystem {
    specialArgs = { inherit inputs; };
    modules = [ ./hosts/newhostname ];
  };
};

5. Deploy

# First deployment (explicit)
sudo nixos-rebuild switch --flake .#newhostname

# Subsequent deployments can use
nixos-rebuild-auto

Adding New Modules

Create a new file in modules/category/:

# modules/services/tailscale.nix
{ config, pkgs, ... }:

{
  services.tailscale.enable = true;
  environment.systemPackages = [ pkgs.tailscale ];
}

Then import it in the appropriate host config:

  • hosts/common/default.nix - for all hosts
  • hosts/electra/default.nix - for electra (both modes)
  • hosts/electra/default.nix (under specialisation.dgpu.configuration) or hosts/lena/default.nix - for a single mode/host
imports = [
  # ...
  ../../modules/services/tailscale.nix
];

Rollback

Boot into previous generation

Select from boot menu at startup (systemd-boot shows all available generations).

Rollback from command line

# List generations
sudo nix-env --list-generations --profile /nix/var/nix/profiles/system

# Switch to specific generation
sudo nix-env --switch-generation 42 --profile /nix/var/nix/profiles/system
sudo /nix/var/nix/profiles/system/bin/switch-to-configuration switch

Garbage Collection

Automatic daily cleanup is configured in modules/maintenance/garbage-collection.nix:

  • Deletes generations older than 3 days
  • Runs daily with a randomized 1-hour delay to avoid contention

Additionally, nix-settings.nix configures automatic store GC to maintain 5-10GB free disk space.

Manual cleanup:

# Remove old generations (keeps last 7 days)
sudo nix-collect-garbage --delete-older-than 7d

# Remove ALL old generations (keep only current)
sudo nix-collect-garbage -d

Automated System Services

NixOS Auto-Update (All Hosts)

Defined in modules/services/nixos-auto-update.nix. Both hosts run in pull-only mode at 03:00 with a 15-minute randomised delay.

Pull-only mode (all hosts):

  1. Skips if the repository has uncommitted changes (work in progress detected)
  2. Pulls latest config from remote
  3. Validates the configuration with a dry-run build
  4. Builds the new configuration
  5. Switches to the new configuration and reactivates the current specialisation if applicable
  6. Desktop notifications at key points and on success/failure; warns separately if a reboot is needed for kernel changes

The flake.lock is updated either manually (nix flake update) or automatically via the nix binary cache webhook which triggers a rebuild on push.

The service also supports full mode (not currently used) which additionally runs nix flake update, validates, commits the lock file with a summary of input changes, and pushes — before switching. On switch failure it rolls back the commit.

Monitor the service:

journalctl -u nixos-auto-update.service -f

Trigger or inspect manually:

just nixos-auto-update-run-now   # Trigger immediately (normal run)
just nixos-auto-update-last-run  # Show last run status
sudo nixos-auto-update --force   # Force flake update regardless of lock age
just diff-last-update            # Show package changes from the last update

Restic Backup (Electra and Lena)

Defined in modules/services/restic-backup.nix. Automated backups of /home/nimmo:

  • Runs every 6 hours with 15-minute randomized delay
  • Credentials managed via sops-nix (encrypted in secrets/secrets.yaml, decrypted to /run/secrets/ at runtime)
  • Excludes configured via /etc/restic/excludes.txt (created empty; edit to customise)

Monitor backups:

journalctl -u restic-backup.service -f

Silent Boot (All hosts)

Defined in modules/boot/silent-boot.nix. Plymouth splash screen with quiet kernel parameters for a clean boot experience.

Auto Power Profile (Electra igpu/dgpu and Lena)

Defined in modules/power/auto-power-profile.nix. Triggered by udev on AC plug/unplug events and switches profiles:

  • Charging/Full + >25% battery: performance mode
  • Charging/Full + <=25% battery: balanced mode
  • Discharging + >50% battery: balanced mode
  • Discharging + <=50% battery: power-saver mode

Monitor with:

journalctl -u auto-power-profile.service -f

Current Hosts

Host Machine Channel Key Differences
electra Framework 16 unstable Base: battery mode (vanilla kernel, locked power-saver, iGPU runtime PM, maker). Specialisation igpu: dynamic power profile, gaming/maker. Specialisation dgpu: Zen kernel, NVIDIA/AMD hybrid, dual Ollama, Docker
lena Lenovo Ideapad 5 2-in-1 25.11 stable Tablet mode, touchscreen, Disko partitioning, auto-update (pull-only), no Ollama/gaming

Shared Across All Hosts (via hosts/common/)

  • Systemd-boot, NetworkManager
  • Garbage collection (daily, 3-day age limit)
  • btrfs scrub (monthly, all btrfs mounts)
  • Portability options (modules/common/default-config.nix)
  • sops-nix host key configuration
  • UK locale (en_GB.UTF-8, Europe/London)

Desktop hosts only (electra, lena — via hosts/common/desktop.nix):

  • Fonts (Noto, Fira Code, JetBrains Mono Nerd Font)
  • Printing (CUPS with Brother drivers, Avahi network discovery)
  • Removable storage (udisks2, NTFS support, polkit mount rules)
  • KDE Plasma 6 (login manager is host-specific: plasma-login-manager on electra, SDDM on lena)
  • Silent boot (Plymouth)
  • Auto power profile switching (udev-triggered)
  • Bluetooth
  • Desktop apps (modules/desktop/apps.nix)
  • System packages (packages/system.nix)

Electra (All Modes)

  • Framework 16 hardware module (AMD GTT 32GB, fingerprint, PipeWire, zram, ROCm)
  • Expansion card automount (1TB NTFS at /run/media/nimmo/Expansion1TB)
  • AI development profile (modules/profiles/ai-development.nix): Ollama + Open WebUI + AI user tools
  • Maker profile (modules/profiles/maker.nix): Cura, OpenSCAD
  • NixOS auto-update (daily)
  • ROCm HSA override for AMD 780M iGPU (HSA_OVERRIDE_GFX_VERSION=11.0.0)
  • Docker with AMD 780M iGPU access

Electra Base (battery)

  • Linux vanilla kernel (mainline, no latency tuning)
  • Power profile locked to power-saver (modules/power/battery-mode.nix)
  • iGPU runtime power management (amdgpu.runpm=1)
  • Gaming profile disabled

Electra igpu Specialisation Only

  • Dynamic power profile switching (modules/power/auto-power-profile.nix)
  • Gaming profile (modules/profiles/gaming.nix): Steam, Gamemode, Discord, MangoHUD, powertop
  • Maker profile (modules/profiles/maker.nix): Cura, OpenSCAD

Electra dgpu Specialisation Only

  • Linux Zen kernel
  • Dynamic power profile switching (modules/power/auto-power-profile.nix)
  • Gaming profile (modules/profiles/gaming.nix): Steam, Gamemode, Discord, MangoHUD, powertop
  • NVIDIA/AMD Prime offload drivers
  • NVIDIA Ollama instance (port 11435, CUDA acceleration)
  • Docker with NVIDIA Container Toolkit
  • nvtop for GPU monitoring

Lena-Specific

  • Tablet mode via iio-sensor-proxy (automatic screen rotation)
  • Fingerprint reader via fprintd
  • Btrfs with Disko-managed partitioning (subvolumes: @, @home, @nix, @log)
  • Both nimmo (admin) and claire (standard user) accounts
  • AI tools profile (modules/profiles/ai-tools.nix): Claude Code, Qwen Code
  • Maker profile (modules/profiles/maker.nix): Cura, OpenSCAD
  • NixOS 25.11 stable channel

User Accounts

nimmo (All hosts)

  • Type: Administrator account
  • Groups: wheel (sudo), networkmanager, video, audio, render, docker (all electra modes)
  • Shell: bash with bash-it framework (rjorgenson theme)
  • Configuration: Managed by home-manager in home/nimmo.nix
  • Packages: Via capability profiles (modules/profiles/); AI tools, gaming, and maker packages are per-host based on which profiles are imported
  • Features:
    • Git configuration unified across all hosts (nimmo@nimmog.uk)
    • Direnv with nix-direnv for automatic environment loading
    • Custom nixos-rebuild-auto function (rebuilds and reactivates current specialisation)
    • Optimized autostart: Nextcloud delayed 15 seconds, Discover disabled for faster login

claire (Lena only)

  • Type: Standard user account
  • Groups: networkmanager, video, audio (no wheel/sudo)
  • Purpose: Guest/family account with restricted privileges
  • Packages: System packages only

Ollama with Open WebUI

Electra runs Ollama for local LLM inference with Open WebUI as the web interface, using native NixOS services.

Architecture

Base / both modes (modules/profiles/ai-development.nixmodules/services/ollama.nix): AMD Ollama instance + Open WebUI (imported via electra)

  • AMD iGPU Instance (port 11434): For large models with 48GB shared RAM
    • Context window: 65,536 tokens
    • Vulkan acceleration
    • Keep-alive: 24 hours
  • Open WebUI (localhost:3000): Web interface for model interaction

dgpu specialisation (modules/services/ollama-nvidia.nix): Adds a second NVIDIA instance

  • NVIDIA dGPU Instance (port 11435): For fast inference with 8GB VRAM
    • Context window: 8,192 tokens
    • CUDA acceleration
    • Optimized for quick chats and coding completion
  • Open WebUI is configured to connect to both instances

Both instances share a models directory at /run/media/models (btrfs subvolume), so models downloaded on one instance are available to the other.

Usage

Access the web interface at http://localhost:3000

Direct API access:

# AMD instance (electra, all tiers)
curl http://localhost:11434/api/generate -d '{"model":"llama3.2","prompt":"Hello"}'

# NVIDIA instance (electra-dgpu only)
curl http://localhost:11435/api/generate -d '{"model":"llama3.2","prompt":"Hello"}'

View logs:

journalctl -u ollama.service -f          # AMD instance
journalctl -u ollama-nvidia.service -f   # NVIDIA instance (electra-dgpu only)
journalctl -u open-webui.service -f      # Web interface

Hardware Acceleration

dgpu specialisation:

  • AMD instance uses Vulkan with GTT extended to 32GB (amdgpu.gtt_size=32768)
  • NVIDIA instance uses CUDA
  • Both instances run simultaneously, allowing you to choose the best hardware for each task

Base (iGPU mode):

  • Uses Vulkan with GTT extended to 32GB
  • HSA override for RDNA3 780M compatibility (HSA_OVERRIDE_GFX_VERSION=11.0.0)

Model Recommendations

For NVIDIA dGPU (8GB VRAM) - Fast inference:

  • Llama 3.2 3B (very fast, lightweight)
  • Qwen 2.5 Coder 7B (excellent for code)
  • Llama 3.1 8B (balanced performance)
  • Mistral 7B (general purpose)

For AMD iGPU with 48GB shared RAM - Large models:

  • Qwen 2.5 72B (high capability)
  • CodeLlama 70B (specialized for code)
  • QwQ 32B (reasoning focused)
  • Llama 3.1 70B (general purpose)
  • DeepSeek Coder 33B (advanced code generation)

Data Persistence

/run/media/models/        # Shared models directory (btrfs @models subvolume)
/var/lib/ollama/          # AMD instance state
/var/lib/ollama-nvidia/   # NVIDIA instance state (dgpu specialisation only)
/var/lib/open-webui/      # Open WebUI data (chat history, settings)

Flake Inputs

Input Purpose
nixpkgs NixOS unstable (electra)
nixpkgs-bitwarden Pinned nixpkgs for bitwarden-desktop (electron 39 workaround)
nixpkgs-stable NixOS 25.11 (lena)
home-manager User environment management (unstable)
home-manager-stable User environment management (stable, for lena)
bash-it Bash framework for themes and plugins
claude-code-nix Claude Code AI assistant
nixos-hardware Hardware-optimized configs (Lenovo Ideapad, Framework)
disko Declarative disk partitioning
nur Nix User Repository (Firefox extensions)
sops-nix Encrypted secrets management (age-based)
plasma-manager Declarative KDE Plasma configuration via home-manager
framework-system Official Framework hardware tool (upstream flake)

Learning More

The manual/ directory contains a 13-chapter learning manual designed to take you from relying on AI for config changes to understanding and confidently modifying the configuration yourself. Start with manual/README.md for the chapter index. Practical chapters come first; theory chapters come later.

  • Need to do a specific task right now? Jump to Chapter 2 (Workflows) or Chapter 8 (Quick Reference).
  • Want to understand how this repo is organised? Start at Chapter 1 (Configuration Structure).
  • Something broke? Go to Chapter 7 (Troubleshooting).
  • New to Nix entirely? Start at Chapter 9 (Nix Language) and work through Part 2.