diff --git a/.sisyphus/boulder.json b/.sisyphus/boulder.json deleted file mode 100644 index b498a72..0000000 --- a/.sisyphus/boulder.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "active_plan": "/home/cschmatzler/nixos-config/.sisyphus/plans/dendritic-migration.md", - "started_at": "2026-03-05T10:57:53.044Z", - "session_ids": [ - "ses_34287fe8effeSATHvHUmGqZ5Fp" - ], - "plan_name": "dendritic-migration", - "agent": "atlas", - "worktree_path": "/home/cschmatzler/nixos-config" -} diff --git a/.sisyphus/notepads/dendritic-migration/decisions.md b/.sisyphus/notepads/dendritic-migration/decisions.md deleted file mode 100644 index 540c900..0000000 --- a/.sisyphus/notepads/dendritic-migration/decisions.md +++ /dev/null @@ -1,2 +0,0 @@ - -- Do not include user aspects (e.g. `den.aspects.cschmatzler`) in host aspect `includes`. Den HM integration already applies the user aspect for each `den.hosts...users.` via `den.ctx.user`; duplicating it via host `includes` leads to duplicated HM option merges (notably `types.lines` options like `programs.nushell.extraConfig`). diff --git a/.sisyphus/notepads/dendritic-migration/issues.md b/.sisyphus/notepads/dendritic-migration/issues.md deleted file mode 100644 index 65716df..0000000 --- a/.sisyphus/notepads/dendritic-migration/issues.md +++ /dev/null @@ -1,3 +0,0 @@ - -- Nushell `programs.nushell.extraConfig` duplication traced to Den applying the user aspect twice: it is included via host aspect `includes` (e.g. `den.aspects.tahani.includes = [ ... den.aspects.cschmatzler ... ]`) AND Den's HM integration already includes the user aspect via `den.ctx.user` (see Den `hm-integration.nix`). Result: user-aspect-provided HM config (like `den.aspects.shell.homeManager`) merges twice, so `extraConfig` contains two identical copies. -- `dev-tools` nushell functions (e.g. `ggpull`) missing in `michael` is expected: `modules/michael.nix` does not include `den.aspects.dev-tools`. diff --git a/.sisyphus/notepads/dendritic-migration/learnings.md b/.sisyphus/notepads/dendritic-migration/learnings.md deleted file mode 100644 index 3f20dc0..0000000 --- a/.sisyphus/notepads/dendritic-migration/learnings.md +++ /dev/null @@ -1,128 +0,0 @@ -- For den migration, move legacy non-flake-parts modules into `modules/_legacy/` before enabling `inputs.import-tree ./modules`; import-tree ignores underscore-prefixed paths. -- `flake-parts` must include `inputs.nixpkgs-lib.follows = "nixpkgs"` in this repository to match den bootstrap expectations. -- The den bootstrap works with `modules/dendritic.nix` importing `(inputs.flake-file.flakeModules.dendritic or { })` and `(inputs.den.flakeModules.dendritic or { })`, plus initial `flake-file.inputs` declarations. -- Den host wiring uses `den.hosts...users. = {}` declarations in `modules/hosts.nix` for each host-user pair. -- `den.default.includes` accepts batteries directly via `den.provides.*`; this bootstrap uses `den.provides.define-user` and `den.provides.inputs'`. -- In this flake-parts setup, declaring `options.flake.darwinConfigurations` as `lib.types.lazyAttrsOf lib.types.raw` allows multiple Darwin hosts to merge correctly. - -## Task 3: Utility functions under _lib/ - COMPLETED - -**What was done:** -- Created `modules/_lib/` directory -- Copied 5 pure function files (not NixOS modules): - - `lib/constants.nix` → `modules/_lib/constants.nix` (14 lines) - - `lib/build-rust-package.nix` → `modules/_lib/build-rust-package.nix` (20 lines) - - `profiles/wallpaper.nix` → `modules/_lib/wallpaper.nix` (11 lines) - - `profiles/open-project.nix` → `modules/_lib/open-project.nix` (10 lines) - - `profiles/packages.nix` → `modules/_lib/packages.nix` (67 lines) - -**Key insight:** -- import-tree ignores paths with `/_` prefix, so `modules/_lib/` is safe for pure functions -- These files are NOT NixOS/home-manager modules - they're utility functions that would crash import-tree if placed directly under `modules/` -- Files were COPIED (not moved) because old locations are still referenced by existing host configs until Task 26 - -**Verification:** -- All 5 files copied with identical content (byte-for-byte match) -- `alejandra --check modules/_lib/` passed (formatting compliant) -- `nix flake show` exits 0 (import-tree correctly ignores `_lib/`) - -**Dependencies:** -- Unblocks Task 4 (overlays need `build-rust-package.nix` from `_lib/`) - -## Task 2: Hosts and defaults bootstrap notes - -- Den host wiring uses `den.hosts...users. = {}` declarations in `modules/hosts.nix` for each host-user pair. -- `den.default.includes` accepts batteries directly via `den.provides.*`; this bootstrap uses `den.provides.define-user` and `den.provides.inputs'`. -- In this flake-parts setup, declaring `options.flake.darwinConfigurations` as `lib.types.lazyAttrsOf lib.types.raw` allows multiple Darwin hosts to merge correctly. - -## Task 5: Core aspect module - COMPLETED - -**What was done:** -- Created `modules/core.nix` as a flake-parts module defining `den.aspects.core` -- Ported all nix settings from `profiles/core.nix` into the `os` class (applies to both nixos and darwin) -- Updated `modules/defaults.nix` to include `den.aspects.core` in `den.default.includes` - -**Key decisions:** -- Used `os` class for shared settings (fish, nushell, nixpkgs.config.allowUnfree, nix package, substituters, trusted-public-keys, gc.automatic, gc.options, experimental-features) -- Deliberately EXCLUDED `trusted-users` from core.nix (platform-specific: darwin uses "@admin", NixOS uses specific user — handled by darwin.nix and nixos-system.nix) -- Deliberately EXCLUDED gc interval/dates (platform-specific: darwin uses `interval`, NixOS uses `dates` — handled by darwin.nix and nixos-system.nix) - -**Verification:** -- `modules/core.nix` created with 35 lines (exact port of profiles/core.nix settings) -- `modules/defaults.nix` updated to include `den.aspects.core` in includes list -- `alejandra .` formatted both files successfully -- `nix flake show` exits 0 (flake evaluates cleanly) - -**Dependencies:** -- Unblocks Task 6 (darwin.nix and nixos-system.nix can now reference den.aspects.core) - -## Task 6a: NixOS system aspect - COMPLETED - -**What was done:** -- Created `modules/nixos-system.nix` as a flake-parts module defining `den.aspects.nixos-system` -- Ported NixOS-specific config from `profiles/nixos.nix` into the `nixos` class - -**Key decisions:** -- Used `nixos` class (not `os`) since all settings are NixOS-specific (sudo, boot, systemd-boot, users) -- `nixos` class uses NixOS module function form `{pkgs, ...}: { ... }` to access `pkgs` for `linuxPackages_latest` and `nushell` -- `inputs` accessed from outer flake-parts module args for `home-manager.nixosModules.home-manager` import -- Hardcoded "cschmatzler" instead of variable interpolation (user is always the same) -- Hardcoded SSH keys inline instead of referencing constants (simplifies dependency) -- Deliberately EXCLUDED: system.stateVersion (in defaults.nix), sops.age.sshKeyPaths (in secrets.nix), home-manager.sharedModules/_module.args (den handles via inputs' battery) - -**Pattern:** -- Outer function: `{inputs, ...}:` — flake-parts module args -- Inner class: `nixos = {pkgs, ...}: { ... }` — NixOS module function -- `imports = [inputs.home-manager.nixosModules.home-manager]` inside the nixos class - -**Verification:** -- `alejandra --check .` passes (already compliant on write) -- `nix flake show` exits 0 (both michael and tahani evaluate cleanly) - -## Task 6b: Darwin system aspect - COMPLETED - -**What was done:** -- Created `modules/darwin.nix` as a flake-parts module defining `den.aspects.darwin-system` -- Created `modules/_darwin/dock.nix` — the dock module (NixOS-style with options/config) -- Ported profiles/darwin.nix, profiles/dock.nix, profiles/homebrew.nix, and nix-homebrew config - -**Files created:** -- `modules/darwin.nix` — flake-parts module with `den.aspects.darwin-system.darwin` class -- `modules/_darwin/dock.nix` — dock options+activation script module (underscore prefix avoids import-tree) - -**Key decisions:** -- `darwin` class uses NixOS module function form `{pkgs, ...}: { ... }` to access `pkgs.nushell` -- `inputs` accessed from outer flake-parts module args via closure (for nix-homebrew, home-manager, homebrew taps) -- Dock module placed in `modules/_darwin/dock.nix` and imported via `imports = [./_darwin/dock.nix]` inside the darwin class -- All `user` variable references replaced with hardcoded "cschmatzler" -- Excluded: home-manager.extraSpecialArgs (den handles via batteries), system.stateVersion (in defaults.nix) -- nix-homebrew config wired with taps from flake inputs (homebrew-core, homebrew-cask) - -**Pattern for complex sub-modules:** -- Use `modules/_/` prefix (underscore avoids import-tree auto-import) -- Import from aspect class via `imports = [./_darwin/dock.nix]` -- The inner NixOS module function captures `inputs` from outer flake-parts scope via Nix closure - -**Verification:** -- `alejandra .` — already compliant on write (no changes needed) -- `nix flake show` exits 0 (flake evaluates cleanly with new aspect) - -## Task 23: Michael aspect with absorbed gitea module - COMPLETED - -- Created `modules/_hosts/michael/` and copied `hosts/michael/disk-config.nix` plus `hosts/michael/hardware-configuration.nix` byte-for-byte into underscore-prefixed paths so import-tree ignores them. -- Added `modules/michael.nix` defining `den.aspects.michael` with includes `den.aspects.nixos-system`, `den.aspects.core`, and `den.aspects.cschmatzler`. -- Inlined the full gitea/redis/litestream/caddy/restic/systemd config directly in the michael aspect and removed dependency on `options.my.gitea`. -- Preserved intentional `lib.mkForce` overrides for litestream and restic service users/groups. -- Replaced legacy `cfg.*` references with concrete values and SOPS paths: litestream bucket `michael-gitea-litestream`, restic bucket `michael-gitea-repositories`, endpoint `s3.eu-central-003.backblazeb2.com`, and `config.sops.secrets.michael-gitea-*.path`. - -## Task 25: Tahani aspect with host sub-files - COMPLETED - -- Created `modules/_hosts/tahani/` and copied `hosts/tahani/{adguardhome,cache,networking,paperless}.nix` byte-for-byte into underscore-prefixed paths so import-tree ignores host-only sub-files. -- Added `modules/tahani.nix` defining `den.aspects.tahani` with includes `den.aspects.nixos-system`, `den.aspects.core`, and `den.aspects.cschmatzler` (network aspects intentionally deferred). -- Ported tahani-specific NixOS settings into the aspect (`networking.hostName`, docker enablement, docker group membership for `cschmatzler`, and 16 GiB swapfile declaration). -- Ported tahani-specific Home Manager settings into the aspect (`programs.git.settings.user.email`, zellij Nushell integration override enabled for tahani). -- Inbox-triage systemd unit now uses `pkgs.himalaya` from overlay in `PATH` (`${pkgs.himalaya}/bin`) with `inputs'.llm-agents.packages.opencode` for `ExecStart`; no `config.home-manager.users...` lookup. -- Verification: `alejandra .`, `alejandra --check .`, and `nix flake show` all pass; `lsp_diagnostics` is clean on all newly created tahani files. - -- Home Manager `programs.nushell` module writes `config.nu` as a merge of: `environmentVariables` (via `load-env`), flattened `settings`, optional `configFile.text`, then `extraConfig`, then generated `shellAliases` (see HM `modules/programs/nushell.nix`). So any duplication in `config.nu` that is isolated to `extraConfig` almost always means the option value was merged multiple times (module included multiple times), not that HM writes it twice. -- In Den, HM user contexts include both the host aspect chain and the user aspect (`den.ctx.user`). If you also include the user aspect from the host aspect `includes`, user HM config is applied twice. diff --git a/.sisyphus/notepads/dendritic-migration/problems.md b/.sisyphus/notepads/dendritic-migration/problems.md deleted file mode 100644 index e69de29..0000000 diff --git a/.sisyphus/plans/dendritic-migration.md b/.sisyphus/plans/dendritic-migration.md deleted file mode 100644 index 031db1d..0000000 --- a/.sisyphus/plans/dendritic-migration.md +++ /dev/null @@ -1,1794 +0,0 @@ -# Dendritic Migration: Rewrite NixOS Config with den Framework - -## TL;DR - -> **Quick Summary**: Complete rewrite of the NixOS/darwin configuration from host-centric architecture to feature/aspect-centric using the den framework (vic/den). Replaces specialArgs pass-through, unifies home-manager integration paths, replaces colmena with deploy-rs, and adopts auto-importing via import-tree. -> -> **Deliverables**: -> - New `flake.nix` using den + flake-parts + import-tree + flake-file -> - All 38+ profiles converted to den aspects in `modules/` -> - All 4 hosts (chidi, jason, michael, tahani) building successfully -> - deploy-rs replacing colmena for NixOS deployment -> - Zero specialArgs usage — inputs flow via flake-parts module args -> - Overlays preserved and migrated to den module structure -> - SOPS secrets preserved exactly -> -> **Estimated Effort**: Large -> **Parallel Execution**: YES - 5 waves -> **Critical Path**: Task 1 → Task 2 → Task 4 → Tasks 8-11 → Task 20 → Final - ---- - -## Context - -### Original Request -Migrate NixOS configuration to the dendritic pattern using the den framework. Organize config by feature instead of by tool (nixos vs home-manager). Make every file a flake-parts module. Eliminate specialArgs pass-through hell. - -### Interview Summary -**Key Discussions**: -- **Framework choice**: User chose den (vic/den) over pure dendritic pattern — wants full aspect/context/batteries system -- **Migration strategy**: Clean rewrite, not incremental — fresh start with new structure -- **Deploy**: Replace colmena with deploy-rs for NixOS server deployment -- **Input management**: Use flake-file (vic/flake-file) to auto-manage flake.nix inputs from modules -- **Custom modules**: Absorb my.gitea and my.pgbackrest into den aspects (no separate nixosModules export) -- **Host roles**: chidi = work laptop (Slack, tuist.dev email), jason = personal laptop -- **Feature granularity**: Trusted to planner — will group by concern where natural - -**Research Findings**: -- den framework provides: aspects, contexts, batteries (define-user, primary-user, user-shell, inputs') -- import-tree auto-imports all .nix files, ignores `/_` prefixed paths -- flake-file auto-manages flake.nix from module-level declarations -- deploy-rs uses `deploy.nodes.` flake output — limited darwin support, use only for NixOS -- Real-world den migration examples reviewed (hyperparabolic/nix-config, dendrix community) - -### Metis Review -**Identified Gaps (addressed)**: -- `local.dock.*` is a third custom module namespace that was initially missed — will be migrated -- `profiles/wallpaper.nix`, `profiles/packages.nix`, `profiles/open-project.nix` are pure functions, NOT modules — must go under `_`-prefixed paths to avoid import-tree failures -- Himalaya cross-dependency (tahani reads HM config from NixOS scope) — redesign using overlay package directly -- `zellij.nix` uses `osConfig.networking.hostName == "tahani"` hostname comparison — replace with per-host aspect override -- `pgbackrest` module is exported but never imported internally — absorb into aspects per user's decision -- `apps/` directory contains bash scripts — will be rewritten to Nushell as part of this migration -- Platform-conditional code (`stdenv.isDarwin`) in HM profiles is correct — keep, don't split into per-class -- Published flake outputs need explicit preservation decisions - ---- - -## Work Objectives - -### Core Objective -Rewrite the entire NixOS/darwin configuration to use the den framework's aspect-oriented architecture, eliminating specialArgs pass-through and organizing all configuration by feature/concern instead of by host. - -### Concrete Deliverables -- New `flake.nix` with den + import-tree + flake-aspects + flake-file -- `modules/` directory with all features as den aspects (auto-imported) -- `_lib/` directory for non-module utility functions -- All 4 hosts building identically to current config -- deploy-rs configuration for michael and tahani -- No residual `hosts/`, `profiles/`, old `modules/` structure - -### Definition of Done -- [ ] `nix build ".#darwinConfigurations.chidi.system"` succeeds -- [ ] `nix build ".#darwinConfigurations.jason.system"` succeeds -- [ ] `nix build ".#nixosConfigurations.michael.config.system.build.toplevel"` succeeds -- [ ] `nix build ".#nixosConfigurations.tahani.config.system.build.toplevel"` succeeds -- [ ] `nix flake check` passes -- [ ] `alejandra --check .` passes -- [ ] `nix eval ".#deploy.nodes.michael"` returns valid deploy-rs node -- [ ] `nix eval ".#deploy.nodes.tahani"` returns valid deploy-rs node -- [ ] Zero uses of `specialArgs` or `extraSpecialArgs` in codebase - -### Must Have -- Exact behavioral equivalence — same services, packages, config files on all hosts -- SOPS secret paths preserved exactly (darwin: age keyfile, NixOS: ssh host key) -- Per-host git email overrides preserved (chidi→tuist.dev, jason/tahani→schmatzler.com) -- All current overlays functional -- deploy-rs for NixOS hosts (michael, tahani) -- Darwin deployment stays as local `darwin-rebuild switch` (deploy-rs has limited darwin support) -- All stateVersion values unchanged (darwin: 6, nixos: "25.11", homeManager: "25.11") -- All perSystem apps (build, apply, build-switch, rollback) preserved or equivalently replaced - -### Must NOT Have (Guardrails) -- MUST NOT add new packages, services, or features not in current config -- MUST NOT split simple single-concern profiles into multiple aspects (atuin.nix → one aspect) -- MUST NOT add abstractions for "future use" (multi-user support, dynamic host detection, etc.) -- MUST NOT rewrite app scripts in any language other than Nushell (per AGENTS.md scripting policy) -- MUST NOT change any stateVersion values -- MUST NOT re-encrypt or restructure SOPS secrets — paths and key assignments stay identical -- MUST NOT change any service configuration values (ports, paths, domains, credentials) -- MUST NOT add den batteries beyond what's needed — each must map to a current requirement -- MUST NOT create abstractions over overlays (current pattern is clear) -- MUST NOT add excessive comments, JSDoc, or documentation to nix files -- MUST NOT use hostname string comparisons in shared aspects (no `osConfig.networking.hostName == "tahani"`) -- MUST NOT read HM config values from NixOS scope (the himalaya anti-pattern) - ---- - -## Verification Strategy - -> **ZERO HUMAN INTERVENTION** — ALL verification is agent-executed. No exceptions. - -### Test Decision -- **Infrastructure exists**: NO (this is a NixOS config, not a software project) -- **Automated tests**: None (verification is via `nix build` / `nix eval` / `nix flake check`) -- **Framework**: N/A - -### QA Policy -Every task MUST verify its changes compile via `nix eval` or `nix build --dry-run`. -Formatting MUST pass `alejandra --check .` after every file change. - ---- - -## Execution Strategy - -### Parallel Execution Waves - -``` -Wave 1 (Foundation — flake bootstrap + utilities): -├── Task 1: New flake.nix with den + import-tree + flake-file [deep] -├── Task 2: den bootstrap module (hosts, users, defaults, base) [deep] -├── Task 3: Utility functions under _lib/ [quick] -├── Task 4: Overlays module [quick] -├── Task 5: SOPS secrets aspects (all 4 hosts) [quick] -└── Task 6: Deploy-rs module [quick] - -Wave 2 (Core shared aspects — no host dependencies): -├── Task 7: Core system aspect (nix settings, shells) [quick] -├── Task 8: Darwin system aspect (system defaults, dock, homebrew, nix-homebrew) [unspecified-high] -├── Task 9: NixOS system aspect (boot, sudo, systemd, users) [unspecified-high] -├── Task 10: User aspect (cschmatzler — define-user, primary-user, shell) [quick] -└── Task 11: perSystem apps module [quick] - -Wave 3 (Home-manager aspects — bulk migration, MAX PARALLEL): -├── Task 12: Shell aspects (nushell, bash, zsh, starship) [quick] -├── Task 13: Dev tools aspects (git, jujutsu, lazygit, jjui, direnv, mise) [quick] -├── Task 14: Editor aspects (neovim/nixvim) [unspecified-high] -├── Task 15: Terminal aspects (ghostty, zellij, yazi, bat, fzf, ripgrep, zoxide) [quick] -├── Task 16: Communication aspects (himalaya, mbsync, ssh) [unspecified-high] -├── Task 17: Desktop aspects (aerospace, wallpaper, home base) [quick] -├── Task 18: AI tools aspects (opencode, claude-code) [quick] -└── Task 19: Miscellaneous aspects (atuin, zk, open-project) [quick] - -Wave 4 (Host-specific + services + scripts): -├── Task 20: Server aspects — michael (gitea + litestream + restic) [deep] -├── Task 21: Server aspects — tahani (adguard, paperless, docker, inbox-triage) [deep] -├── Task 22: Host aspects — chidi (work-specific) [quick] -├── Task 23: Host aspects — jason (personal-specific) [quick] -├── Task 24: Network aspects (openssh, fail2ban, tailscale, postgresql) [quick] -├── Task 25: Packages aspect (system packages list) [quick] -└── Task 29: Rewrite apps/ scripts from bash to Nushell [quick] - -Wave 5 (Cleanup + verification): -├── Task 26: Remove old structure (hosts/, profiles/, old modules/) [quick] -├── Task 27: Full build verification all 4 hosts [deep] -└── Task 28: Formatting pass + final cleanup [quick] - -Wave FINAL (After ALL tasks — independent review, 4 parallel): -├── Task F1: Plan compliance audit (oracle) -├── Task F2: Code quality review (unspecified-high) -├── Task F3: Real manual QA (unspecified-high) -└── Task F4: Scope fidelity check (deep) - -Critical Path: Task 1 → Task 2 → Task 7 → Tasks 8-9 → Task 10 → Tasks 12-19 → Tasks 20-21 + Task 29 → Task 27 → F1-F4 -Parallel Speedup: ~60% faster than sequential -Max Concurrent: 8 (Wave 3) -``` - -### Dependency Matrix - -- **1**: — — 2, 3, 4, 5, 6, 11, W1 -- **2**: 1 — 7, 8, 9, 10, W1 -- **3**: 1 — 4, 14, 16, 20, 21, W1 -- **4**: 1, 3 — 7, 8, 9, W1 -- **5**: 1, 2 — 20, 21, 22, 23, W1 -- **6**: 1, 2 — 27, W1 -- **7**: 2, 4 — 12-19, W2 -- **8**: 2, 4 — 17, 22, 23, W2 -- **9**: 2, 4 — 20, 21, 24, W2 -- **10**: 2 — 12-19, W2 -- **11**: 1 — 27, W2 -- **12-19**: 7, 10 — 20-25, W3 -- **20**: 5, 9, 14, 16 — 27, W4 -- **21**: 5, 9, 16, 18 — 27, W4 -- **22**: 5, 8, 17 — 27, W4 -- **23**: 5, 8, 17 — 27, W4 -- **24**: 9 — 27, W4 -- **25**: 7 — 27, W4 -- **29**: 11 — 27, W4 -- **26**: 27 — F1-F4, W5 -- **27**: 20-25, 29 — 26, 28, W5 -- **28**: 27 — F1-F4, W5 - -### Agent Dispatch Summary - -- **W1**: **6** — T1 → `deep`, T2 → `deep`, T3 → `quick`, T4 → `quick`, T5 → `quick`, T6 → `quick` -- **W2**: **5** — T7 → `quick`, T8 → `unspecified-high`, T9 → `unspecified-high`, T10 → `quick`, T11 → `quick` -- **W3**: **8** — T12-T13 → `quick`, T14 → `unspecified-high`, T15 → `quick`, T16 → `unspecified-high`, T17-T19 → `quick` -- **W4**: **7** — T20-T21 → `deep`, T22-T25 → `quick`, T29 → `quick` -- **W5**: **3** — T26 → `quick`, T27 → `deep`, T28 → `quick` -- **FINAL**: **4** — F1 → `oracle`, F2 → `unspecified-high`, F3 → `unspecified-high`, F4 → `deep` - ---- - -## TODOs - -- [x] 1. New flake.nix with den + import-tree + flake-file - - **What to do**: - - Move existing `modules/gitea.nix` and `modules/pgbackrest.nix` to `modules/_legacy/` (underscore prefix = ignored by import-tree). These will be absorbed into den aspects in Tasks 20/21 and deleted in Task 26 - - Create new `flake.nix` that uses `flake-parts.lib.mkFlake` with `inputs.import-tree ./modules` - - Add all required inputs: preserve existing (nixpkgs, flake-parts, sops-nix, home-manager, darwin, nix-homebrew, homebrew-core, homebrew-cask, nixvim, zjstatus, llm-agents, disko, jj-ryu, jj-starship, himalaya, naersk, tuicr) AND add new required inputs (den, import-tree, flake-aspects, flake-file, deploy-rs) - - Preserve all existing `follows` declarations and `flake = false` attributes - - The `outputs` should be minimal: `inputs.flake-parts.lib.mkFlake { inherit inputs; } (inputs.import-tree ./modules)` - - Remove the old `outputs` block entirely (specialArgs, genAttrs, inline configs — all gone) - - Create a minimal placeholder module in `modules/` (e.g. empty flake-parts module) so import-tree has something to import - - Ensure `nix flake show` doesn't error - - **Must NOT do**: - - Do not include ANY configuration logic in flake.nix — everything goes in modules/ - - Do not change any existing input URLs or versions - - Do not add inputs beyond the required new ones (den, import-tree, flake-aspects, flake-file, deploy-rs) - - **Recommended Agent Profile**: - - **Category**: `deep` - - Reason: This is the highest-risk task — if the flake bootstrap is wrong, nothing works. Needs careful attention to input declarations, follows chains, and flake-file compatibility. - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: NO - - **Parallel Group**: Wave 1 (start first) - - **Blocks**: All other tasks - - **Blocked By**: None - - **References**: - - `flake.nix:1-168` — Current flake with all inputs and follows declarations to preserve - - `templates/default/flake.nix` in vic/den repo — Reference flake.nix structure using import-tree - - den migration guide: https://den.oeiuwq.com/guides/migrate/ - - import-tree README: https://github.com/vic/import-tree — Auto-import pattern - - flake-file: https://github.com/vic/flake-file — For auto-managing inputs from modules - - **Acceptance Criteria**: - - [ ] `flake.nix` has all current inputs preserved with correct follows - - [ ] `flake.nix` has new required inputs: den, import-tree, flake-aspects, flake-file, deploy-rs - - [ ] `flake.nix` outputs use `import-tree ./modules` - - [ ] `modules/_legacy/gitea.nix` and `modules/_legacy/pgbackrest.nix` exist (moved from modules/) - - [ ] `nix flake show` doesn't error (with a minimal placeholder module) - - **QA Scenarios**: - ``` - Scenario: Flake evaluates without errors - Tool: Bash - Preconditions: New flake.nix written, modules/ directory exists with at least one .nix file - Steps: - 1. Run `nix flake show --json 2>&1` - 2. Assert exit code 0 - 3. Run `nix flake check --no-build 2>&1` - Expected Result: Both commands exit 0 without evaluation errors - Evidence: .sisyphus/evidence/task-1-flake-eval.txt - - Scenario: All inputs preserved - Tool: Bash - Preconditions: New flake.nix written - Steps: - 1. Run `nix flake metadata --json | nu -c '$in | from json | get locks.nodes | columns | sort'` - 2. Compare against expected list: [darwin, disko, deploy-rs, den, flake-aspects, flake-file, flake-parts, himalaya, home-manager, homebrew-cask, homebrew-core, import-tree, jj-ryu, jj-starship, llm-agents, naersk, nix-homebrew, nixpkgs, nixvim, sops-nix, tuicr, zjstatus] - Expected Result: All inputs present in lock file - Evidence: .sisyphus/evidence/task-1-inputs.txt - ``` - - **Commit**: YES (group with 2, 3) - - Message: `feat(den): bootstrap flake with den + import-tree + flake-file` - - Files: `flake.nix`, `modules/` - - Pre-commit: `alejandra --check .` - -- [x] 2. Den bootstrap module — hosts, users, defaults, base - - **What to do**: - - Create `modules/den.nix` — import den flakeModule, declare all 4 hosts and their users: - ```nix - den.hosts.aarch64-darwin.chidi.users.cschmatzler = {}; - den.hosts.aarch64-darwin.jason.users.cschmatzler = {}; - den.hosts.x86_64-linux.michael.users.cschmatzler = {}; - den.hosts.x86_64-linux.tahani.users.cschmatzler = {}; - ``` - - Set `den.base.user.classes = lib.mkDefault ["homeManager"];` - - Create `modules/defaults.nix` — define `den.default` with: - - `includes = [den.provides.define-user den.provides.inputs']` - - State versions: `nixos.system.stateVersion = "25.11"`, `homeManager.home.stateVersion = "25.11"` - - Darwin state version handled per-class - - Wire flake-file module import if needed - - Create `modules/flake-parts.nix` to import `inputs.flake-parts.flakeModules.modules` - - **Must NOT do**: - - Do not add multi-user abstractions - - Do not add batteries not needed - - Do not change stateVersion values - - **Recommended Agent Profile**: - - **Category**: `deep` - - Reason: Core den bootstrap — needs understanding of den's host/user/aspect model and correct battery usage - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: NO - - **Parallel Group**: Wave 1 (after Task 1) - - **Blocks**: Tasks 7-10, all Wave 2+ - - **Blocked By**: Task 1 - - **References**: - - `lib/constants.nix:1-14` — Current constants (user name, SSH keys, stateVersions) - - den docs: https://den.oeiuwq.com/guides/declare-hosts/ — Host/user declaration - - den docs: https://den.oeiuwq.com/guides/batteries/ — Available batteries - - `templates/example/modules/den.nix` in vic/den — Example host declarations - - `templates/minimal/modules/den.nix` in vic/den — Minimal den setup with aspects - - **Acceptance Criteria**: - - [ ] `nix eval ".#darwinConfigurations" --json` shows chidi and jason - - [ ] `nix eval ".#nixosConfigurations" --json` shows michael and tahani - - [ ] den.default includes define-user and inputs' batteries - - **QA Scenarios**: - ``` - Scenario: All 4 host configurations exist - Tool: Bash - Preconditions: modules/den.nix and modules/defaults.nix created - Steps: - 1. Run `nix eval ".#darwinConfigurations" --json 2>&1 | nu -c '$in | from json | columns | sort'` - 2. Assert output contains "chidi" and "jason" - 3. Run `nix eval ".#nixosConfigurations" --json 2>&1 | nu -c '$in | from json | columns | sort'` - 4. Assert output contains "michael" and "tahani" - Expected Result: All 4 hosts registered - Evidence: .sisyphus/evidence/task-2-hosts.txt - ``` - - **Commit**: YES (group with 1, 3) - - Message: `feat(den): bootstrap flake with den + import-tree + flake-file` - - Files: `modules/den.nix`, `modules/defaults.nix`, `modules/flake-parts.nix` - - Pre-commit: `alejandra --check .` - -- [x] 3. Utility functions under _lib/ - - **What to do**: - - Create `modules/_lib/` directory (underscore prefix = ignored by import-tree) - - Move `lib/build-rust-package.nix` → `modules/_lib/build-rust-package.nix` (preserve content exactly) - - Convert `profiles/wallpaper.nix` → `modules/_lib/wallpaper.nix` (it's a pure function `{pkgs}: ...`, not a module) - - Convert `profiles/open-project.nix` → `modules/_lib/open-project.nix` (pure function) - - Move `lib/constants.nix` → `modules/_lib/constants.nix` (preserve content exactly — values used by den.base and aspects) - - NOTE: `profiles/packages.nix` is also a function (`callPackage`-compatible) — convert to `modules/_lib/packages.nix` - - **Must NOT do**: - - Do not modify function signatures or return values - - Do not place these under non-underscore paths (import-tree would fail) - - **Recommended Agent Profile**: - - **Category**: `quick` - - Reason: Simple file moves/copies with path updates - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 1 (with Tasks 4, 5, 6) - - **Blocks**: Tasks that reference these utilities (overlays, packages, wallpaper aspects) - - **Blocked By**: Task 1 - - **References**: - - `lib/constants.nix:1-14` — Constants to move - - `lib/build-rust-package.nix` — Rust package builder overlay helper - - `profiles/wallpaper.nix` — Pure function returning derivation - - `profiles/open-project.nix` — Pure function returning derivation - - `profiles/packages.nix` — callPackage-compatible function returning package list - - import-tree docs: `/_` prefix convention for ignoring paths - - **Acceptance Criteria**: - - [ ] `modules/_lib/` directory exists with all 5 files - - [ ] No function files exist under non-underscore paths in modules/ - - [ ] `alejandra --check modules/_lib/` passes - - **QA Scenarios**: - ``` - Scenario: Utility files exist and are ignored by import-tree - Tool: Bash - Preconditions: _lib/ directory created with all files - Steps: - 1. Verify `modules/_lib/constants.nix` exists - 2. Verify `modules/_lib/build-rust-package.nix` exists - 3. Verify `modules/_lib/wallpaper.nix` exists - 4. Verify `modules/_lib/open-project.nix` exists - 5. Verify `modules/_lib/packages.nix` exists - 6. Run `nix flake check --no-build` to confirm import-tree ignores _lib/ - Expected Result: All files present, flake evaluates without trying to import them as modules - Evidence: .sisyphus/evidence/task-3-lib-files.txt - ``` - - **Commit**: YES (group with 1, 2) - - Message: `feat(den): bootstrap flake with den + import-tree + flake-file` - - Files: `modules/_lib/*` - -- [x] 4. Overlays module - - **What to do**: - - Create `modules/overlays.nix` — a flake-parts module that defines all overlays - - Port the current overlay pattern: each overlay takes `inputs` from flake-parts module args and produces a nixpkgs overlay - - Register overlays via `nixpkgs.overlays` in `den.default` or via `flake.overlays` - - Port these overlays: himalaya, jj-ryu (uses _lib/build-rust-package.nix), jj-starship (passthrough), tuicr, zjstatus - - The current dynamic loader pattern (`overlays/default.nix`) is no longer needed — each overlay is defined inline or imported from `_lib/` - - Ensure overlays are applied to all hosts via `den.default.nixos` and `den.default.darwin` or equivalent - - **Must NOT do**: - - Do not create abstractions over the overlay pattern - - Do not change what packages the overlays produce - - Do not publish `flake.overlays` output (user chose to absorb into aspects — if external consumers need it, reconsider) - - **Recommended Agent Profile**: - - **Category**: `quick` - - Reason: Translating existing overlays into a flake-parts module is straightforward - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 1 (with Tasks 3, 5, 6) - - **Blocks**: Tasks 7-9 (overlays must be registered before host configs use overlayed packages) - - **Blocked By**: Tasks 1, 3 - - **References**: - - `overlays/default.nix:1-18` — Current dynamic overlay loader - - `overlays/himalaya.nix:1-3` — Overlay pattern: `{inputs}: final: prev: { himalaya = inputs.himalaya.packages...; }` - - `overlays/jj-ryu.nix` — Uses `_lib/build-rust-package.nix` helper with naersk - - `overlays/jj-starship.nix` — Passes through upstream overlay - - `overlays/zjstatus.nix` — Package from input - - `overlays/tuicr.nix` — Package from input - - **Acceptance Criteria**: - - [ ] `modules/overlays.nix` defines all 5 overlays - - [ ] Overlays are applied to nixpkgs for all hosts - - [ ] `nix eval ".#nixosConfigurations.tahani.config.nixpkgs.overlays" --json` shows overlays present - - **QA Scenarios**: - ``` - Scenario: Overlayed packages are available - Tool: Bash - Preconditions: overlays.nix created and hosts building - Steps: - 1. Run `nix eval ".#nixosConfigurations.tahani.pkgs.himalaya" --json 2>&1` - 2. Assert it evaluates (doesn't error with "himalaya not found") - Expected Result: himalaya package resolves from overlay - Evidence: .sisyphus/evidence/task-4-overlays.txt - ``` - - **Commit**: NO (groups with Wave 1) - -- [x] 5. SOPS secrets aspects (all 4 hosts) - - **What to do**: - - Create `modules/secrets.nix` — a flake-parts module handling SOPS for all hosts - - Use den aspects to define per-host secrets: - - `den.aspects.chidi`: darwin SOPS — `sops.age.keyFile = "/Users/cschmatzler/.config/sops/age/keys.txt"`, disable ssh/gnupg paths - - `den.aspects.jason`: same darwin SOPS pattern - - `den.aspects.michael`: NixOS SOPS — `sops.age.sshKeyPaths`, define secrets (michael-gitea-litestream, michael-gitea-restic-password, michael-gitea-restic-env) with exact same sopsFile paths, owners, groups - - `den.aspects.tahani`: NixOS SOPS — define secrets (tahani-paperless-password, tahani-email-password) with exact same paths and owners - - Import sops-nix modules per-class: `den.default.nixos` imports `inputs.sops-nix.nixosModules.sops`, `den.default.darwin` imports `inputs.sops-nix.darwinModules.sops` - - Use flake-file to declare sops-nix input dependency from this module - - **Must NOT do**: - - Do not change any sopsFile paths, owners, groups, or formats - - Do not re-encrypt secrets - - Do not modify the `secrets/` directory structure - - **Recommended Agent Profile**: - - **Category**: `quick` - - Reason: Direct translation of existing secrets config into den aspects - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 1 (with Tasks 3, 4, 6) - - **Blocks**: Tasks 20-23 (host aspects need secrets available) - - **Blocked By**: Tasks 1, 2 - - **References**: - - `hosts/chidi/secrets.nix:1-5` — Darwin SOPS pattern - - `hosts/jason/secrets.nix` — Same as chidi - - `hosts/michael/secrets.nix:1-22` — NixOS SOPS with gitea secrets (owners, groups, sopsFile paths) - - `hosts/tahani/secrets.nix:1-13` — NixOS SOPS with paperless + email secrets - - `profiles/nixos.nix:57` — `sops.age.sshKeyPaths` for NixOS - - `secrets/` directory — Encrypted secret files (DO NOT MODIFY) - - **Acceptance Criteria**: - - [ ] `nix eval ".#nixosConfigurations.michael.config.sops.secrets" --json | nu -c '$in | from json | columns'` contains michael-gitea-litestream, michael-gitea-restic-password, michael-gitea-restic-env - - [ ] `nix eval ".#nixosConfigurations.tahani.config.sops.secrets" --json | nu -c '$in | from json | columns'` contains tahani-paperless-password, tahani-email-password - - **QA Scenarios**: - ``` - Scenario: SOPS secrets paths preserved exactly - Tool: Bash - Preconditions: secrets.nix module created - Steps: - 1. Run `nix eval ".#nixosConfigurations.michael.config.sops.secrets" --json 2>&1` - 2. Assert keys include michael-gitea-litestream, michael-gitea-restic-password, michael-gitea-restic-env - 3. Run `nix eval ".#nixosConfigurations.tahani.config.sops.secrets" --json 2>&1` - 4. Assert keys include tahani-paperless-password, tahani-email-password - Expected Result: All secrets defined with correct paths - Evidence: .sisyphus/evidence/task-5-sops.txt - - Scenario: Darwin SOPS uses age keyfile, not SSH - Tool: Bash - Preconditions: secrets.nix module created - Steps: - 1. Run `nix eval ".#darwinConfigurations.chidi.config.sops.age.keyFile" 2>&1` - 2. Assert output is "/Users/cschmatzler/.config/sops/age/keys.txt" - Expected Result: Darwin hosts use age keyfile path - Evidence: .sisyphus/evidence/task-5-sops-darwin.txt - ``` - - **Commit**: NO (groups with Wave 1) - -- [x] 6. Deploy-rs module - - **What to do**: - - Create `modules/deploy.nix` — a flake-parts module that configures deploy-rs - - Add `deploy-rs` as a flake input (replacing colmena) - - Define `flake.deploy.nodes.michael` and `flake.deploy.nodes.tahani` with: - - `hostname = ""` - - `profiles.system.user = "root"` - - `profiles.system.path = deploy-rs.lib.x86_64-linux.activate.nixos self.nixosConfigurations.` - - `sshUser = "cschmatzler"` - - Add deploy-rs checks to `flake.checks` via `deploy-rs.lib.x86_64-linux.deployChecks self.deploy` - - Only NixOS hosts — darwin stays local `darwin-rebuild switch` - - Use flake-file to declare deploy-rs input from this module - - **Must NOT do**: - - Do not add darwin deploy-rs nodes (limited support) - - Do not remove the perSystem apps that handle darwin apply - - **Recommended Agent Profile**: - - **Category**: `quick` - - Reason: Straightforward deploy-rs configuration with two nodes - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 1 (with Tasks 3, 4, 5) - - **Blocks**: Task 27 (verification needs deploy-rs nodes) - - **Blocked By**: Tasks 1, 2 - - **References**: - - `flake.nix:110-130` — Current colmena config to replace - - deploy-rs docs: https://github.com/serokell/deploy-rs — Node config format - - Current deployment users: `user = "cschmatzler"` for colmena targetUser - - **Acceptance Criteria**: - - [ ] `nix eval ".#deploy.nodes.michael.hostname"` returns "michael" - - [ ] `nix eval ".#deploy.nodes.tahani.hostname"` returns "tahani" - - [ ] deploy-rs checks registered in flake checks - - **QA Scenarios**: - ``` - Scenario: deploy-rs nodes exist for NixOS hosts only - Tool: Bash - Preconditions: deploy.nix module created - Steps: - 1. Run `nix eval ".#deploy.nodes" --json 2>&1 | nu -c '$in | from json | columns | sort'` - 2. Assert output is ["michael", "tahani"] - 3. Assert no darwin hosts in deploy nodes - Expected Result: Exactly 2 deploy nodes for NixOS hosts - Evidence: .sisyphus/evidence/task-6-deploy.txt - ``` - - **Commit**: NO (groups with Wave 1) - -- [x] 7. Core system aspect (nix settings, shells) - - **What to do**: - - Create `modules/core.nix` — den aspect for core nix/system settings shared across all hosts - - Port `profiles/core.nix` content into `den.aspects.core` with appropriate per-class configs: - - `os` class (or both `nixos` and `darwin`): nix settings (experimental-features, auto-optimise-store), fish shell enable, environment.systemPackages (common tools) - - Include this aspect in `den.default.includes` so all hosts get it - - Remove the `user` and `constants` args dependency — use den context instead - - **Must NOT do**: - - Do not change nix settings values - - Do not add packages not in current core.nix - - **Recommended Agent Profile**: - - **Category**: `quick` - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 2 (with Tasks 8-11) - - **Blocks**: Tasks 12-19 (Wave 3 aspects may depend on core being applied) - - **Blocked By**: Tasks 2, 4 - - **References**: - - `profiles/core.nix` — Current core profile with nix settings, fish, systemPackages - - **Acceptance Criteria**: - - [ ] `den.default.includes` contains core aspect - - [ ] nix experimental-features setting preserved - - **QA Scenarios**: - ``` - Scenario: Core nix settings applied to all hosts - Tool: Bash - Steps: - 1. Run `nix eval ".#nixosConfigurations.michael.config.nix.settings.experimental-features" --json 2>&1` - 2. Assert contains "nix-command" and "flakes" - Expected Result: Nix settings from core.nix applied - Evidence: .sisyphus/evidence/task-7-core.txt - ``` - - **Commit**: NO (groups with Wave 2) - -- [x] 8. Darwin system aspect (system defaults, dock, homebrew, nix-homebrew) - - **What to do**: - - Create `modules/darwin.nix` — den aspect for darwin-specific system configuration - - Port `profiles/darwin.nix` into `den.aspects.darwin-system`: - - `darwin` class: system.defaults (NSGlobalDomain, dock, finder, trackpad, screencapture, screensaver, loginwindow, spaces, WindowManager, menuExtraClock, CustomUserPreferences), nix GC settings, nix trusted-users - - User creation for darwin (users.users.${user}) — or rely on den.provides.define-user - - `home-manager.useGlobalPkgs = true` - - Port `profiles/dock.nix` — the `local.dock.*` custom option module. Absorb into the darwin aspect or create `modules/dock.nix` - - Port `profiles/homebrew.nix` into `modules/homebrew.nix` — nix-homebrew configuration with taps, casks, etc. - - Include darwin-system aspect in darwin host aspects (chidi, jason) - - Wire nix-homebrew module import via `den.aspects.darwin-system.darwin` - - State version: `system.stateVersion = 6` (from constants.stateVersions.darwin) - - **Must NOT do**: - - Do not change any system.defaults values - - Do not change dock entries - - Do not change homebrew taps or cask lists - - **Recommended Agent Profile**: - - **Category**: `unspecified-high` - - Reason: Multiple complex darwin profiles need merging into aspects with correct module imports - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 2 (with Tasks 7, 9-11) - - **Blocks**: Tasks 17, 22, 23 (desktop and host-specific darwin) - - **Blocked By**: Tasks 2, 4 - - **References**: - - `profiles/darwin.nix:1-125` — Full darwin system config (system defaults, users, nix settings) - - `profiles/dock.nix` — Custom `local.dock.*` option module with entries - - `profiles/homebrew.nix` — Homebrew config with taps, brews, casks - - `flake.nix:77-94` — Current darwin configuration wiring (nix-homebrew module, homebrew taps) - - **Acceptance Criteria**: - - [ ] All system.defaults values preserved - - [ ] nix-homebrew configured with same taps - - [ ] dock entries preserved - - [ ] `nix eval ".#darwinConfigurations.chidi.config.system.defaults.NSGlobalDomain.AppleInterfaceStyle"` returns null - - **QA Scenarios**: - ``` - Scenario: Darwin system defaults applied - Tool: Bash - Steps: - 1. Run `nix eval ".#darwinConfigurations.chidi.config.system.defaults.dock.autohide" 2>&1` - 2. Assert output is "true" - Expected Result: Dock autohide preserved from darwin.nix - Evidence: .sisyphus/evidence/task-8-darwin.txt - ``` - - **Commit**: NO (groups with Wave 2) - -- [x] 9. NixOS system aspect (boot, sudo, systemd, users) - - **What to do**: - - Create `modules/nixos-system.nix` — den aspect for NixOS-specific system configuration - - Port `profiles/nixos.nix` into `den.aspects.nixos-system`: - - `nixos` class: security.sudo, boot (systemd-boot, EFI, kernel modules, latest kernel), nix settings (trusted-users, gc, nixPath), time.timeZone, user creation with groups - - `home-manager.useGlobalPkgs = true` and `home-manager.sharedModules` — but this should now be handled by den's HM integration battery (no manual _module.args) - - Root user SSH authorized keys from constants - - State version: `system.stateVersion = "25.11"` - - `sops.age.sshKeyPaths` for NixOS hosts - - **Must NOT do**: - - Do not change sudo rules - - Do not change boot loader settings - - Do not change user groups - - **Recommended Agent Profile**: - - **Category**: `unspecified-high` - - Reason: NixOS system profile has multiple interconnected settings that need careful migration - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 2 (with Tasks 7, 8, 10, 11) - - **Blocks**: Tasks 20, 21, 24 (server and network aspects) - - **Blocked By**: Tasks 2, 4 - - **References**: - - `profiles/nixos.nix:1-79` — Full NixOS system config (sudo, boot, nix, users, HM wiring) - - `lib/constants.nix:4-7` — SSH keys for root and user - - **Acceptance Criteria**: - - [ ] sudo rules preserved exactly - - [ ] boot settings (systemd-boot, kernel) preserved - - [ ] No manual `_module.args` or `sharedModules` for HM — den handles it - - [ ] Root SSH authorized keys set - - **QA Scenarios**: - ``` - Scenario: NixOS boot config preserved - Tool: Bash - Steps: - 1. Run `nix eval ".#nixosConfigurations.michael.config.boot.loader.systemd-boot.enable" 2>&1` - 2. Assert output is "true" - Expected Result: Boot settings from nixos.nix preserved - Evidence: .sisyphus/evidence/task-9-nixos.txt - ``` - - **Commit**: NO (groups with Wave 2) - -- [x] 10. User aspect (cschmatzler — primary user) - - **What to do**: - - Create `modules/user.nix` — den aspect for the cschmatzler user - - Define `den.aspects.cschmatzler`: - - `includes`: `den.provides.primary-user`, `(den.provides.user-shell "nushell")`, relevant shared aspects - - `homeManager`: basic home config from `profiles/home.nix` (programs.home-manager.enable, home.packages via callPackage _lib/packages.nix, home.activation for wallpaper on darwin) - - SSH authorized keys from constants - - The user aspect is the central hub that `includes` all feature aspects the user wants - - Per-host email overrides will be in host aspects (Tasks 22-23), not here - - Default email: `homeManager.programs.git.settings.user.email` left for host-specific override - - **Must NOT do**: - - Do not add features not in current user config - - Do not set git email here (it's per-host) - - **Recommended Agent Profile**: - - **Category**: `quick` - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 2 (with Tasks 7-9, 11) - - **Blocks**: Tasks 12-19 (HM aspects) - - **Blocked By**: Task 2 - - **References**: - - `profiles/home.nix:1-24` — Home base config (home-manager enable, packages, wallpaper activation) - - `lib/constants.nix:2` — User name "cschmatzler" - - `lib/constants.nix:4-7` — SSH authorized keys - - den batteries docs: https://den.oeiuwq.com/guides/batteries/ — primary-user, user-shell - - **Acceptance Criteria**: - - [ ] `den.aspects.cschmatzler` defined with primary-user and user-shell batteries - - [ ] Home packages list from packages.nix applied - - **QA Scenarios**: - ``` - Scenario: User aspect creates correct system user - Tool: Bash - Steps: - 1. Run `nix eval ".#nixosConfigurations.michael.config.users.users.cschmatzler.isNormalUser" 2>&1` - 2. Assert output is "true" - Expected Result: User created with isNormalUser - Evidence: .sisyphus/evidence/task-10-user.txt - ``` - - **Commit**: NO (groups with Wave 2) - -- [x] 11. perSystem apps module - - **What to do**: - - Create `modules/apps.nix` — a flake-parts module that defines perSystem apps - - Port the current `perSystem` block from flake.nix that creates apps: build, apply, build-switch, rollback - - These apps reference `apps/${system}/${name}` shell scripts — keep this mechanism - - Ensure apps are available for both x86_64-linux and aarch64-darwin - - **Must NOT do**: - - Do not change app behavior (the actual script rewrite to Nushell is Task 29) - - **Recommended Agent Profile**: - - **Category**: `quick` - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 2 (with Tasks 7-10) - - **Blocks**: Task 27 (verification) - - **Blocked By**: Task 1 - - **References**: - - `flake.nix:143-165` — Current perSystem apps block - - `apps/` directory — Shell scripts for each platform - - **Acceptance Criteria**: - - [ ] `nix eval ".#apps.aarch64-darwin" --json | nu -c '$in | from json | columns'` includes build, apply - - [ ] `nix eval ".#apps.x86_64-linux" --json | nu -c '$in | from json | columns'` includes build, apply - - **QA Scenarios**: - ``` - Scenario: perSystem apps accessible - Tool: Bash - Steps: - 1. Run `nix eval ".#apps.aarch64-darwin" --json 2>&1 | nu -c '$in | from json | columns | sort'` - 2. Assert contains apply, build, build-switch, rollback - Expected Result: All 4 apps registered - Evidence: .sisyphus/evidence/task-11-apps.txt - ``` - - **Commit**: NO (groups with Wave 2) - -- [ ] 12. Shell aspects (nushell, bash, zsh, starship) - - **What to do**: - - Create `modules/shell.nix` — den aspect grouping shell-related HM config - - Port into `den.aspects.shell.homeManager`: nushell config (`profiles/nushell.nix` — programs.nushell with aliases, env, config, platform-conditional PATH), bash config (`profiles/bash.nix`), zsh config (`profiles/zsh.nix`), starship config (`profiles/starship.nix` — programs.starship with settings) - - Keep `stdenv.isDarwin` platform checks in HM config — these are correct in HM context - - Include shell aspect in user aspect (Task 10's `den.aspects.cschmatzler.includes`) - - **Must NOT do**: - - Do not change shell aliases, env vars, or config values - - Do not split into 4 separate aspects (these are naturally grouped) - - **Recommended Agent Profile**: - - **Category**: `quick` - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 3 (with Tasks 13-19) - - **Blocks**: Tasks 20-25 - - **Blocked By**: Tasks 7, 10 - - **References**: - - `profiles/nushell.nix` — Nushell config with platform conditionals - - `profiles/bash.nix` — Bash config - - `profiles/zsh.nix` — Zsh config - - `profiles/starship.nix` — Starship prompt config - - **Acceptance Criteria**: - - [ ] All shell programs configured in HM - - [ ] Platform-conditional nushell PATH preserved - - **QA Scenarios**: - ``` - Scenario: Shell programs enabled in HM - Tool: Bash - Steps: - 1. Run `nix eval ".#darwinConfigurations.chidi.config.home-manager.users.cschmatzler.programs.nushell.enable" 2>&1` - 2. Assert true - Expected Result: Nushell enabled - Evidence: .sisyphus/evidence/task-12-shell.txt - ``` - - **Commit**: NO (groups with Wave 3) - -- [ ] 13. Dev tools aspects (git, jujutsu, lazygit, jjui, direnv, mise) - - **What to do**: - - Create `modules/dev-tools.nix` — den aspect grouping developer tools HM config - - Port into `den.aspects.dev-tools.homeManager`: git config (`profiles/git.nix` — programs.git with aliases, settings, ignores, diff tools), jujutsu config (`profiles/jujutsu.nix`), lazygit (`profiles/lazygit.nix`), jjui (`profiles/jjui.nix`), direnv (`profiles/direnv.nix`), mise (`profiles/mise.nix`) - - NOTE: Do NOT set `programs.git.settings.user.email` here — that's per-host - - Include dev-tools aspect in user aspect - - **Must NOT do**: - - Do not change git aliases or settings - - Do not set git email (per-host override) - - **Recommended Agent Profile**: - - **Category**: `quick` - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 3 (with Tasks 12, 14-19) - - **Blocks**: Tasks 20-25 - - **Blocked By**: Tasks 7, 10 - - **References**: - - `profiles/git.nix` — Git config with delta, aliases, ignores - - `profiles/jujutsu.nix` — Jujutsu VCS config - - `profiles/lazygit.nix` — Lazygit TUI - - `profiles/jjui.nix` — jj TUI - - `profiles/direnv.nix` — Direnv with nix-direnv - - `profiles/mise.nix` — Mise version manager - - **Acceptance Criteria**: - - [ ] All dev tools configured - - [ ] Git email NOT set in this aspect - - **QA Scenarios**: - ``` - Scenario: Git configured without email override - Tool: Bash - Steps: - 1. Run `nix eval ".#darwinConfigurations.chidi.config.home-manager.users.cschmatzler.programs.git.enable" 2>&1` - 2. Assert true - Expected Result: Git enabled in HM - Evidence: .sisyphus/evidence/task-13-devtools.txt - ``` - - **Commit**: NO (groups with Wave 3) - -- [ ] 14. Editor aspects (neovim/nixvim) - - **What to do**: - - Create `modules/neovim/` directory with den aspect for neovim/nixvim - - Port the entire `profiles/neovim/` directory (16+ files) into den aspect structure - - The main module (`profiles/neovim/default.nix`) imports all plugin configs — replicate this structure - - Import `inputs.nixvim.homeModules.nixvim` in the HM class config - - Use flake-file to declare nixvim input dependency from this module - - The neovim sub-files can be imported via the module's own imports (NOT via import-tree — they're HM modules, not flake-parts modules). Place them under `modules/neovim/_plugins/` or similar to avoid import-tree scanning them, OR use den aspect's `homeManager.imports` - - **Must NOT do**: - - Do not change any neovim plugin configurations - - Do not restructure plugin files unnecessarily - - **Recommended Agent Profile**: - - **Category**: `unspecified-high` - - Reason: neovim config is 16+ files with complex imports — needs careful migration of the import chain - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 3 (with Tasks 12-13, 15-19) - - **Blocks**: Tasks 20-23 - - **Blocked By**: Tasks 7, 10 - - **References**: - - `profiles/neovim/default.nix` — Main neovim module (imports all plugins) - - `profiles/neovim/` — 16+ plugin config files - - nixvim input: `inputs.nixvim.homeModules.nixvim` - - **Acceptance Criteria**: - - [ ] All neovim plugins configured - - [ ] nixvim HM module imported - - **QA Scenarios**: - ``` - Scenario: Nixvim enabled in home-manager - Tool: Bash - Steps: - 1. Run `nix eval ".#darwinConfigurations.chidi.config.home-manager.users.cschmatzler.programs.nixvim.enable" 2>&1` - 2. Assert true (or check that nixvim module is imported) - Expected Result: Nixvim working - Evidence: .sisyphus/evidence/task-14-neovim.txt - ``` - - **Commit**: NO (groups with Wave 3) - -- [ ] 15. Terminal aspects (ghostty, zellij, yazi, bat, fzf, ripgrep, zoxide) - - **What to do**: - - Create `modules/terminal.nix` — den aspect for terminal tools HM config - - Port: ghostty (`profiles/ghostty.nix`), bat (`profiles/bat.nix`), fzf (`profiles/fzf.nix`), ripgrep (`profiles/ripgrep.nix`), zoxide (`profiles/zoxide.nix`), yazi (`profiles/yazi.nix`) - - Create `modules/zellij.nix` — separate aspect for zellij because it needs per-host behavior - - Port `profiles/zellij.nix` but REMOVE the `osConfig.networking.hostName == "tahani"` check - - Instead, the tahani-specific zellij auto-start behavior goes in Task 21 (tahani host aspect) - - **Must NOT do**: - - Do not use hostname string comparisons - - Do not change tool configurations - - **Recommended Agent Profile**: - - **Category**: `quick` - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 3 (with Tasks 12-14, 16-19) - - **Blocks**: Tasks 20-25 - - **Blocked By**: Tasks 7, 10 - - **References**: - - `profiles/zellij.nix` — Zellij with host-specific autostart check (line 20: `osConfig.networking.hostName == "tahani"`) - - `profiles/ghostty.nix`, `profiles/bat.nix`, `profiles/fzf.nix`, `profiles/ripgrep.nix`, `profiles/zoxide.nix`, `profiles/yazi.nix` - - **Acceptance Criteria**: - - [ ] All terminal tools configured - - [ ] No hostname string comparisons in shared aspects - - [ ] Zellij base config without host-specific auto-start - - **QA Scenarios**: - ``` - Scenario: Terminal tools enabled - Tool: Bash - Steps: - 1. Run `nix eval ".#darwinConfigurations.chidi.config.home-manager.users.cschmatzler.programs.bat.enable" 2>&1` - 2. Assert true - Expected Result: bat enabled in HM - Evidence: .sisyphus/evidence/task-15-terminal.txt - ``` - - **Commit**: NO (groups with Wave 3) - -- [ ] 16. Communication aspects (himalaya, mbsync, ssh) - - **What to do**: - - Create `modules/email.nix` — den aspect for email (himalaya + mbsync) - - Port `profiles/himalaya.nix` — the himalaya HM module that creates a wrapper script (`writeShellApplication` around himalaya binary with IMAP password from sops) - - Port `profiles/mbsync.nix` — mbsync HM config - - CRITICAL: The himalaya wrapper package is currently accessed from NixOS scope in tahani (cross-module dependency). In den, instead create the wrapper within the `homeManager` class AND also make it available to the NixOS `nixos` class via the overlay package (himalaya overlay already exists). The inbox-triage systemd service in Task 21 should use `pkgs.himalaya` (from overlay) directly, not reach into HM config. - - Create `modules/ssh-client.nix` — den aspect for SSH client config - - Port `profiles/ssh.nix` — SSH client HM config with platform-conditional paths - - **Must NOT do**: - - Do not create cross-module dependencies (HM → NixOS reads) - - Do not change himalaya or mbsync settings - - **Recommended Agent Profile**: - - **Category**: `unspecified-high` - - Reason: Himalaya cross-dependency redesign is architecturally critical - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 3 (with Tasks 12-15, 17-19) - - **Blocks**: Tasks 20, 21 - - **Blocked By**: Tasks 7, 10 - - **References**: - - `profiles/himalaya.nix` — Himalaya HM module with writeShellApplication wrapper - - `profiles/mbsync.nix` — mbsync config - - `profiles/ssh.nix` — SSH client config with platform paths - - `hosts/tahani/default.nix:9` — The cross-module dependency to eliminate: `himalaya = config.home-manager.users.${user}.programs.himalaya.package` - - `overlays/himalaya.nix:1-3` — Himalaya overlay (packages from input) - - **Acceptance Criteria**: - - [ ] Himalaya configured in HM - - [ ] No cross-module HM→NixOS reads - - [ ] SSH client configured with correct platform paths - - **QA Scenarios**: - ``` - Scenario: Himalaya configured without cross-module dependency - Tool: Bash - Steps: - 1. Grep new modules/ for "config.home-manager.users" - 2. Assert zero matches (no HM config reads from NixOS scope) - Expected Result: No cross-module dependency - Evidence: .sisyphus/evidence/task-16-email.txt - ``` - - **Commit**: NO (groups with Wave 3) - -- [ ] 17. Desktop aspects (aerospace, home base) - - **What to do**: - - Create `modules/desktop.nix` — den aspect for desktop/GUI HM config - - Port `profiles/aerospace.nix` — AeroSpace tiling WM config (darwin-only HM module) - - The wallpaper activation from `profiles/home.nix` is already in _lib/wallpaper.nix — wire it via the user aspect's darwin HM config - - Include fonts.fontconfig.enable for darwin hosts (currently in chidi/jason host configs) - - **Must NOT do**: - - Do not change aerospace settings - - **Recommended Agent Profile**: - - **Category**: `quick` - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 3 (with Tasks 12-16, 18-19) - - **Blocks**: Tasks 22, 23 - - **Blocked By**: Tasks 7, 8, 10 - - **References**: - - `profiles/aerospace.nix` — AeroSpace WM config - - `hosts/chidi/default.nix:50` — `fonts.fontconfig.enable = true` - - **Acceptance Criteria**: - - [ ] AeroSpace configured in darwin HM - - [ ] fonts.fontconfig.enable set for darwin hosts - - **QA Scenarios**: - ``` - Scenario: AeroSpace configured for darwin hosts - Tool: Bash - Steps: - 1. Run `nix eval ".#darwinConfigurations.chidi.config.home-manager.users.cschmatzler.programs.aerospace.enable" 2>&1` (or check relevant config) - Expected Result: AeroSpace enabled - Evidence: .sisyphus/evidence/task-17-desktop.txt - ``` - - **Commit**: NO (groups with Wave 3) - -- [ ] 18. AI tools aspects (opencode, claude-code) - - **What to do**: - - Create `modules/ai-tools.nix` — den aspect for AI coding tools - - Port `profiles/opencode.nix` — references `inputs.llm-agents.packages...opencode` - - Port `profiles/claude-code.nix` — references `inputs.llm-agents.packages...claude-code` - - These need `inputs` access — use den's `inputs'` battery or access `inputs` from flake-parts module args - - Use flake-file to declare llm-agents input dependency - - NOTE: The opencode config may include `profiles/opencode/` directory content - - **Must NOT do**: - - Do not change opencode or claude-code settings - - **Recommended Agent Profile**: - - **Category**: `quick` - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 3 (with Tasks 12-17, 19) - - **Blocks**: Task 21 (tahani uses opencode in systemd service) - - **Blocked By**: Tasks 7, 10 - - **References**: - - `profiles/opencode.nix` — OpenCode HM config using inputs.llm-agents - - `profiles/claude-code.nix` — Claude Code HM config using inputs.llm-agents - - `profiles/opencode/` — OpenCode config directory (if exists) - - **Acceptance Criteria**: - - [ ] Both AI tools configured in HM - - [ ] inputs.llm-agents accessed correctly (not via specialArgs) - - **QA Scenarios**: - ``` - Scenario: AI tools packages available - Tool: Bash - Steps: - 1. Verify opencode and claude-code are in home packages (nix eval) - Expected Result: Both tools in user's home packages - Evidence: .sisyphus/evidence/task-18-ai.txt - ``` - - **Commit**: NO (groups with Wave 3) - -- [ ] 19. Miscellaneous aspects (atuin, zk) - - **What to do**: - - Create `modules/atuin.nix` — den aspect for atuin (shell history sync) - - Port `profiles/atuin.nix` into `den.aspects.atuin.homeManager` - - Create `modules/zk.nix` — den aspect for zk (zettelkasten) - - Port `profiles/zk.nix` into `den.aspects.zk.homeManager` - - Include both in user aspect - - **Must NOT do**: - - Do not change settings - - **Recommended Agent Profile**: - - **Category**: `quick` - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 3 (with Tasks 12-18) - - **Blocks**: Tasks 20-25 - - **Blocked By**: Tasks 7, 10 - - **References**: - - `profiles/atuin.nix` — Atuin config - - `profiles/zk.nix` — Zk zettelkasten config - - **Acceptance Criteria**: - - [ ] Atuin and zk configured in HM - - **QA Scenarios**: - ``` - Scenario: Atuin enabled - Tool: Bash - Steps: - 1. Run `nix eval ".#darwinConfigurations.chidi.config.home-manager.users.cschmatzler.programs.atuin.enable" 2>&1` - 2. Assert true - Expected Result: Atuin enabled - Evidence: .sisyphus/evidence/task-19-misc.txt - ``` - - **Commit**: NO (groups with Wave 3) - -- [ ] 20. Server aspects — michael (gitea + litestream + restic) - - **What to do**: - - Create `modules/michael.nix` — den aspect for michael host - - Port michael-specific config into `den.aspects.michael`: - - `nixos` class: import disko module (`inputs.disko.nixosModules.disko`), import disk-config.nix and hardware-configuration.nix (place originals under `modules/_hosts/michael/` with `_` prefix to avoid import-tree) - - `nixos` class: gitea service config — absorb the entire `modules/gitea.nix` custom module into this aspect. The `my.gitea` options become direct service configuration (services.gitea, services.litestream, services.restic). Use SOPS secrets from Task 5. - - `nixos` class: `modulesPath` imports (installer/scan/not-detected.nix, profiles/qemu-guest.nix) - - `nixos` class: `networking.hostName = "michael"` - - Include: nixos-system, core, openssh, fail2ban, tailscale aspects - - HM: minimal imports — only nushell, home base, ssh, nixvim - - Git email override: `homeManager.programs.git.settings.user.email` is NOT set (michael has no email override in current config) - - Wire disko input via flake-file - - **Must NOT do**: - - Do not change gitea service configuration values - - Do not change disk-config or hardware-configuration - - Do not create abstractions over gitea's backup system - - **Recommended Agent Profile**: - - **Category**: `deep` - - Reason: Complex server with custom gitea module absorption, disko, hardware config, and multiple service interactions - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 4 (with Tasks 21-25) - - **Blocks**: Task 27 - - **Blocked By**: Tasks 5, 9, 14, 16 - - **References**: - - `hosts/michael/default.nix:1-48` — Full michael host config - - `hosts/michael/disk-config.nix` — Disko partition config - - `hosts/michael/hardware-configuration.nix` — Hardware config - - `modules/gitea.nix` — Custom my.gitea module (litestream, restic, s3) to absorb - - `hosts/michael/secrets.nix:1-22` — SOPS secrets (already in Task 5) - - **Acceptance Criteria**: - - [ ] `nix build ".#nixosConfigurations.michael.config.system.build.toplevel"` succeeds - - [ ] Gitea service configured with litestream and restic - - [ ] Disko disk-config preserved - - **QA Scenarios**: - ``` - Scenario: Michael host builds successfully - Tool: Bash - Steps: - 1. Run `nix build ".#nixosConfigurations.michael.config.system.build.toplevel" --dry-run 2>&1` - 2. Assert exit code 0 - Expected Result: Michael builds without errors - Evidence: .sisyphus/evidence/task-20-michael.txt - - Scenario: Gitea service configured - Tool: Bash - Steps: - 1. Run `nix eval ".#nixosConfigurations.michael.config.services.gitea.enable" 2>&1` - 2. Assert true - Expected Result: Gitea enabled - Evidence: .sisyphus/evidence/task-20-gitea.txt - ``` - - **Commit**: NO (groups with Wave 4) - -- [ ] 21. Server aspects — tahani (adguard, paperless, docker, inbox-triage) - - **What to do**: - - Create `modules/tahani.nix` — den aspect for tahani host - - Port tahani-specific config into `den.aspects.tahani`: - - `nixos` class: import tahani-specific files (adguardhome.nix, cache.nix, networking.nix, paperless.nix — place under `modules/_hosts/tahani/`) - - `nixos` class: `networking.hostName = "tahani"`, `virtualisation.docker.enable`, docker group for user - - `nixos` class: swap device config - - `nixos` class: **Inbox-triage systemd service** — REDESIGNED to avoid cross-module dependency: - - Use `pkgs.himalaya` (from overlay, NOT from HM config) for the himalaya binary - - Use `inputs.llm-agents.packages.${pkgs.stdenv.hostPlatform.system}.opencode` for opencode binary - - Define systemd service and timer exactly as current - - Include: nixos-system, core, openssh, tailscale aspects - - HM: all the profiles that tahani currently imports (most shared aspects + himalaya, mbsync) - - HM: git email override: `homeManager.programs.git.settings.user.email = "christoph@schmatzler.com"` - - HM: zellij auto-start override (the tahani-specific behavior from zellij.nix) - - **Must NOT do**: - - Do not read HM config from NixOS scope (no `config.home-manager.users...`) - - Do not change service configs (adguard, paperless, docker) - - **Recommended Agent Profile**: - - **Category**: `deep` - - Reason: Most complex host — has the himalaya cross-dependency redesign, multiple services, and the most HM profiles - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 4 (with Tasks 20, 22-25) - - **Blocks**: Task 27 - - **Blocked By**: Tasks 5, 9, 16, 18 - - **References**: - - `hosts/tahani/default.nix:1-94` — Full tahani config with cross-module dependency - - `hosts/tahani/adguardhome.nix` — AdGuard Home service config - - `hosts/tahani/cache.nix` — Cache config - - `hosts/tahani/networking.nix` — Network config - - `hosts/tahani/paperless.nix` — Paperless-NGX service config - - `profiles/zellij.nix:20` — The hostname check to replace with per-host override - - `overlays/himalaya.nix` — Himalaya available as `pkgs.himalaya` via overlay - - **Acceptance Criteria**: - - [ ] `nix build ".#nixosConfigurations.tahani.config.system.build.toplevel"` succeeds - - [ ] Inbox-triage systemd service uses `pkgs.himalaya` (overlay), NOT HM config read - - [ ] Zero instances of `config.home-manager.users` in any module - - [ ] Zellij auto-start is tahani-specific (not hostname comparison) - - **QA Scenarios**: - ``` - Scenario: Tahani builds without cross-module dependency - Tool: Bash - Steps: - 1. Run `nix build ".#nixosConfigurations.tahani.config.system.build.toplevel" --dry-run 2>&1` - 2. Assert exit code 0 - 3. Grep modules/ for "config.home-manager.users" - 4. Assert zero matches - Expected Result: Tahani builds, no HM→NixOS cross-reads - Evidence: .sisyphus/evidence/task-21-tahani.txt - - Scenario: Docker enabled on tahani - Tool: Bash - Steps: - 1. Run `nix eval ".#nixosConfigurations.tahani.config.virtualisation.docker.enable" 2>&1` - 2. Assert true - Expected Result: Docker enabled - Evidence: .sisyphus/evidence/task-21-docker.txt - ``` - - **Commit**: NO (groups with Wave 4) - -- [ ] 22. Host aspects — chidi (work-specific) - - **What to do**: - - Create `modules/chidi.nix` — den aspect for chidi (work laptop) - - Define `den.aspects.chidi`: - - Include: darwin-system, core, tailscale, all shared user aspects - - `darwin` class: `environment.systemPackages = [pkgs.slack]` (work-specific) - - `darwin` class: `networking.hostName = "chidi"`, `networking.computerName = "chidi"` - - `homeManager` class: `programs.git.settings.user.email = "christoph@tuist.dev"` (work email) - - `homeManager` class: `fonts.fontconfig.enable = true` - - **Must NOT do**: - - Do not add work-specific packages beyond Slack - - Do not change git email - - **Recommended Agent Profile**: - - **Category**: `quick` - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 4 (with Tasks 20-21, 23-25) - - **Blocks**: Task 27 - - **Blocked By**: Tasks 5, 8, 17 - - **References**: - - `hosts/chidi/default.nix:1-57` — Current chidi config - - `hosts/chidi/secrets.nix:1-5` — Already handled in Task 5 - - **Acceptance Criteria**: - - [ ] `nix build ".#darwinConfigurations.chidi.system"` succeeds - - [ ] Slack in systemPackages - - [ ] Git email = "christoph@tuist.dev" - - **QA Scenarios**: - ``` - Scenario: Chidi builds with work email - Tool: Bash - Steps: - 1. Run `nix build ".#darwinConfigurations.chidi.system" --dry-run 2>&1` - 2. Assert exit code 0 - 3. Run `nix eval ".#darwinConfigurations.chidi.config.home-manager.users.cschmatzler.programs.git.settings.user.email" 2>&1` - 4. Assert output is "christoph@tuist.dev" - Expected Result: Chidi builds, work email set - Evidence: .sisyphus/evidence/task-22-chidi.txt - ``` - - **Commit**: NO (groups with Wave 4) - -- [ ] 23. Host aspects — jason (personal-specific) - - **What to do**: - - Create `modules/jason.nix` — den aspect for jason (personal laptop) - - Define `den.aspects.jason`: - - Include: darwin-system, core, tailscale, all shared user aspects - - `darwin` class: `networking.hostName = "jason"`, `networking.computerName = "jason"` - - `homeManager` class: `programs.git.settings.user.email = "christoph@schmatzler.com"` (personal email) - - `homeManager` class: `fonts.fontconfig.enable = true` - - **Must NOT do**: - - Do not add packages not in current jason config - - **Recommended Agent Profile**: - - **Category**: `quick` - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 4 (with Tasks 20-22, 24-25) - - **Blocks**: Task 27 - - **Blocked By**: Tasks 5, 8, 17 - - **References**: - - `hosts/jason/default.nix:1-52` — Current jason config - - **Acceptance Criteria**: - - [ ] `nix build ".#darwinConfigurations.jason.system"` succeeds - - [ ] Git email = "christoph@schmatzler.com" - - **QA Scenarios**: - ``` - Scenario: Jason builds with personal email - Tool: Bash - Steps: - 1. Run `nix build ".#darwinConfigurations.jason.system" --dry-run 2>&1` - 2. Assert exit code 0 - Expected Result: Jason builds successfully - Evidence: .sisyphus/evidence/task-23-jason.txt - ``` - - **Commit**: NO (groups with Wave 4) - -- [ ] 24. Network aspects (openssh, fail2ban, tailscale, postgresql) - - **What to do**: - - Create `modules/network.nix` — den aspect for network services - - Port `profiles/openssh.nix` → `den.aspects.openssh.nixos` (SSH server config) - - Port `profiles/fail2ban.nix` → `den.aspects.fail2ban.nixos` - - Port `profiles/tailscale.nix` → `den.aspects.tailscale` with per-class configs (nixos + darwin support, uses `lib.optionalAttrs pkgs.stdenv.isLinux` currently — convert to per-class) - - Port `profiles/postgresql.nix` → `den.aspects.postgresql.nixos` (if used by any host) - - Include these in appropriate host aspects - - **Must NOT do**: - - Do not change SSH, fail2ban, or tailscale settings - - **Recommended Agent Profile**: - - **Category**: `quick` - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 4 (with Tasks 20-23, 25) - - **Blocks**: Task 27 - - **Blocked By**: Task 9 - - **References**: - - `profiles/openssh.nix` — OpenSSH server config - - `profiles/fail2ban.nix` — Fail2ban config - - `profiles/tailscale.nix` — Tailscale with platform conditionals - - `profiles/postgresql.nix` — PostgreSQL config - - **Acceptance Criteria**: - - [ ] All network services configured - - [ ] Tailscale works on both darwin and nixos - - **QA Scenarios**: - ``` - Scenario: Tailscale enabled on all hosts - Tool: Bash - Steps: - 1. Run `nix eval ".#nixosConfigurations.michael.config.services.tailscale.enable" 2>&1` - 2. Assert true - Expected Result: Tailscale enabled - Evidence: .sisyphus/evidence/task-24-network.txt - ``` - - **Commit**: NO (groups with Wave 4) - -- [ ] 25. Packages aspect (system packages list) - - **What to do**: - - Ensure the home.packages list from `_lib/packages.nix` is wired into the user aspect - - The `callPackage` pattern for packages.nix should be replicated — import `_lib/packages.nix` and pass required args - - Ensure platform-conditional packages (`lib.optionals stdenv.isDarwin/isLinux`) are preserved - - Remove colmena from the package list, add deploy-rs CLI if needed - - **Must NOT do**: - - Do not add packages not in current packages.nix (except deploy-rs CLI) - - Do not remove colmena replacement from packages without confirming - - **Recommended Agent Profile**: - - **Category**: `quick` - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 4 (with Tasks 20-24) - - **Blocks**: Task 27 - - **Blocked By**: Task 7 - - **References**: - - `profiles/packages.nix` — Full package list (moved to _lib/packages.nix in Task 3) - - `profiles/home.nix:13` — `home.packages = pkgs.callPackage ./packages.nix {inherit inputs;};` - - **Acceptance Criteria**: - - [ ] All packages from current list present - - [ ] Platform-conditional packages preserved - - **QA Scenarios**: - ``` - Scenario: Home packages include expected tools - Tool: Bash - Steps: - 1. Verify packages.nix is loaded and packages are in home.packages - Expected Result: Packages available - Evidence: .sisyphus/evidence/task-25-packages.txt - ``` - - **Commit**: NO (groups with Wave 4) - -- [ ] 26. Remove old structure - - **What to do**: - - Delete `hosts/` directory entirely - - Delete `profiles/` directory entirely - - Delete `modules/_legacy/` directory (old NixOS modules moved here by Task 1, now fully absorbed into den aspects) - - Delete `overlays/` directory entirely (now in modules/overlays.nix) - - Delete `lib/` directory entirely (now in modules/_lib/) - - Keep `secrets/` directory (encrypted files, unchanged) - - Keep `apps/` directory (rewritten to Nushell by Task 29) - - Keep `.sops.yaml` (unchanged) - - Verify no broken references remain - - **Must NOT do**: - - Do not delete `secrets/`, `apps/`, `.sops.yaml`, or `alejandra.toml` - - **Recommended Agent Profile**: - - **Category**: `quick` - - **Skills**: [`git-master`] - - **Parallelization**: - - **Can Run In Parallel**: NO - - **Parallel Group**: Wave 5 (after Task 27 confirms all builds pass) - - **Blocks**: F1-F4 - - **Blocked By**: Task 27 - - **References**: - - All old directories to remove: hosts/, profiles/, overlays/, lib/ - - **Acceptance Criteria**: - - [ ] Old directories removed - - [ ] `nix flake check` still passes after removal - - [ ] No broken file references - - **QA Scenarios**: - ``` - Scenario: Old structure removed, builds still pass - Tool: Bash - Steps: - 1. Verify hosts/ directory doesn't exist - 2. Verify profiles/ directory doesn't exist - 3. Run `nix flake check --no-build 2>&1` - 4. Assert exit code 0 - Expected Result: Clean structure, still evaluates - Evidence: .sisyphus/evidence/task-26-cleanup.txt - ``` - - **Commit**: YES - - Message: `chore: remove old host-centric structure` - - Files: deleted directories - - Pre-commit: `nix flake check --no-build && alejandra --check .` - -- [ ] 27. Full build verification all 4 hosts - - **What to do**: - - Build ALL 4 host configurations (or dry-run if cross-platform): - - `nix build ".#darwinConfigurations.chidi.system" --dry-run` - - `nix build ".#darwinConfigurations.jason.system" --dry-run` - - `nix build ".#nixosConfigurations.michael.config.system.build.toplevel" --dry-run` - - `nix build ".#nixosConfigurations.tahani.config.system.build.toplevel" --dry-run` - - Run `nix flake check` - - Run `alejandra --check .` - - Verify deploy-rs nodes: `nix eval ".#deploy.nodes" --json` - - Verify zero specialArgs: grep for specialArgs in all .nix files - - Verify no hostname comparisons in shared aspects - - Verify no HM→NixOS cross-reads - - **Must NOT do**: - - Do not skip any host build - - **Recommended Agent Profile**: - - **Category**: `deep` - - Reason: Comprehensive verification requiring multiple build commands and assertions - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: NO - - **Parallel Group**: Wave 5 (after all implementation) - - **Blocks**: Tasks 26, 28, F1-F4 - - **Blocked By**: Tasks 20-25 - - **References**: - - Definition of Done section of this plan - - All acceptance criteria from all tasks - - **Acceptance Criteria**: - - [ ] All 4 hosts build (or dry-run) successfully - - [ ] `nix flake check` passes - - [ ] `alejandra --check .` passes - - [ ] deploy-rs nodes exist for michael and tahani - - [ ] Zero specialArgs usage in codebase - - [ ] Zero hostname string comparisons in shared modules - - **QA Scenarios**: - ``` - Scenario: Complete build verification - Tool: Bash - Steps: - 1. Build all 4 hosts (dry-run) - 2. Run nix flake check - 3. Run alejandra --check . - 4. Eval deploy-rs nodes - 5. Grep for specialArgs — assert 0 matches - 6. Grep for "networking.hostName ==" in shared modules — assert 0 matches - Expected Result: All checks pass - Evidence: .sisyphus/evidence/task-27-verification.txt - ``` - - **Commit**: NO - -- [ ] 28. Formatting pass + final cleanup - - **What to do**: - - Run `alejandra .` to format all files - - Remove any TODO comments or placeholder code - - Verify `modules/` directory structure is clean - - Ensure `.sops.yaml` still references correct secret file paths - - Final `nix flake check` - - **Recommended Agent Profile**: - - **Category**: `quick` - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: NO - - **Parallel Group**: Wave 5 (after Task 27) - - **Blocks**: F1-F4 - - **Blocked By**: Task 27 - - **References**: - - `alejandra.toml` — Formatter config (tabs for indentation) - - **Acceptance Criteria**: - - [ ] `alejandra --check .` passes - - [ ] No TODO/FIXME/HACK comments - - **QA Scenarios**: - ``` - Scenario: All files formatted - Tool: Bash - Steps: - 1. Run `alejandra --check . 2>&1` - 2. Assert exit code 0 - Expected Result: All files pass formatter - Evidence: .sisyphus/evidence/task-28-format.txt - ``` - - **Commit**: YES - - Message: `feat: rewrite config with den framework` - - Files: all modules/*, flake.nix, flake.lock - - Pre-commit: `nix flake check && alejandra --check .` - -- [ ] 29. Rewrite apps/ scripts from bash to Nushell - - **What to do**: - - Rewrite `apps/common.sh` → `apps/common.nu` — convert colored output helper functions (`print_info`, `print_success`, `print_error`, `print_warning`) to Nushell using `ansi` commands - - Rewrite all 4 darwin scripts (`apps/aarch64-darwin/{build,apply,build-switch,rollback}`) from bash to Nushell: - - `build`: hostname detection via `scutil --get LocalHostName` (fallback `hostname -s`), `nix build` darwin config, unlink result - - `apply`: hostname detection, `nix run nix-darwin -- switch` - - `build-switch`: hostname detection, `nix build` then `sudo darwin-rebuild switch`, unlink result - - `rollback`: list generations via `darwin-rebuild --list-generations`, prompt for generation number via `input`, switch to it - - Rewrite all 4 linux scripts (`apps/x86_64-linux/{build,apply,build-switch,rollback}`) from bash to Nushell: - - `build`: hostname via `hostname`, `nix build` nixos config, unlink result - - `apply`: hostname, sudo-aware `nixos-rebuild switch` - - `build-switch`: hostname, `nix build` then sudo-aware `nixos-rebuild switch` - - `rollback`: list generations via sudo-aware `nix-env --profile ... --list-generations`, prompt for number via `input`, sudo-aware switch-generation + switch-to-configuration - - All scripts get `#!/usr/bin/env nu` shebang - - Delete `apps/common.sh` after `apps/common.nu` is created - - Use `use ../common.nu *` (or equivalent) to import shared helpers in each script - - Preserve exact same behavior — same commands, same output messages, same error handling - - Handle sudo checks in linux scripts: use `(id -u)` or `$env.EUID` equivalent in Nushell - - **Must NOT do**: - - Do not change any nix build/switch/rebuild commands — only the shell scripting around them changes - - Do not add new functionality beyond what exists in the bash scripts - - Do not change the file names (the perSystem apps module references them by path) - - **Recommended Agent Profile**: - - **Category**: `quick` - - Reason: Straightforward 1:1 rewrite of 9 small scripts (~186 lines total) from bash to Nushell. No architectural decisions needed. - - **Skills**: [] - - **Parallelization**: - - **Can Run In Parallel**: YES - - **Parallel Group**: Wave 4 (with Tasks 20-25) - - **Blocks**: Task 27 (build verification should confirm apps still work) - - **Blocked By**: Task 11 (perSystem apps module must be in place first) - - **References**: - - **Pattern References**: - - `apps/common.sh` — Current colored output helpers (23 lines) — rewrite to Nushell `ansi` equivalents - - `apps/aarch64-darwin/build` — Darwin build script (16 lines) — template for all darwin scripts - - `apps/x86_64-linux/build` — Linux build script (16 lines) — template for all linux scripts - - `apps/x86_64-linux/rollback` — Most complex script (30 lines, sudo checks, interactive input) — key test case - - **API/Type References**: - - `modules/apps.nix` (created by Task 11) — perSystem apps module that references these scripts by path - - **External References**: - - Nushell documentation: https://www.nushell.sh/book/ — Language reference for bash→nu translation - - Nushell `ansi` command: for colored output (replaces ANSI escape codes) - - Nushell `input` command: for interactive prompts (replaces bash `read -r`) - - **Acceptance Criteria**: - - [ ] All 9 scripts rewritten with `#!/usr/bin/env nu` shebang - - [ ] `apps/common.nu` exists with colored output helpers - - [ ] `apps/common.sh` deleted - - [ ] `nix run ".#build" -- --help 2>&1` doesn't error (script is parseable by nu) - - [ ] `nix run ".#apply" -- --help 2>&1` doesn't error - - [ ] No bash files remain in `apps/` directory - - **QA Scenarios**: - ``` - Scenario: All apps/ scripts are valid Nushell - Tool: Bash - Preconditions: Task 11 (perSystem apps module) complete, all scripts rewritten - Steps: - 1. Run `find apps/ -type f -name "*.sh" 2>&1` — assert no .sh files remain - 2. Run `head -1 apps/aarch64-darwin/build` — assert contains "#!/usr/bin/env nu" - 3. Run `head -1 apps/x86_64-linux/build` — assert contains "#!/usr/bin/env nu" - 4. Run `nu -c 'source apps/common.nu; print_info "test"' 2>&1` — assert exit code 0 and output contains "[INFO]" - 5. Run `nu -c 'source apps/common.nu; print_error "test"' 2>&1` — assert exit code 0 and output contains "[ERROR]" - Expected Result: All scripts are Nushell, common.nu functions work - Failure Indicators: Any .sh file found, shebang mismatch, nu parse errors - Evidence: .sisyphus/evidence/task-29-nushell-scripts.txt - - Scenario: perSystem apps still reference correct scripts - Tool: Bash - Preconditions: Apps module (Task 11) and scripts (Task 29) both complete - Steps: - 1. Run `nix eval ".#apps.x86_64-linux" --json 2>&1 | nu -c '$in | from json | columns | sort'` - 2. Assert output contains: apply, build, build-switch, rollback - 3. Run `nix eval ".#apps.aarch64-darwin" --json 2>&1 | nu -c '$in | from json | columns | sort'` - 4. Assert output contains: apply, build, build-switch, rollback - Expected Result: All 4 apps registered on both platforms - Failure Indicators: Missing app entries, nix eval errors - Evidence: .sisyphus/evidence/task-29-apps-registered.txt - ``` - - **Commit**: YES - - Message: `refactor: rewrite app scripts from bash to nushell` - - Files: `apps/common.nu`, `apps/aarch64-darwin/*`, `apps/x86_64-linux/*` - - Pre-commit: `nu -c 'source apps/common.nu'` - ---- - -## Final Verification Wave (MANDATORY — after ALL implementation tasks) - -> 4 review agents run in PARALLEL. ALL must APPROVE. Rejection → fix → re-run. - -- [ ] F1. **Plan Compliance Audit** — `oracle` - Read the plan end-to-end. For each "Must Have": verify implementation exists (nix eval, read file). For each "Must NOT Have": search codebase for forbidden patterns (specialArgs, hostname comparisons, HM→NixOS cross-reads). Check all 4 hosts build. Compare deliverables against plan. - Output: `Must Have [N/N] | Must NOT Have [N/N] | Tasks [N/N] | VERDICT: APPROVE/REJECT` - -- [ ] F2. **Code Quality Review** — `unspecified-high` - Run `alejandra --check .` + `nix flake check`. Review all new modules for: dead code, unused imports, inconsistent patterns, hardcoded values that should be options. Check den API usage is idiomatic. Verify import-tree conventions (no function files in import paths). - Output: `Format [PASS/FAIL] | Check [PASS/FAIL] | Files [N clean/N issues] | VERDICT` - -- [ ] F3. **Real Manual QA** — `unspecified-high` - Start from clean state. Build all 4 hosts. Verify deploy-rs nodes exist via nix eval. Verify SOPS secrets preserved via nix eval. Verify git email overrides. Verify overlays produce correct packages. Verify no specialArgs usage anywhere. Save evidence to `.sisyphus/evidence/final-qa/`. - Output: `Builds [4/4 pass] | Deploy [2/2] | Secrets [N/N] | VERDICT` - -- [ ] F4. **Scope Fidelity Check** — `deep` - For each task: read "What to do", verify actual implementation matches 1:1. Check "Must NOT Have" compliance — no new packages, no new services, no abstractions. Verify every current profile has a corresponding den aspect. Flag any behavioral differences. - Output: `Tasks [N/N compliant] | Scope [CLEAN/N issues] | VERDICT` - ---- - -## Commit Strategy - -Since this is a clean rewrite, the work should be committed as a small series of logical commits: - -- **1**: `feat: rewrite config with den framework` — All new modules, flake.nix -- **2**: `refactor: rewrite app scripts from bash to nushell` — apps/ directory -- **3**: `chore: remove old host-centric structure` — Delete hosts/, profiles/, modules/_legacy/ -- Pre-commit: `alejandra --check . && nix flake check` - ---- - -## Success Criteria - -### Verification Commands -```bash -nix build ".#darwinConfigurations.chidi.system" # Expected: builds successfully -nix build ".#darwinConfigurations.jason.system" # Expected: builds successfully -nix build ".#nixosConfigurations.michael.config.system.build.toplevel" # Expected: builds successfully -nix build ".#nixosConfigurations.tahani.config.system.build.toplevel" # Expected: builds successfully -nix flake check # Expected: passes -alejandra --check . # Expected: passes -nix eval ".#deploy.nodes.michael" --json # Expected: valid deploy-rs node -nix eval ".#deploy.nodes.tahani" --json # Expected: valid deploy-rs node -``` - -### Final Checklist -- [ ] All "Must Have" present -- [ ] All "Must NOT Have" absent -- [ ] All 4 hosts build -- [ ] Zero specialArgs usage -- [ ] SOPS paths identical to current -- [ ] deploy-rs configured for NixOS hosts -- [ ] All overlays functional -- [ ] Formatting passes