# Nix Home Manager Flake Architecture ## Overview This document defines the architecture for migrating from chezmoi to Nix Home Manager with flakes. The design supports two target environments (personal and work) while maintaining a clean, modular, and extensible structure. --- ## 1. Directory Structure ``` . ├── flake.nix # Main flake entry point ├── flake.lock # Locked dependencies ├── README.md # Setup and usage documentation │ ├── hosts/ # Machine-specific configurations │ ├── personal/ │ │ └── default.nix # Personal machine darwin config │ └── work/ │ └── default.nix # Work machine darwin config │ ├── home/ # Home Manager configurations │ ├── default.nix # Shared home configuration │ ├── personal.nix # Personal profile overrides │ └── work.nix # Work profile overrides │ ├── modules/ # Reusable Nix modules │ ├── darwin/ # macOS-specific modules │ │ ├── default.nix # Common darwin settings │ │ ├── homebrew.nix # Homebrew cask management │ │ └── system.nix # System preferences │ │ │ └── home/ # Home Manager modules │ ├── shell/ │ │ ├── default.nix # Shell module entry point │ │ ├── zsh.nix # Zsh configuration │ │ ├── starship.nix # Starship prompt │ │ ├── atuin.nix # Shell history │ │ ├── direnv.nix # Directory environments │ │ └── aliases.nix # Shell aliases │ │ │ ├── git/ │ │ ├── default.nix # Git module entry point │ │ ├── config.nix # Core git configuration │ │ └── identities.nix # Git identity management │ │ │ ├── ssh/ │ │ ├── default.nix # SSH module entry point │ │ └── hosts.nix # SSH host configurations │ │ │ ├── terminal/ │ │ ├── default.nix # Terminal module entry point │ │ ├── tmux.nix # Tmux configuration │ │ └── neovim.nix # Neovim configuration │ │ │ ├── packages/ │ │ ├── default.nix # Package module entry point │ │ ├── cli.nix # CLI tools │ │ ├── development.nix # Development tools │ │ └── kubernetes.nix # K8s tools │ │ │ └── apps/ │ ├── default.nix # Apps module entry point │ └── aerospace.nix # Window manager config │ ├── lib/ # Helper functions │ └── default.nix # Utility functions │ ├── overlays/ # Nixpkgs overlays │ └── default.nix # Custom package overlays │ ├── secrets/ # Encrypted secrets (sops-nix) │ ├── secrets.yaml # Encrypted secrets file │ └── .sops.yaml # SOPS configuration │ └── docs/ # Documentation ├── migration-analysis.md # Migration analysis └── nix-architecture.md # This document ``` ### Design Rationale 1. **`hosts/`** - Machine-level configurations using nix-darwin. Each host can have unique system settings while sharing common darwin modules. 2. **`home/`** - Profile-specific home-manager configurations. The [`default.nix`](home/default.nix) contains shared settings, while [`personal.nix`](home/personal.nix) and [`work.nix`](home/work.nix) contain profile-specific overrides. 3. **`modules/`** - Reusable, composable modules organized by functionality. Split into `darwin/` (system-level) and `home/` (user-level) to maintain clear separation. 4. **`lib/`** - Helper functions for reducing boilerplate and improving maintainability. 5. **`overlays/`** - Custom package modifications or additions to nixpkgs. 6. **`secrets/`** - Encrypted secrets managed by sops-nix for sensitive data like API tokens. --- ## 2. Flake Structure ### 2.1 Inputs ```nix { inputs = { # Core dependencies nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable"; # Home Manager for user environment home-manager = { url = "github:nix-community/home-manager"; inputs.nixpkgs.follows = "nixpkgs"; }; # nix-darwin for macOS system configuration nix-darwin = { url = "github:LnL7/nix-darwin"; inputs.nixpkgs.follows = "nixpkgs"; }; # Secrets management sops-nix = { url = "github:Mic92/sops-nix"; inputs.nixpkgs.follows = "nixpkgs"; }; # Optional: Homebrew management through nix-darwin nix-homebrew = { url = "github:zhaofengli-wip/nix-homebrew"; }; }; } ``` ### 2.2 Outputs Structure ```nix { outputs = { self, nixpkgs, home-manager, nix-darwin, sops-nix, nix-homebrew, ... }@inputs: let # Supported systems (macOS for now, Linux can be added later) systems = [ "aarch64-darwin" "x86_64-darwin" ]; # Helper to generate per-system attributes forAllSystems = nixpkgs.lib.genAttrs systems; # Common special args passed to all modules specialArgs = { inherit inputs; }; in { # Darwin (macOS) system configurations darwinConfigurations = { # Personal machine configuration "personal" = nix-darwin.lib.darwinSystem { system = "aarch64-darwin"; inherit specialArgs; modules = [ ./hosts/personal ./modules/darwin home-manager.darwinModules.home-manager { home-manager = { useGlobalPkgs = true; useUserPackages = true; extraSpecialArgs = specialArgs; users.alice = { ... }: { imports = [ ./home ./home/personal.nix ]; }; }; } ]; }; # Work machine configuration "work" = nix-darwin.lib.darwinSystem { system = "aarch64-darwin"; inherit specialArgs; modules = [ ./hosts/work ./modules/darwin home-manager.darwinModules.home-manager { home-manager = { useGlobalPkgs = true; useUserPackages = true; extraSpecialArgs = specialArgs; users.alice = { ... }: { imports = [ ./home ./home/work.nix ]; }; }; } ]; }; }; # Standalone Home Manager configurations (for non-darwin systems) homeConfigurations = { "personal@linux" = home-manager.lib.homeManagerConfiguration { pkgs = nixpkgs.legacyPackages.x86_64-linux; extraSpecialArgs = specialArgs; modules = [ ./home ./home/personal.nix ]; }; "work@linux" = home-manager.lib.homeManagerConfiguration { pkgs = nixpkgs.legacyPackages.x86_64-linux; extraSpecialArgs = specialArgs; modules = [ ./home ./home/work.nix ]; }; }; # Development shells for this repository devShells = forAllSystems (system: let pkgs = nixpkgs.legacyPackages.${system}; in { default = pkgs.mkShell { packages = with pkgs; [ nixfmt sops age ]; }; } ); }; } ``` ### 2.3 Key Design Decisions 1. **nix-darwin as primary entry point** - On macOS, use `darwinConfigurations` which integrates home-manager as a module. This allows managing both system-level settings (Homebrew, system preferences) and user-level dotfiles in one command. 2. **Standalone homeConfigurations** - Provided for future Linux support or cases where nix-darwin isn't desired. 3. **`useGlobalPkgs` and `useUserPackages`** - Ensures home-manager uses the same nixpkgs instance as darwin, avoiding duplicate package downloads. 4. **`specialArgs`** - Passes inputs to all modules, enabling access to flake inputs anywhere in the configuration. --- ## 3. Module Design ### 3.1 Module Architecture Diagram ```mermaid graph TB subgraph Flake F[flake.nix] end subgraph Darwin Configs DP[hosts/personal] DW[hosts/work] end subgraph Darwin Modules DM[modules/darwin/default.nix] HB[modules/darwin/homebrew.nix] SYS[modules/darwin/system.nix] end subgraph Home Configs HC[home/default.nix] HP[home/personal.nix] HW[home/work.nix] end subgraph Home Modules SH[modules/home/shell] GIT[modules/home/git] SSH[modules/home/ssh] TM[modules/home/terminal] PKG[modules/home/packages] APP[modules/home/apps] end F --> DP F --> DW DP --> DM DW --> DM DM --> HB DM --> SYS DP --> HC DW --> HC DP --> HP DW --> HW HC --> SH HC --> GIT HC --> SSH HC --> TM HC --> PKG HC --> APP ``` ### 3.2 Shared vs Profile-Specific Content | Component | Shared | Personal-Specific | Work-Specific | |-----------|--------|-------------------|---------------| | **Shell** | zsh, starship, atuin, aliases | - | - | | **Git** | Core config, aliases, delta | Personal signing key, personal email | Work signing key, work email, zeronorth config | | **SSH** | 1Password agent, control master | github-private host | github-zeronorth host | | **Packages** | CLI tools, dev tools, k8s | Personal apps (darktable, proton, steam) | - | | **Homebrew Casks** | 1password, ghostty, raycast | signal, proton-*, steam | - | | **Project Configs** | - | ~/Projects/.gitconfig | ~/Projects/private/.gitconfig, ~/Projects/zeronorth/.gitconfig | ### 3.3 Module Option Pattern Each module should follow this pattern for configurability: ```nix # modules/home/git/default.nix { config, lib, pkgs, ... }: with lib; let cfg = config.modules.git; in { options.modules.git = { enable = mkEnableOption "Git configuration"; userName = mkOption { type = types.str; default = "Morten Olsen"; description = "Git user name"; }; userEmail = mkOption { type = types.str; description = "Git user email"; }; signing = { enable = mkEnableOption "Git commit signing"; key = mkOption { type = types.str; description = "SSH signing key"; }; }; includes = mkOption { type = types.listOf (types.submodule { options = { condition = mkOption { type = types.str; }; path = mkOption { type = types.str; }; }; }); default = []; description = "Conditional git config includes"; }; }; config = mkIf cfg.enable { programs.git = { enable = true; userName = cfg.userName; userEmail = cfg.userEmail; signing = mkIf cfg.signing.enable { key = cfg.signing.key; signByDefault = true; }; extraConfig = { gpg.format = "ssh"; gpg.ssh.program = "/Applications/1Password.app/Contents/MacOS/op-ssh-sign"; # ... other shared config }; includes = cfg.includes; }; }; } ``` ### 3.4 Module Implementations #### Shell Module ([`modules/home/shell/default.nix`](modules/home/shell/default.nix)) ```nix { config, lib, pkgs, ... }: { imports = [ ./zsh.nix ./starship.nix ./atuin.nix ./direnv.nix ./aliases.nix ]; options.modules.shell = { enable = lib.mkEnableOption "Shell configuration"; }; config = lib.mkIf config.modules.shell.enable { # Enable all shell sub-modules modules.shell.zsh.enable = true; modules.shell.starship.enable = true; modules.shell.atuin.enable = true; modules.shell.direnv.enable = true; }; } ``` #### Git Module ([`modules/home/git/default.nix`](modules/home/git/default.nix)) ```nix { config, lib, pkgs, ... }: { imports = [ ./config.nix ./identities.nix ]; options.modules.git = { enable = lib.mkEnableOption "Git configuration"; profile = lib.mkOption { type = lib.types.enum [ "personal" "work" ]; description = "Git profile to use"; }; }; } ``` #### SSH Module ([`modules/home/ssh/default.nix`](modules/home/ssh/default.nix)) ```nix { config, lib, pkgs, ... }: { imports = [ ./hosts.nix ]; options.modules.ssh = { enable = lib.mkEnableOption "SSH configuration"; onePasswordAgent = lib.mkOption { type = lib.types.bool; default = true; description = "Use 1Password SSH agent"; }; }; config = lib.mkIf config.modules.ssh.enable { programs.ssh = { enable = true; controlMaster = "auto"; controlPath = "/tmp/ssh-%r@%h:%p"; forwardAgent = true; extraConfig = lib.mkIf config.modules.ssh.onePasswordAgent '' IdentityAgent "~/Library/Group Containers/2BUA8C4S2C.com.1password/t/agent.sock" ''; includes = [ "~/.colima/ssh_config" ]; }; }; } ``` #### Homebrew Module ([`modules/darwin/homebrew.nix`](modules/darwin/homebrew.nix)) ```nix { config, lib, pkgs, ... }: let cfg = config.modules.homebrew; in { options.modules.homebrew = { enable = lib.mkEnableOption "Homebrew management"; personalCasks = lib.mkOption { type = lib.types.bool; default = false; description = "Include personal-only casks"; }; }; config = lib.mkIf cfg.enable { homebrew = { enable = true; onActivation = { autoUpdate = true; cleanup = "zap"; upgrade = true; }; taps = [ "nikitabobko/tap" "coder/coder" "fluxcd/tap" "sst/tap" ]; casks = [ "1password" "1password-cli" "aerospace" "dbeaver-community" "ghostty" "home-assistant" "jellyfin-media-player" "lens" "localsend" "mqtt-explorer" "obsidian" "ollama-app" "raycast" ] ++ lib.optionals cfg.personalCasks [ "darktable" "signal" "proton-mail-bridge" "proton-pass" "protonvpn" "steam" ]; }; }; } ``` ### 3.5 Secrets Management For sensitive data, use sops-nix with age encryption: ```nix # secrets/.sops.yaml keys: - &personal age1... # Personal machine key - &work age1... # Work machine key creation_rules: - path_regex: secrets/personal\.yaml$ key_groups: - age: - *personal - path_regex: secrets/work\.yaml$ key_groups: - age: - *work - path_regex: secrets/secrets\.yaml$ key_groups: - age: - *personal - *work ``` For 1Password integration (already used in current setup), reference secrets directly: ```nix # In modules that need secrets home.sessionVariables = { NODE_AUTH_TOKEN = "op://Employee/Github NPM Token/password"; }; ``` --- ## 4. Configuration Profiles ### 4.1 Shared Configuration ([`home/default.nix`](home/default.nix)) ```nix { config, lib, pkgs, ... }: { imports = [ ../modules/home/shell ../modules/home/git ../modules/home/ssh ../modules/home/terminal ../modules/home/packages ../modules/home/apps ]; home = { stateVersion = "24.05"; sessionVariables = { EDITOR = "nvim"; LANG = "en_US.UTF-8"; }; sessionPath = [ "$HOME/.local/bin" "$HOME/.cargo/bin" "/opt/homebrew/bin" ]; }; # Enable shared modules modules = { shell.enable = true; git.enable = true; ssh.enable = true; terminal.enable = true; packages.enable = true; apps.enable = true; }; } ``` ### 4.2 Personal Profile ([`home/personal.nix`](home/personal.nix)) ```nix { config, lib, pkgs, ... }: { # Git configuration for personal modules.git = { profile = "personal"; userEmail = "fbtijfdq@void.black"; signing.key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFaIAP/ZJ7+7jeR44e1yIJjfQAB6MN351LDKJAXVF62P"; includes = [ { condition = "gitdir:~/Projects/"; path = "~/Projects/.gitconfig"; } ]; }; # SSH hosts for personal modules.ssh.hosts = { github-private = { hostname = "ssh.github.com"; user = "git"; port = 443; identityFile = "~/.ssh/keys/github-private.pub"; }; gitea-ssh-olsen-cloud = { hostname = "gitea-ssh.olsen.cloud"; user = "git"; port = 2202; identityFile = "~/.ssh/keys/github-private.pub"; }; }; # Personal-only packages modules.packages.personal = true; # Project-specific git config home.file.".Projects/.gitconfig".text = '' [user] email = fbtijfdq@void.black name = Morten Olsen signingkey = ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFaIAP/ZJ7+7jeR44e1yIJjfQAB6MN351LDKJAXVF62P [commit] gpgsign = true [gpg] format = ssh [gpg "ssh"] program = "/Applications/1Password.app/Contents/MacOS/op-ssh-sign" [url "ssh://git@ssh-gitea.olsen.cloud:2205/"] insteadOf = "https://gitea.olsen.cloud/" [url "git@github-private:"] insteadOf = https://github.com/ ''; } ``` ### 4.3 Work Profile ([`home/work.nix`](home/work.nix)) ```nix { config, lib, pkgs, ... }: { # Git configuration for work modules.git = { profile = "work"; userEmail = "fbtijfdq@void.black"; # Default email signing.key = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILAzuPy7D/54GxMq9Zhz0CUjaDnEQ6RkQ/yqVYl7U55k"; includes = [ { condition = "gitdir:~/Projects/private/"; path = "~/Projects/private/.gitconfig"; } { condition = "gitdir:~/Projects/zeronorth/"; path = "~/Projects/zeronorth/.gitconfig"; } ]; }; # SSH hosts for work modules.ssh.hosts = { github-private = { hostname = "ssh.github.com"; user = "git"; port = 443; identityFile = "~/.ssh/keys/github-private.pub"; }; github-zeronorth = { hostname = "ssh.github.com"; user = "git"; port = 443; identityFile = "~/.ssh/keys/github-zeronorth.pub"; }; gitea-ssh-olsen-cloud = { hostname = "gitea-ssh.olsen.cloud"; user = "git"; port = 2202; identityFile = "~/.ssh/keys/github-private.pub"; }; }; # Work-only packages (none currently) modules.packages.work = true; # Project-specific git configs home.file = { "Projects/private/.gitconfig".text = '' [user] email = fbtijfdq@void.black name = Morten Olsen signingkey = ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILAzuPy7D/54GxMq9Zhz0CUjaDnEQ6RkQ/yqVYl7U55k [commit] gpgsign = true [gpg] format = ssh [gpg "ssh"] program = "/Applications/1Password.app/Contents/MacOS/op-ssh-sign" [url "ssh://git@ssh-gitea.olsen.cloud:2205/"] insteadOf = "https://gitea.olsen.cloud/" [url "git@github-private:"] insteadOf = https://github.com/ ''; "Projects/zeronorth/.gitconfig".text = '' [user] email = morten.olsen@zeronorth.com name = Morten Olsen signingkey = ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKDbZITpz5QrVIxPn9gKVWMPK+3W3YZZGszFOQvO/h7M [commit] gpgsign = true [gpg] format = ssh [gpg "ssh"] program = "/Applications/1Password.app/Contents/MacOS/op-ssh-sign" [url "git@github-zeronorth:"] insteadOf = https://github.com/ ''; "Projects/zeronorth/.envrc".text = '' export NODE_AUTH_TOKEN="op://Employee/Github NPM Token/password" export NPM_TOKEN="op://Employee/Github NPM Token/password" export NPM_GITHUB_TOKEN="op://Employee/Github NPM Token/password" export AWS_PROFILE=zntest ''; }; } ``` ### 4.4 Profile Selection Flow ```mermaid flowchart TD A[New Machine Setup] --> B{Machine Type?} B -->|Personal| C[darwin-rebuild switch --flake .#personal] B -->|Work| D[darwin-rebuild switch --flake .#work] C --> E[Loads hosts/personal + home/personal.nix] D --> F[Loads hosts/work + home/work.nix] E --> G[Personal SSH keys, git config, packages] F --> H[Work SSH keys, git config, zeronorth setup] G --> I[System Ready] H --> I ``` --- ## 5. Usage Patterns ### 5.1 Initial Setup on New Machine #### Prerequisites 1. Install Nix with flakes enabled: ```bash curl -L https://nixos.org/nix/install | sh ``` 2. Enable flakes in Nix configuration: ```bash mkdir -p ~/.config/nix echo "experimental-features = nix-command flakes" >> ~/.config/nix/nix.conf ``` #### Personal Machine Setup ```bash # Clone the dotfiles repository git clone https://github.com/username/dotfiles.git ~/.dotfiles cd ~/.dotfiles # Build and activate the personal configuration nix build .#darwinConfigurations.personal.system ./result/sw/bin/darwin-rebuild switch --flake .#personal # Subsequent rebuilds darwin-rebuild switch --flake .#personal ``` #### Work Machine Setup ```bash # Clone the dotfiles repository git clone https://github.com/username/dotfiles.git ~/.dotfiles cd ~/.dotfiles # Build and activate the work configuration nix build .#darwinConfigurations.work.system ./result/sw/bin/darwin-rebuild switch --flake .#work # Subsequent rebuilds darwin-rebuild switch --flake .#work ``` ### 5.2 Switching Configurations If you need to switch a machine from personal to work (or vice versa): ```bash # Switch to work configuration darwin-rebuild switch --flake .#work # Switch back to personal configuration darwin-rebuild switch --flake .#personal ``` **Note:** Switching profiles will change git configs, SSH hosts, and installed packages. Some manual cleanup may be needed for files that were created by the previous profile. ### 5.3 Updating Configuration #### After Editing Nix Files ```bash # Rebuild and switch to new configuration darwin-rebuild switch --flake .#personal # or .#work # Build without switching (for testing) darwin-rebuild build --flake .#personal ``` #### Updating Flake Inputs ```bash # Update all inputs nix flake update # Update specific input nix flake lock --update-input nixpkgs nix flake lock --update-input home-manager # Rebuild after update darwin-rebuild switch --flake .#personal ``` ### 5.4 Common Commands Reference | Command | Description | |---------|-------------| | `darwin-rebuild switch --flake .#personal` | Apply personal configuration | | `darwin-rebuild switch --flake .#work` | Apply work configuration | | `darwin-rebuild build --flake .#personal` | Build without applying | | `nix flake update` | Update all flake inputs | | `nix flake check` | Validate flake configuration | | `nix repl --expr 'builtins.getFlake "."'` | Interactive debugging | | `darwin-rebuild --rollback` | Rollback to previous generation | | `nix-collect-garbage -d` | Clean up old generations | ### 5.5 Development Workflow ```bash # Enter development shell with tools for editing this repo nix develop # Format Nix files nixfmt **/*.nix # Check configuration validity nix flake check ``` --- ## 6. Future Extensibility ### 6.1 Adding Linux Support The architecture already includes placeholder `homeConfigurations` for Linux. To fully support Linux: 1. Add Linux-specific modules in `modules/home/` with platform conditionals: ```nix { config, lib, pkgs, ... }: { config = lib.mkMerge [ # Common configuration { ... } # macOS-specific (lib.mkIf pkgs.stdenv.isDarwin { ... }) # Linux-specific (lib.mkIf pkgs.stdenv.isLinux { ... }) ]; } ``` 2. Create Linux host configurations in `hosts/linux/`. 3. Use `homeConfigurations` for standalone home-manager on Linux. ### 6.2 Adding New Machines To add a new machine configuration: 1. Create a new directory under `hosts/`: ``` hosts/ ├── personal/ ├── work/ └── new-machine/ └── default.nix ``` 2. Add the configuration to `flake.nix`: ```nix darwinConfigurations."new-machine" = nix-darwin.lib.darwinSystem { # ... }; ``` ### 6.3 Adding New Modules To add a new module (e.g., for a new application): 1. Create the module file: ``` modules/home/apps/new-app.nix ``` 2. Import it in the parent module: ```nix # modules/home/apps/default.nix imports = [ ./aerospace.nix ./new-app.nix ]; ``` 3. Add options and configuration following the established pattern. --- ## 7. Migration Checklist When implementing this architecture, follow this order: - [ ] Create basic flake.nix with inputs - [ ] Set up directory structure - [ ] Implement darwin modules (homebrew, system) - [ ] Implement shell modules (zsh, starship, atuin) - [ ] Implement git modules with profile support - [ ] Implement SSH modules - [ ] Implement terminal modules (tmux) - [ ] Implement package modules - [ ] Implement apps modules (aerospace) - [ ] Create personal profile configuration - [ ] Create work profile configuration - [ ] Set up secrets management (sops-nix) - [ ] Test on personal machine - [ ] Test on work machine - [ ] Document any manual steps - [ ] Remove chezmoi after successful migration --- ## 8. Summary This architecture provides: 1. **Clean separation of concerns** - Darwin system config, home-manager user config, and reusable modules are clearly separated. 2. **Profile-based configuration** - Personal and work environments are distinct profiles that share common modules but override specific settings. 3. **Modular design** - Each functional area (shell, git, ssh, packages) is a self-contained module with configurable options. 4. **macOS-first with extensibility** - Designed for macOS with nix-darwin, but structured to easily add Linux support later. 5. **Declarative package management** - CLI tools via nixpkgs, GUI apps via Homebrew casks managed through nix-darwin. 6. **Secrets handling** - Support for both sops-nix encrypted secrets and 1Password CLI references. 7. **Simple usage patterns** - Single command to apply configuration, easy switching between profiles. The migration from chezmoi to this Nix-based setup will provide reproducible, declarative configuration management with the full power of the Nix ecosystem. --- ## 9. Final Implementation This section documents the actual implemented structure, which may differ slightly from the original design above. ### 9.1 Implemented Directory Structure ``` . ├── flake.nix # Main flake entry point ├── flake.lock # Locked dependencies ├── README.md # Setup and usage documentation │ ├── home/ # Home Manager configurations │ ├── default.nix # Shared home configuration │ ├── personal.nix # Personal profile overrides │ └── work.nix # Work profile overrides │ ├── hosts/ # Machine-specific nix-darwin configs │ ├── personal/ │ │ └── default.nix # Personal machine darwin settings │ └── work/ │ └── default.nix # Work machine darwin settings │ ├── modules/ # Reusable Nix modules │ ├── darwin/ │ │ └── homebrew.nix # Homebrew cask management │ │ │ └── home/ # Home Manager modules │ ├── apps.nix # Application configs (aerospace, jellyfin-tui) │ ├── git.nix # Git configuration with signing │ ├── git-files.nix # Project-specific git configs │ ├── packages.nix # CLI packages via Nix │ ├── shell.nix # Shell environment (zsh, starship, etc.) │ ├── ssh.nix # SSH configuration with 1Password │ └── tmux.nix # Tmux configuration │ └── docs/ # Documentation ├── migration-analysis.md # Original chezmoi analysis ├── nix-architecture.md # This document └── usage.md # Detailed usage guide ``` ### 9.2 Module Reference #### Darwin Modules | Module | File | Purpose | |--------|------|---------| | **Homebrew** | [`modules/darwin/homebrew.nix`](../modules/darwin/homebrew.nix) | Manages Homebrew taps, formulae, and casks declaratively | #### Home Manager Modules | Module | File | Purpose | |--------|------|---------| | **Shell** | [`modules/home/shell.nix`](../modules/home/shell.nix) | Zsh, Starship, Atuin, Direnv, Zoxide, FZF, Pyenv | | **Packages** | [`modules/home/packages.nix`](../modules/home/packages.nix) | CLI tools and development packages | | **Git** | [`modules/home/git.nix`](../modules/home/git.nix) | Git configuration with delta, signing, aliases | | **Git Files** | [`modules/home/git-files.nix`](../modules/home/git-files.nix) | Project-specific gitconfig files | | **SSH** | [`modules/home/ssh.nix`](../modules/home/ssh.nix) | SSH with 1Password agent, host configurations | | **Tmux** | [`modules/home/tmux.nix`](../modules/home/tmux.nix) | Tmux with vim navigation, plugins | | **Apps** | [`modules/home/apps.nix`](../modules/home/apps.nix) | Aerospace window manager, Jellyfin TUI | ### 9.3 Module Configuration Options #### `modules.homebrew` (Darwin) | Option | Type | Default | Description | |--------|------|---------|-------------| | `enable` | bool | `false` | Enable Homebrew management | | `casks.shared` | list of str | (see module) | Casks installed on all machines | | `casks.personal` | list of str | (see module) | Casks installed only on personal machines | | `casks.enablePersonal` | bool | `false` | Whether to install personal casks | | `brews` | list of str | (see module) | Homebrew formulae to install | | `taps` | list of str | (see module) | Homebrew taps to add | | `cleanup` | enum | `"zap"` | Cleanup behavior: `"none"`, `"uninstall"`, `"zap"` | #### `modules.ssh` (Home) | Option | Type | Default | Description | |--------|------|---------|-------------| | `enable` | bool | `false` | Enable SSH configuration | | `enableGitHubPrivate` | bool | `false` | Enable github-private host | | `enableGitHubZeronorth` | bool | `false` | Enable github-zeronorth host | | `enableCoder` | bool | `false` | Enable Coder SSH hosts | | `enableGiteaPrivate` | bool | `false` | Enable gitea-ssh.olsen.cloud host | | `githubPrivateKeyPath` | str | `"~/.ssh/keys/github-private.pub"` | Path to GitHub private key | | `githubZeronorthKeyPath` | str | `"~/.ssh/keys/github-zeronorth.pub"` | Path to GitHub Zeronorth key | #### `modules.git` (Home) | Option | Type | Default | Description | |--------|------|---------|-------------| | `enable` | bool | `false` | Enable Git configuration | | `userName` | str | `"Morten Olsen"` | Git user name | | `userEmail` | str | (required) | Git user email | | `signingKey` | str | (required) | SSH signing key (public key) | | `includes` | list of {condition, path} | `[]` | Conditional includes for project configs | #### `modules.gitFiles` (Home) | Option | Type | Default | Description | |--------|------|---------|-------------| | `enable` | bool | `false` | Enable project-specific git files | | `personal.enable` | bool | `false` | Create ~/Projects/.gitconfig | | `personal.email` | str | (example) | Email for personal projects | | `personal.signingKey` | str | (required) | Signing key for personal projects | | `private.enable` | bool | `false` | Create ~/Projects/private/.gitconfig | | `private.email` | str | (example) | Email for private projects | | `private.signingKey` | str | (required) | Signing key for private projects | | `zeronorth.enable` | bool | `false` | Create ~/Projects/zeronorth/.gitconfig | | `zeronorth.email` | str | (example) | Email for zeronorth projects | | `zeronorth.signingKey` | str | (required) | Signing key for zeronorth projects | #### `modules.apps` (Home) | Option | Type | Default | Description | |--------|------|---------|-------------| | `enable` | bool | `false` | Enable application configurations | | `aerospace.enable` | bool | `true` | Enable Aerospace window manager config | | `jellyfin-tui.enable` | bool | `false` | Enable Jellyfin TUI config | | `jellyfin-tui.serverUrl` | str | `""` | Jellyfin server URL | | `jellyfin-tui.serverName` | str | `"Home Server"` | Display name for server | | `jellyfin-tui.username` | str | `""` | Jellyfin username | | `jellyfin-tui.passwordFile` | str | `""` | Path to password file | ### 9.4 Profile Configuration Summary #### Personal Profile ([`home/personal.nix`](../home/personal.nix)) ```nix modules.git = { enable = true; userEmail = "alice@personal.example.com"; signingKey = "ssh-ed25519 AAAAC3..."; includes = [{ condition = "gitdir:~/Projects/"; path = "~/Projects/.gitconfig"; }]; }; modules.gitFiles = { enable = true; personal = { enable = true; email = "..."; signingKey = "..."; }; }; modules.ssh = { enableGitHubPrivate = true; enableGiteaPrivate = true; enableGitHubZeronorth = false; enableCoder = false; }; modules.apps = { jellyfin-tui = { enable = true; serverUrl = "..."; username = "..."; }; }; ``` #### Work Profile ([`home/work.nix`](../home/work.nix)) ```nix modules.git = { enable = true; userEmail = "alice@work.example.com"; signingKey = "ssh-ed25519 AAAAC3..."; includes = [ { condition = "gitdir:~/Projects/private/"; path = "~/Projects/private/.gitconfig"; } { condition = "gitdir:~/Projects/zeronorth/"; path = "~/Projects/zeronorth/.gitconfig"; } ]; }; modules.gitFiles = { enable = true; private = { enable = true; email = "..."; signingKey = "..."; }; zeronorth = { enable = true; email = "..."; signingKey = "..."; }; }; modules.ssh = { enableGitHubPrivate = true; enableGitHubZeronorth = true; enableCoder = true; enableGiteaPrivate = false; }; ``` ### 9.5 Packages Installed #### Via Nix (from [`modules/home/packages.nix`](../modules/home/packages.nix)) | Category | Packages | |----------|----------| | **Modern CLI** | bat, eza, fd, ripgrep, delta | | **File Utils** | jq, yq, tree, rsync, unzip, curl, wget, watch | | **Git** | git, gh, jujutsu, lazygit | | **Development** | neovim, tmux, nodejs_22, deno, rustup, python313, uv, gnumake, cmake | | **Containers** | docker, docker-buildx, docker-compose, colima | | **Kubernetes** | kubectl, kubernetes-helm, helmfile, k9s, istioctl, fluxcd | | **Infrastructure** | terraform, ansible, sshpass, awscli2 | | **Media** | ffmpeg | | **Security** | gnupg, age, sops | | **Misc** | graphviz, tree-sitter, htop, ncdu, tldr, nixfmt-rfc-style, nil | #### Via Homebrew Casks (from [`modules/darwin/homebrew.nix`](../modules/darwin/homebrew.nix)) **Shared (all machines):** - 1password, 1password-cli - ghostty, dbeaver-community, lens - aerospace - raycast, obsidian - jellyfin-media-player, ollama-app - localsend, mqtt-explorer, home-assistant **Personal only:** - darktable - proton-mail-bridge, proton-pass, protonvpn - signal - steam #### Via Homebrew Formulae - coder/coder/coder - fluxcd/tap/flux - sst/tap/opencode - tree-sitter-cli ### 9.6 Key Differences from Original Design 1. **Simplified module structure** - Instead of deeply nested modules (e.g., `modules/home/shell/zsh.nix`), the implementation uses flatter files (e.g., `modules/home/shell.nix`) for simplicity. 2. **No sops-nix** - Secrets are managed via 1Password CLI references rather than sops-nix encrypted files. 3. **No lib/ directory** - Helper functions are defined inline in modules rather than in a separate lib directory. 4. **No overlays/** - No custom package overlays are currently needed. 5. **Combined shell module** - All shell-related configuration (zsh, starship, atuin, direnv, zoxide, fzf, pyenv) is in a single `shell.nix` file. 6. **Separate git-files module** - Project-specific gitconfig files are managed in a dedicated `git-files.nix` module rather than inline in profile files. ### 9.7 Migration Status The following chezmoi files have been migrated: | Chezmoi File | Nix Module | Status | |--------------|------------|--------| | `dot_zshrc` | `modules/home/shell.nix` | ✅ Migrated | | `dot_tmux.conf` | `modules/home/tmux.nix` | ✅ Migrated | | `dot_gitconfig.tmpl` | `modules/home/git.nix` | ✅ Migrated | | `dot_gitignore_global` | `modules/home/git.nix` | ✅ Migrated | | `dot_Brewfile.tmpl` | `modules/darwin/homebrew.nix` + `modules/home/packages.nix` | ✅ Migrated | | `dot_aerospace.toml` | `modules/home/apps.nix` | ✅ Migrated | | `dot_config/atuin/config.toml` | `modules/home/shell.nix` | ✅ Migrated | | `dot_shellrc/rc.d/*` | `modules/home/shell.nix` | ✅ Migrated | | `dot_ssh/config` | `modules/home/ssh.nix` | ✅ Migrated | | `dot_ssh/config.d/*` | `modules/home/ssh.nix` | ✅ Migrated | | `private_Projects/*` | `modules/home/git-files.nix` | ✅ Migrated | | `private_Library/.../jellyfin-tui/*` | `modules/home/apps.nix` | ✅ Migrated | The original chezmoi files are kept in the repository for reference during the transition period.