Files
nixos-config/docs/plans/2026-04-26-home-profile-restructuring.md
m3tm3re 06b430e067 fix: code review fixes
- Fix hardcoded user path in webapps.nix (use homeDirectory)
- Normalize wallpapers option to use .enable suffix
- Remove duplicate FZF keybind declaration
- Update comments to match actual implementation
2026-04-26 10:48:52 +02:00

19 KiB

Home Profile Restructuring Implementation Plan

For agentic workers: REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Restructure nixos-config/home/ from host-based to profile-based organization with clear separation between base, coding, profiles, desktop, and server layers.

Architecture: Three-layer model: Base (always loaded) → Coding (profile-independent) → Profiles/Context (freely combinable with constraints). Desktop and Server contexts are mutually exclusive.

Tech Stack: NixOS, Home Manager, Nix flakes


File Structure

home/
├── base/                          # IMMER geladen
│   ├── default.nix
│   ├── shell/
│   │   ├── default.nix
│   │   ├── nushell.nix            # PRIMARY Shell
│   │   └── starship.nix
│   ├── cli-tools/
│   │   ├── default.nix
│   │   ├── fzf.nix
│   │   ├── zellij.nix
│   │   ├── nitch.nix
│   │   └── television.nix
│   └── secrets/
│       └── secrets.nix
│
├── coding/                        # Profil-unabhängig
│   ├── default.nix
│   ├── editor/
│   │   ├── default.nix
│   │   └── neovim.nix             # Basis NeoVim (aus nixpkgs referenziert)
│   ├── lsp/
│   │   ├── default.nix
│   │   └── servers.nix
│   ├── git/
│   │   └── git.nix
│   └── agents/
│       └── agents.nix              # Agent-System (aus nixpkgs referenziert)
│
├── profiles/                      # FREI KOMBINIERBAR
│   ├── gaming/
│   │   ├── default.nix
│   │   ├── steam.nix
│   │   └── gamescope.nix
│   │
│   └── media/
│       ├── default.nix
│       ├── obs.nix
│       ├── ffmpeg.nix
│       ├── yt-dlp.nix
│       ├── kdenlive.nix
│       └── handbrake.nix
│
├── desktop/                       # NUR wenn context=desktop
│   ├── default.nix
│   ├── wm/
│   │   ├── default.nix
│   │   ├── hyprland.nix
│   │   ├── wayland.nix
│   │   └── rofi.nix
│   ├── apps/
│   │   ├── default.nix
│   │   ├── obsidian.nix
│   │   ├── office.nix
│   │   ├── webapps.nix
│   │   └── crypto.nix
│   └── theme/
│       ├── default.nix
│       ├── fonts.nix
│       ├── theme.nix
│       └── wallpapers.nix
│
└── server/
    └── default.nix

Key Integration Points:

Component Source Notes
NeoVim Config inputs.m3ta-nixpkgs.pkgs.neovim-config Custom package in nixpkgs
OpenCode Desktop inputs.m3ta-nixpkgs.pkgs.opencode-desktop Custom package
Agent-System inputs.m3ta-nixpkgs.homeModules.coding.agents OpenCode, Claude Code, Pi
Zed Editor inputs.m3ta-nixpkgs.homeModules.coding.editors Desktop-only via Zed Remote
Editor Module inputs.m3ta-nixpkgs.homeModules.coding.editors NeoVim (base) + Zed (desktop)

Phase 1: Create New Structure

Task 1: Create Directory Structure

