|
| 1 | +# WARP.md |
| 2 | + |
| 3 | +This file provides guidance to WARP (warp.dev) when working with code in this repository. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +This is a declarative macOS dotfiles repository using nix-darwin and home-manager with a Nix flake architecture. It manages system preferences, packages, and user environments across multiple machines (personal and work MacBooks) with shared configuration and host-specific overrides. |
| 8 | + |
| 9 | +## Essential Commands |
| 10 | + |
| 11 | +```shell |
| 12 | +# Development workflow |
| 13 | +just fmt # Format Nix files with alejandra |
| 14 | +just lint # Lint with statix |
| 15 | +just check # Run all checks (format, lint, deadcode) |
| 16 | +just build # Build configuration without applying |
| 17 | + |
| 18 | +# Apply changes |
| 19 | +just switch # Apply configuration (requires sudo) |
| 20 | + |
| 21 | +# Maintenance |
| 22 | +just update # Update flake inputs |
| 23 | +just gc # Garbage collect (keeps last 7 days) |
| 24 | +just generations # List system generations |
| 25 | +just rollback # Rollback to previous generation |
| 26 | + |
| 27 | +# Debugging |
| 28 | +just diff # Show what would change (requires nvd package) |
| 29 | +just validate # Validate flake |
| 30 | +just repl # Open nix repl with flake loaded |
| 31 | +``` |
| 32 | + |
| 33 | +## Critical Constraints |
| 34 | + |
| 35 | +1. **Git tracking required**: Nix flakes only see Git-tracked files. Always run `git add` on new files before building, otherwise you'll get "path does not exist" errors. |
| 36 | + |
| 37 | +2. **No `xdg.userDirs` module**: This is Linux-only and causes assertion failures on macOS. Do not use it. |
| 38 | + |
| 39 | +3. **Fish shell setup**: After `just switch`, the user must manually run `chsh -s /run/current-system/sw/bin/fish` to set fish as the default shell (logout/login required). |
| 40 | + |
| 41 | +4. **1Password SSH agent**: Git signing uses `/Applications/1Password.app/Contents/MacOS/op-ssh-sign`. Ensure 1Password is installed and SSH agent is enabled. |
| 42 | + |
| 43 | +5. **Draft file convention**: Prefix files/directories with `_` to exclude them from auto-discovery (e.g., `_draft.nix`, `_experimental/`). |
| 44 | + |
| 45 | +## Architecture |
| 46 | + |
| 47 | +### Entry Points |
| 48 | + |
| 49 | +- **`flake.nix`**: Flake definition with inputs, outputs, and `mkDarwinConfig` helper |
| 50 | +- **`darwin.nix`**: System-level nix-darwin configuration (imports `modules/`) |
| 51 | +- **`home.nix`**: User-level home-manager configuration (imports `programs/`) |
| 52 | + |
| 53 | +### Directory Structure |
| 54 | + |
| 55 | +``` |
| 56 | +dotfiles/ |
| 57 | +├── flake.nix # Flake inputs/outputs, mkDarwinConfig helper |
| 58 | +├── darwin.nix # Shared darwin system config |
| 59 | +├── home.nix # Shared home-manager user config |
| 60 | +├── hosts/ # Machine-specific configs (data, not modules) |
| 61 | +│ ├── personal.nix # Personal MacBook configuration |
| 62 | +│ └── work.nix # Work MacBook configuration |
| 63 | +├── modules/ # System-level nix-darwin modules (auto-discovered) |
| 64 | +│ ├── default.nix # Auto-discovery logic |
| 65 | +│ ├── dock.nix # Dock settings |
| 66 | +│ ├── finder.nix # Finder settings |
| 67 | +│ ├── homebrew.nix # Shared Homebrew configuration |
| 68 | +│ ├── security.nix # Firewall, Touch ID settings |
| 69 | +│ └── ... # Other macOS system preference modules |
| 70 | +├── programs/ # User program configurations (auto-discovered) |
| 71 | +│ ├── default.nix # Auto-discovery logic |
| 72 | +│ ├── fish/ # Fish shell (directory module) |
| 73 | +│ │ ├── default.nix |
| 74 | +│ │ ├── abbreviations.nix |
| 75 | +│ │ ├── aliases.nix |
| 76 | +│ │ └── functions.nix |
| 77 | +│ ├── git/ # Git configuration (directory module) |
| 78 | +│ │ ├── default.nix |
| 79 | +│ │ └── .gitmessage # Commit template |
| 80 | +│ ├── bat.nix # File modules for simple configs |
| 81 | +│ ├── starship.nix |
| 82 | +│ └── ... |
| 83 | +├── lib/ # Shared Nix utilities |
| 84 | +│ └── auto-discovery.nix # Auto-discovery function for modules |
| 85 | +└── docs/ # Documentation |
| 86 | + ├── CUSTOMIZATION.md # Detailed how-to guide |
| 87 | + ├── TASKS.md # Task tracker |
| 88 | + └── adr/ # Architecture Decision Records |
| 89 | +``` |
| 90 | + |
| 91 | +### Auto-Discovery System |
| 92 | + |
| 93 | +Both `modules/` and `programs/` use auto-discovery via `lib/auto-discovery.nix`: |
| 94 | + |
| 95 | +- **Single-file modules**: `foo.nix` → automatically imported |
| 96 | +- **Directory modules**: `foo/default.nix` → automatically imported (used for complex configs with assets) |
| 97 | +- **Excluded**: Files/directories starting with `_` (draft convention) |
| 98 | +- **Excluded**: `default.nix` itself |
| 99 | + |
| 100 | +This means you can add new program configurations or system modules by simply creating a `.nix` file—no import statements needed. |
| 101 | + |
| 102 | +### Host Configuration Pattern |
| 103 | + |
| 104 | +Host files (`hosts/*.nix`) are **data** (attribute sets), not NixOS modules: |
| 105 | + |
| 106 | +```nix |
| 107 | +# hosts/example.nix |
| 108 | +{ |
| 109 | + userConfig = { |
| 110 | + username = "user"; |
| 111 | + fullName = "Full Name"; |
| 112 | + homeDirectory = "/Users/user"; |
| 113 | + dotfilesPath = "/Users/user/Developer/dotfiles"; |
| 114 | + }; |
| 115 | + |
| 116 | + userModule = ../home.nix; |
| 117 | + system = "aarch64-darwin"; |
| 118 | + hostname = "Example-MacBook"; # Run: scutil --get LocalHostName |
| 119 | + |
| 120 | + homebrew = { |
| 121 | + enableRosetta = false; |
| 122 | + casks = []; # Host-specific GUI apps |
| 123 | + }; |
| 124 | +} |
| 125 | +``` |
| 126 | + |
| 127 | +The `mkDarwinConfig` helper in `flake.nix` converts these into full darwin configurations. |
| 128 | + |
| 129 | +### Module Signature Conventions |
| 130 | + |
| 131 | +All modules follow standard NixOS conventions: |
| 132 | + |
| 133 | +```nix |
| 134 | +# programs/example.nix or modules/example.nix |
| 135 | +{ |
| 136 | + config, |
| 137 | + lib, |
| 138 | + pkgs, |
| 139 | + ... |
| 140 | +}: let |
| 141 | + inherit (lib) mkDefault; |
| 142 | +in { |
| 143 | + # Configuration here |
| 144 | + programs.example = { |
| 145 | + enable = mkDefault true; |
| 146 | + # ... |
| 147 | + }; |
| 148 | +} |
| 149 | +``` |
| 150 | + |
| 151 | +- Use full signature: `{ config, lib, pkgs, ... }:` |
| 152 | +- Use `inherit (lib) mkDefault;` for cleaner code |
| 153 | +- Apply `mkDefault` to values users might override |
| 154 | +- Add descriptive header comments |
| 155 | + |
| 156 | +## Common Editing Tasks |
| 157 | + |
| 158 | +### Add a CLI Package |
| 159 | + |
| 160 | +Edit `home.nix` → `home.packages`: |
| 161 | + |
| 162 | +```nix |
| 163 | +packages = with pkgs; [ |
| 164 | + # ... existing packages |
| 165 | + ripgrep # Add new package |
| 166 | +]; |
| 167 | +``` |
| 168 | + |
| 169 | +Find packages: `nix search nixpkgs <name>` |
| 170 | + |
| 171 | +### Add a GUI App (Homebrew Cask) |
| 172 | + |
| 173 | +For **all machines**: `modules/homebrew.nix` → `casks` |
| 174 | +For **specific machine**: `hosts/personal.nix` or `hosts/work.nix` → `homebrew.casks` |
| 175 | + |
| 176 | +Find casks: `brew search <name>` |
| 177 | + |
| 178 | +### Add a Program Configuration |
| 179 | + |
| 180 | +Create a new file in `programs/`: |
| 181 | + |
| 182 | +**Simple module** (single file): |
| 183 | +```nix |
| 184 | +# programs/tmux.nix |
| 185 | +{ pkgs, ... }: { |
| 186 | + programs.tmux = { |
| 187 | + enable = true; |
| 188 | + terminal = "screen-256color"; |
| 189 | + # ... |
| 190 | + }; |
| 191 | +} |
| 192 | +``` |
| 193 | + |
| 194 | +**Complex module** (directory with assets): |
| 195 | +```nix |
| 196 | +# programs/myapp/default.nix |
| 197 | +{ ... }: { |
| 198 | + programs.myapp.enable = true; |
| 199 | + xdg.configFile."myapp/settings.json".source = ./settings.json; |
| 200 | +} |
| 201 | +``` |
| 202 | + |
| 203 | +### Change macOS System Preferences |
| 204 | + |
| 205 | +Edit the appropriate module in `modules/`: |
| 206 | + |
| 207 | +- `dock.nix` - Dock behavior |
| 208 | +- `finder.nix` - Finder settings |
| 209 | +- `nsglobaldomain.nix` - Global system settings |
| 210 | +- `trackpad.nix` - Trackpad gestures |
| 211 | +- `security.nix` - Firewall, Touch ID |
| 212 | +- `custom-preferences.nix` - Settings not exposed via typed options |
| 213 | + |
| 214 | +### Add Environment Variables |
| 215 | + |
| 216 | +Edit `programs/session.nix` → `home.sessionVariables` |
| 217 | + |
| 218 | +### Add Fish Shell Customizations |
| 219 | + |
| 220 | +- **Abbreviations**: `programs/fish/abbreviations.nix` (expanded inline) |
| 221 | +- **Aliases**: `programs/fish/aliases.nix` (not expanded) |
| 222 | +- **Functions**: `programs/fish/functions.nix` (complex logic) |
| 223 | + |
| 224 | +### Add a New Machine |
| 225 | + |
| 226 | +1. Create `hosts/new-machine.nix` with host configuration |
| 227 | +2. Edit `flake.nix`: |
| 228 | + - Add `newMachineHost = import ./hosts/new-machine.nix;` |
| 229 | + - Add `${newMachineHost.hostname} = mkDarwinConfig newMachineHost;` to `darwinConfigurations` |
| 230 | +3. On new machine: `sudo darwin-rebuild switch --flake .#hostname` |
| 231 | + |
| 232 | +## Testing Workflow |
| 233 | + |
| 234 | +1. **Check syntax**: `just check` (format, lint, deadcode) |
| 235 | +2. **Build first**: `just build` (ensures no evaluation errors) |
| 236 | +3. **Review changes**: `just diff` (if `nvd` is installed) |
| 237 | +4. **Apply**: `just switch` |
| 238 | +5. **If broken**: `just rollback` |
| 239 | + |
| 240 | +## Important Notes |
| 241 | + |
| 242 | +### Version Control |
| 243 | + |
| 244 | +- Changes must be `git add`ed before building (flakes requirement) |
| 245 | +- The repository uses Git for version control |
| 246 | +- All host-specific data is in version control |
| 247 | + |
| 248 | +### Multiple Hosts |
| 249 | + |
| 250 | +- Configuration is in flake outputs: `darwinConfigurations.<hostname>` |
| 251 | +- Run `scutil --get LocalHostName` to get the correct hostname |
| 252 | +- Build specific host: `darwin-rebuild build --flake .#<hostname>` |
| 253 | +- Switch specific host: `sudo darwin-rebuild switch --flake .#<hostname>` |
| 254 | + |
| 255 | +### Documentation |
| 256 | + |
| 257 | +- `docs/CUSTOMIZATION.md` - Comprehensive how-to guide with examples |
| 258 | +- `docs/adr/` - Architecture Decision Records explaining design choices |
| 259 | +- `docs/TASKS.md` - Ongoing work and improvements |
| 260 | + |
| 261 | +### References |
| 262 | + |
| 263 | +All nix-darwin and home-manager options are documented: |
| 264 | +- [nix-darwin Manual](https://daiderd.com/nix-darwin/manual/index.html) |
| 265 | +- [home-manager Manual](https://nix-community.github.io/home-manager/) |
| 266 | +- [Nix Package Search](https://search.nixos.org/packages) |
0 commit comments