1795 lines
77 KiB
Markdown
1795 lines
77 KiB
Markdown
# 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.<name>` 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 = "<hostname>"`
|
|
- `profiles.system.user = "root"`
|
|
- `profiles.system.path = deploy-rs.lib.x86_64-linux.activate.nixos self.nixosConfigurations.<hostname>`
|
|
- `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
|