Files:

  • Create: home/base/default.nix

  • Create: home/base/shell/default.nix

  • Create: home/base/shell/nushell.nix

  • Create: home/base/shell/starship.nix

  • Create: home/base/cli-tools/default.nix

  • Create: home/base/cli-tools/fzf.nix

  • Create: home/base/cli-tools/zellij.nix

  • Create: home/base/cli-tools/nitch.nix

  • Create: home/base/cli-tools/television.nix

  • Create: home/base/secrets/secrets.nix

  • Create: home/coding/default.nix

  • Create: home/coding/editor/default.nix

  • Create: home/coding/editor/neovim.nix

  • Create: home/coding/lsp/default.nix

  • Create: home/coding/lsp/servers.nix

  • Create: home/coding/git/git.nix

  • Create: home/coding/agents/agents.nix

  • Create: home/profiles/gaming/default.nix

  • Create: home/profiles/gaming/steam.nix

  • Create: home/profiles/gaming/gamescope.nix

  • Create: home/profiles/media/default.nix

  • Create: home/profiles/media/obs.nix

  • Create: home/profiles/media/ffmpeg.nix

  • Create: home/profiles/media/yt-dlp.nix

  • Create: home/profiles/media/kdenlive.nix

  • Create: home/profiles/media/handbrake.nix

  • Create: home/desktop/default.nix

  • Create: home/desktop/wm/default.nix

  • Create: home/desktop/wm/hyprland.nix

  • Create: home/desktop/wm/wayland.nix

  • Create: home/desktop/wm/rofi.nix

  • Create: home/desktop/apps/default.nix

  • Create: home/desktop/apps/obsidian.nix

  • Create: home/desktop/apps/office.nix

  • Create: home/desktop/apps/webapps.nix

  • Create: home/desktop/apps/crypto.nix

  • Create: home/desktop/theme/default.nix

  • Create: home/desktop/theme/fonts.nix

  • Create: home/desktop/theme/theme.nix

  • Create: home/desktop/theme/wallpapers.nix

  • Create: home/server/default.nix

  • Modify: home/default.nix (Hauptaggregator)

  • Step 1: Create home/base/default.nix

# home/base/default.nix
# Basis-Konfiguration: Shell + CLI-Tools + Secrets
# Wird IMMER geladen (kein enable-Flag)

{ inputs, lib, pkgs, ... }:

{
  imports = [
    ./shell
    ./cli-tools
    ./secrets
  ];
}
  • Step 2: Create home/base/shell/default.nix
# home/base/shell/default.nix
{ inputs, lib, pkgs, ... }:

{
  imports = [
    ./nushell.nix
    ./starship.nix
  ];
}
  • Step 3: Create home/base/shell/nushell.nix

Migrated from: home/features/cli/nushell.nix

# home/base/shell/nushell.nix
# Primary shell - Nushell
{ lib, pkgs, ... }:

{
  programs.nushell = {
    enable = true;
    configFile = ...;
  };
  
  home.packages = with pkgs; [
    nushell
  ];
}
  • Step 4: Create home/base/shell/starship.nix

Migrated from: home/features/cli/starship.nix

  • Step 5: Create home/base/cli-tools/default.nix
# home/base/cli-tools/default.nix
{ ... }:

{
  imports = [
    ./fzf.nix
    ./zellij.nix
    ./nitch.nix
    ./television.nix
  ];
}
  • Step 6: Create CLI tool modules

Migrate from home/features/cli/:

  • fzf.nixhome/base/cli-tools/fzf.nix

  • zellij.nixhome/base/cli-tools/zellij.nix

  • nitch.nixhome/base/cli-tools/nitch.nix

  • television.nixhome/base/cli-tools/television.nix

  • Step 7: Create home/base/secrets/secrets.nix

Migrated from: home/features/cli/secrets.nix

  • Step 8: Create home/coding/default.nix
# home/coding/default.nix
# Coding-Konfiguration: Editor + LSP + Git + Agents
# Wird geladen wenn coding Profil aktiviert

{ inputs, lib, pkgs, ... }:

{
  imports = [
    ./editor
    ./lsp
    ./git
    ./agents
  ];
}
  • Step 9: Create home/coding/editor/default.nix

References: inputs.m3ta-nixpkgs.homeModules.coding.editors

# home/coding/editor/default.nix
{ inputs, lib, pkgs, ... }:

{
  # Importiert NeoVim (immer) + Zed (desktop)
  imports = [
    inputs.m3ta-nixpkgs.homeModules.coding.editors
  ];
  
  # NeoVim Config Package
  home.packages = [ inputs.m3ta-nixpkgs.packages.${pkgs.system}.neovim-config ];
}
  • Step 10: Create home/coding/lsp/default.nix + servers.nix

Migrate LSP configuration from existing setup

  • Step 11: Create home/coding/git/git.nix
# home/coding/git/git.nix
{ lib, pkgs, ... }:

{
  programs.git = {
    enable = true;
    # Git configuration
  };
}
  • Step 12: Create home/coding/agents/agents.nix

References: inputs.m3ta-nixpkgs.homeModules.coding.agents

# home/coding/agents/agents.nix
{ inputs, lib, pkgs, ... }:

{
  imports = [
    inputs.m3ta-nixpkgs.homeModules.coding.agents
  ];
  
  # Agent-Konfiguration
  coding.agents.opencode = {
    enable = true;
    agentsInput = inputs.agents;
    # modelOverrides...
  };
}
  • Step 13: Create home/profiles/gaming/default.nix
# home/profiles/gaming/default.nix
# Gaming Profile - frei kombinierbar

{ lib, pkgs, ... }:

{
  imports = [
    ./steam.nix
    ./gamescope.nix
  ];
}
  • Step 14: Create gaming profile modules

  • steam.nix - Steam + Steam Deck Tools

  • gamescope.nix - Gamescope Session

  • Step 15: Create home/profiles/media/default.nix

# home/profiles/media/default.nix
# Media Profile - Content Creation / Streaming

{ lib, pkgs, ... }:

{
  imports = [
    ./obs.nix
    ./ffmpeg.nix
    ./yt-dlp.nix
    ./kdenlive.nix
    ./handbrake.nix
  ];
}
  • Step 16: Create media profile modules

Migrate from home/features/desktop/media.nix:

  • obs.nix - OBS Studio

  • ffmpeg.nix - FFmpeg + Tools

  • yt-dlp.nix - YouTube Downloader

  • kdenlive.nix - Kdenlive Video Editor

  • handbrake.nix - HandBrake

  • Step 17: Create home/desktop/default.nix

# home/desktop/default.nix
# Desktop-Konfiguration - nur wenn context=desktop

{ lib, pkgs, ... }:

{
  # Zed Remote: Server-Zugriff via SSH
  programs.zed-editor = {
    enable = true;
    # Remote Connections Config
  };
  
  imports = [
    ./wm
    ./apps
    ./theme
  ];
}
  • Step 18: Create home/desktop/wm modules

Migrate from home/features/desktop/:

  • hyprland.nixhome/desktop/wm/hyprland.nix

  • wayland.nixhome/desktop/wm/wayland.nix

  • rofi.nixhome/desktop/wm/rofi.nix

  • Step 19: Create home/desktop/apps modules

Migrate from home/features/desktop/:

  • obsidian.nixhome/desktop/apps/obsidian.nix

  • office.nixhome/desktop/apps/office.nix

  • webapps.nixhome/desktop/apps/webapps.nix

  • crypto.nixhome/desktop/apps/crypto.nix

  • Step 20: Create home/desktop/theme modules

Migrate from home/features/desktop/:

  • fonts.nixhome/desktop/theme/fonts.nix

  • theme.nixhome/desktop/theme/theme.nix

  • wallpapers.nixhome/desktop/theme/wallpapers.nix

  • Step 21: Create home/server/default.nix

# home/server/default.nix
# Server-Konfiguration - nur wenn context=server
# Minimal da primär via Zed Remote gearbeitet wird

{ lib, pkgs, ... }:

{
  # Server-spezifische Konfiguration falls nötig
}
  • Step 22: Commit Phase 1
git add home/
git commit -m "feat(home): create new directory structure

- Add base/ with shell, cli-tools, secrets
- Add coding/ with editor, lsp, git, agents
- Add profiles/ with gaming, media
- Add desktop/ with wm, apps, theme
- Add server/ minimal config
- Reference m3ta-nixpkgs modules where appropriate"

Phase 2: Create Profile System with Constraints

Task 2: Implement Profile Loader with Mutual Exclusion

Files:

  • Create: home/lib/default.nix (Profile loading utilities)

  • Modify: flake.nix (Host-spezifische Home-Config)

  • Modify: hosts/common/users/home.nix

  • Step 1: Create home/lib/default.nix

# home/lib/default.nix
# Profile loading utilities

{ lib }:

{
  # Generiert Home-Manager Konfiguration basierend auf Profilen
  mkHomeConfig = {
    profiles ? [],
    context ? null,  # "desktop" | "server" | null
  }: let
    inherit (lib) optionalAttrs mkIf;
    
    # Profile die immer geladen werden
    baseModules = [ ./base ];
    
    # Profile die optional geladen werden
    profileModules = optionalAttrs (builtins.elem "coding" profiles) [ ./coding ];
    
    # Context-spezifische Module
    contextModules = {
      desktop = [ ./desktop ];
      server = [ ./server ];
    };
    
    # Profile-spezifische Module
    profileSpecific = {
      gaming = [ ./profiles/gaming ];
      media = [ ./profiles/media ];
    };
    
  in {
    imports = baseModules ++ profileModules 
      ++ (contextModules.${context} or [])
      ++ (builtins.map (p: ./profiles.${p}) 
          (builtins.filter (p: builtins.hasAttr p profileSpecific) profiles));
  };
  
  # Assertion: desktop und server schließen sich aus
  mutualExclusiveContexts = builtins.hasAttr "desktop" && builtins.hasAttr "server";
}
  • Step 2: Update flake.nix for m3-ares (Desktop)
# hosts/m3-ares/ (Desktop Beispiel)
{ inputs, lib, pkgs, ... }:

{
  # Home-Manager für m3tam3re auf m3-ares
  home-manager.users.m3tam3re = { config, ... }: {
    # NEU: Profile-System
    m3ta.profiles = [ "coding" "gaming" "media" ];  # Freie Kombination
    m3ta.context = "desktop";  # Schließt "server" aus
    
    # Alternativ: Legacy-Kompatibilität
    # imports = [ ./home ];
  };
}
  • Step 3: Update flake.nix for m3-atlas (Server)
# hosts/m3-atlas/ (Server Beispiel)
{ inputs, lib, pkgs, ... }:

{
  home-manager.users.m3tam3re = { config, ... }: {
    m3ta.profiles = [ "coding" ];  # Nur Coding auf Server
    m3ta.context = "server";  # Schließt "desktop" aus
  };
}
  • Step 4: Add assertions in flake.nix
# Validation: Context constraints
assertion = hostConfig.m3ta.context != "desktop" || hostConfig.m3ta.context != "server" 
  || (hostConfig.m3ta.context == null);  # Mutually exclusive
  • Step 5: Commit Phase 2
git add flake.nix hosts/
git commit -m "feat: implement profile system with constraints

- Add home/lib for profile loading utilities
- Add m3ta.profiles option (list of profiles)
- Add m3ta.context option (desktop|server|null)
- Add mutual exclusion assertion
- Update m3-ares and m3-atlas as examples"

Phase 3: Migrate Existing Configuration

Task 3: Migrate home/features to new Structure

Files:

  • Modify: Multiple files in home/features/ (move content, update paths)

  • Step 1: Map existing features to new structure

Old Location New Location Notes
home/features/cli/nushell.nix home/base/shell/nushell.nix ✓ Done in Task 1
home/features/cli/starship.nix home/base/shell/starship.nix ✓ Done in Task 1
home/features/cli/fzf.nix home/base/cli-tools/fzf.nix ✓ Done in Task 1
home/features/cli/zellij.nix home/base/cli-tools/zellij.nix ✓ Done in Task 1
home/features/cli/nitch.nix home/base/cli-tools/nitch.nix ✓ Done in Task 1
home/features/cli/television.nix home/base/cli-tools/television.nix ✓ Done in Task 1
home/features/cli/secrets.nix home/base/secrets/secrets.nix ✓ Done in Task 1
home/features/coding/opencode.nix Reference via m3ta-nixpkgs Update import
home/features/coding/pi.nix Reference via m3ta-nixpkgs Update import
home/features/desktop/hyprland.nix home/desktop/wm/hyprland.nix ✓ Done in Task 1
home/features/desktop/wayland.nix home/desktop/wm/wayland.nix ✓ Done in Task 1
home/features/desktop/rofi.nix home/desktop/wm/rofi.nix ✓ Done in Task 1
home/features/desktop/obsidian.nix home/desktop/apps/obsidian.nix ✓ Done in Task 1
home/features/desktop/office.nix home/desktop/apps/office.nix ✓ Done in Task 1
home/features/desktop/webapps.nix home/desktop/apps/webapps.nix ✓ Done in Task 1
home/features/desktop/crypto.nix home/desktop/apps/crypto.nix ✓ Done in Task 1
home/features/desktop/fonts.nix home/desktop/theme/fonts.nix ✓ Done in Task 1
home/features/desktop/theme.nix home/desktop/theme/theme.nix ✓ Done in Task 1
home/features/desktop/wallpapers.nix home/desktop/theme/wallpapers.nix ✓ Done in Task 1
home/features/desktop/media.nix home/profiles/media/*.nix Split into modules
home/features/desktop/gaming.nix home/profiles/gaming/*.nix Split into modules
  • Step 2: Archive old structure
# After migration, archive old features/
git mv home/features home/features.old
  • Step 3: Verify all configurations are imported
# Check that all features are accessible in new structure
nix flake check
home-manager dry-activate
  • Step 4: Commit Phase 3
git add -A
git commit -m "chore: migrate features to profile structure

- Move all cli features to base/shell and base/cli-tools
- Move desktop features to desktop/* subdirectories
- Split media into individual profile modules
- Split gaming into individual profile modules
- Archive old features/ directory"

Phase 4: Test and Validate

Task 4: Test Profile Combinations

Files:

  • Test: Manual testing on m3-ares (Desktop)

  • Test: Manual testing on m3-atlas (Server)

  • Step 1: Test m3-ares (Desktop with all profiles)

# Build and test on m3-ares
nixos-rebuild dry-build --flake .#m3-ares
home-manager dry-activate --flake .#m3tam3re@m3-ares

Expected: Loads base + coding + desktop + gaming + media

  • Step 2: Test m3-atlas (Server with coding only)
# Build and test on m3-atlas
nixos-rebuild dry-build --flake .#m3-atlas
home-manager dry-activate --flake .#m3tam3re@m3-atlas

Expected: Loads base + coding + server (no desktop modules)

  • Step 3: Test assertion (should fail)
# This SHOULD fail - desktop and server together
m3ta.context = "desktop";
m3ta.profiles = [ "coding" ];
# Nix should throw assertion error
  • Step 4: Commit Phase 4
git commit -m "test: validate profile combinations on all hosts

- m3-ares: base + coding + desktop + gaming + media ✓
- m3-atlas: base + coding + server ✓
- Constraint assertion working ✓"

Phase 5: Cleanup

Task 5: Remove Old Structure

Files:

  • Delete: home/features.old/ (after verification)

  • Step 1: Verify no broken imports

# Search for any references to old paths
grep -r "home/features" --include="*.nix"

Expected: No results

  • Step 2: Delete old directory
git rm -rf home/features.old
  • Step 3: Final format and check
nix fmt
nix flake check
  • Step 4: Final commit
git commit -m "chore: remove old features directory

Cleanup complete. New structure:
- home/base/ (always loaded)
- home/coding/ (profile-independent)
- home/profiles/ (gaming, media)
- home/desktop/ (context=desktop)
- home/server/ (context=server)"

Summary

Phase Tasks Description
1 1 Create new directory structure
2 2 Implement profile system with constraints
3 3 Migrate existing features
4 4 Test profile combinations
5 5 Remove old structure

Total: 5 tasks, ~22 steps

Expected Duration: 2-4 hours (depending on migration complexity)


Migration Notes

  1. NeoVim Config: Already in nixpkgs, reference via inputs.m3ta-nixpkgs.packages.neovim-config

  2. Agent-System: Already in nixpkgs, reference via inputs.m3ta-nixpkgs.homeModules.coding.agents

  3. Zed Remote: Desktop-only feature, works via SSH. No server-side installation needed.

  4. Fish Shell: Removed from base (Nushell is primary). Can be added as optional profile if needed.

  5. Feature Flags: Old features.*.enable options → New profile lists m3ta.profiles = [ "gaming" "media" ]