From e684ac481ec0a92567656241f585740710ffd36c Mon Sep 17 00:00:00 2001 From: alexion Date: Thu, 23 Jul 2026 19:21:12 -0400 Subject: [PATCH] refactor: mirror module namespaces to their directories (task 0031) Adopt the convention that a Module's option path mirrors its directory under modules/, with an index file naming the directory's own segment. - Group agent Modules under modules.agents.*: claude-code (whole directory), pi (flattened to a file), skills (renamed from agent-skills), and gitea-axi under an agents/tools/ subgroup. The agents/ and tools/ folders are pure namespace prefixes with no aggregator enable. - Nest hypridle and hyprlock under modules.desktop.hyprland.*, with hyprland.nix as the index, and update the desktop aggregator. - Remove the obsolete example Module. - Record the convention in CONTEXT.md and ADR 0004, and update the neogaia host, the two live CLAUDE.md gotchas, and the skills Module's intentional Enable-convention exception comment. --- .claude/CONTEXT.md | 6 ++++ ...0004-module-namespace-mirrors-directory.md | 24 +++++++++++++++ .claude/tasks/0031-module-namespace-tidy.md | 29 +++++++++++++++++++ modules/{ => agents}/claude-code/CLAUDE.md | 0 .../claude-code/authentication.md | 0 .../{ => agents}/claude-code/claude-code.nix | 0 .../claude-code/hooks/agent-sudo-guard.sh | 0 .../skills/codebase-design/DEEPENING.md | 0 .../skills/codebase-design/DESIGN-IT-TWICE.md | 0 .../skills/codebase-design/SKILL.md | 0 .../skills/craft-skill/GLOSSARY.md | 0 .../claude-code/skills/craft-skill/SKILL.md | 0 .../skills/domain-modeling/ADR-FORMAT.md | 0 .../skills/domain-modeling/CONTEXT-FORMAT.md | 0 .../skills/domain-modeling/SKILL.md | 0 .../claude-code/skills/grill/SKILL.md | 0 .../claude-code/skills/implement/SKILL.md | 0 .../skills/improve-codebase/HTML-REPORT.md | 0 .../skills/improve-codebase/SKILL.md | 0 .../claude-code/skills/library/nbdev/SKILL.md | 0 .../claude-code/skills/remove-skills/SKILL.md | 0 .../skills/review-uncommitted/SKILL.md | 0 .../skills/setup-skills/LOCKFILE.md | 0 .../claude-code/skills/setup-skills/SKILL.md | 0 .../skills/setup-skills/hash-dir.sh | 0 .../skills/test-driven-development/SKILL.md | 0 .../skills/test-driven-development/mocking.md | 0 .../test-driven-development/refactoring.md | 0 .../skills/test-driven-development/tests.md | 0 .../claude-code/skills/to-spec/SKILL.md | 0 .../claude-code/skills/to-spec/SPEC-FORMAT.md | 0 .../claude-code/skills/to-tasks/SKILL.md | 0 .../skills/to-tasks/TASK-FORMAT.md | 0 .../claude-code/skills/update-skills/SKILL.md | 0 modules/{pi => agents}/pi.nix | 0 .../{agent-skills.nix => agents/skills.nix} | 5 ++++ modules/{ => agents/tools}/gitea-axi.nix | 0 modules/example.nix | 13 --------- 38 files changed, 64 insertions(+), 13 deletions(-) create mode 100644 .claude/adr/0004-module-namespace-mirrors-directory.md create mode 100644 .claude/tasks/0031-module-namespace-tidy.md rename modules/{ => agents}/claude-code/CLAUDE.md (100%) rename modules/{ => agents}/claude-code/authentication.md (100%) rename modules/{ => agents}/claude-code/claude-code.nix (100%) rename modules/{ => agents}/claude-code/hooks/agent-sudo-guard.sh (100%) rename modules/{ => agents}/claude-code/skills/codebase-design/DEEPENING.md (100%) rename modules/{ => agents}/claude-code/skills/codebase-design/DESIGN-IT-TWICE.md (100%) rename modules/{ => agents}/claude-code/skills/codebase-design/SKILL.md (100%) rename modules/{ => agents}/claude-code/skills/craft-skill/GLOSSARY.md (100%) rename modules/{ => agents}/claude-code/skills/craft-skill/SKILL.md (100%) rename modules/{ => agents}/claude-code/skills/domain-modeling/ADR-FORMAT.md (100%) rename modules/{ => agents}/claude-code/skills/domain-modeling/CONTEXT-FORMAT.md (100%) rename modules/{ => agents}/claude-code/skills/domain-modeling/SKILL.md (100%) rename modules/{ => agents}/claude-code/skills/grill/SKILL.md (100%) rename modules/{ => agents}/claude-code/skills/implement/SKILL.md (100%) rename modules/{ => agents}/claude-code/skills/improve-codebase/HTML-REPORT.md (100%) rename modules/{ => agents}/claude-code/skills/improve-codebase/SKILL.md (100%) rename modules/{ => agents}/claude-code/skills/library/nbdev/SKILL.md (100%) rename modules/{ => agents}/claude-code/skills/remove-skills/SKILL.md (100%) rename modules/{ => agents}/claude-code/skills/review-uncommitted/SKILL.md (100%) rename modules/{ => agents}/claude-code/skills/setup-skills/LOCKFILE.md (100%) rename modules/{ => agents}/claude-code/skills/setup-skills/SKILL.md (100%) rename modules/{ => agents}/claude-code/skills/setup-skills/hash-dir.sh (100%) rename modules/{ => agents}/claude-code/skills/test-driven-development/SKILL.md (100%) rename modules/{ => agents}/claude-code/skills/test-driven-development/mocking.md (100%) rename modules/{ => agents}/claude-code/skills/test-driven-development/refactoring.md (100%) rename modules/{ => agents}/claude-code/skills/test-driven-development/tests.md (100%) rename modules/{ => agents}/claude-code/skills/to-spec/SKILL.md (100%) rename modules/{ => agents}/claude-code/skills/to-spec/SPEC-FORMAT.md (100%) rename modules/{ => agents}/claude-code/skills/to-tasks/SKILL.md (100%) rename modules/{ => agents}/claude-code/skills/to-tasks/TASK-FORMAT.md (100%) rename modules/{ => agents}/claude-code/skills/update-skills/SKILL.md (100%) rename modules/{pi => agents}/pi.nix (100%) rename modules/{agent-skills.nix => agents/skills.nix} (72%) rename modules/{ => agents/tools}/gitea-axi.nix (100%) delete mode 100644 modules/example.nix diff --git a/.claude/CONTEXT.md b/.claude/CONTEXT.md index b79d96d..6be95be 100644 --- a/.claude/CONTEXT.md +++ b/.claude/CONTEXT.md @@ -24,6 +24,12 @@ _Avoid_: loader, importer, scanner The rule that every Module is imported unconditionally and guards its own body with `mkIf config.modules..enable`, so a Host reads as a checklist of `enable = true` flags. _Avoid_: feature flag, toggle, opt-in +**Namespace convention**: +The rule that a Module's option path mirrors its directory path under `modules/`, so a file's location is its namespace. +A file whose name matches its enclosing directory is that directory's index node, declaring the directory's own segment rather than a doubled one. +A directory with no such file is a pure namespace prefix that carries no aggregate enable. +_Avoid_: option tree, module path, config key + **admin identity**: The age identity held only in the operator's password manager, never committed, that is a recipient of every secrets file. It is the recovery path for any wiped machine and the credential that authorizes registering a new host. diff --git a/.claude/adr/0004-module-namespace-mirrors-directory.md b/.claude/adr/0004-module-namespace-mirrors-directory.md new file mode 100644 index 0000000..230cd8a --- /dev/null +++ b/.claude/adr/0004-module-namespace-mirrors-directory.md @@ -0,0 +1,24 @@ +--- +status: accepted +--- + +# A Module's option namespace mirrors its directory + +A Module's option path mirrors its directory path under `modules/`, so a file's location on disk is its namespace: `modules/agents/tools/gitea-axi.nix` declares `modules.agents.tools.gitea-axi`, and a subfolder like `agents/` or `tools/` is a real namespace segment, not a cosmetic grouping. +A file whose name matches its enclosing directory is that directory's index node, declaring the directory's own segment — its `enable` or aggregator — rather than a doubled segment, so `desktop/hyprland/hyprland.nix` owns `modules.desktop.hyprland` while `desktop/hyprland/hypridle.nix` nests under it as `modules.desktop.hyprland.hypridle`. + +We chose this nested-mirrors-directory shape over the previous flat names (`modules.claude-code`, `modules.gitea-axi`) because the flat scheme let a Module sit anywhere on disk regardless of its option path, so the tree stopped predicting where a namespace lived. +Mirroring makes the two the single fact. +A pure grouping directory (`agents/`, `tools/`) contributes a namespace segment but declares no aggregate `enable`: agents are enabled à la carte, so there is deliberately no `modules.agents.enable` that would turn on a bundle nobody wants as a unit. + +## Considered Options + +- **Flat, location-independent names** (the prior state). Rejected: a Module's option path was unconstrained by its file's location, so the directory tree and the option tree drifted and neither could be read off the other. +- **A subfolder as cosmetic grouping only**, with the option path skipping the folder (`agents/pi.nix` → `modules.pi`). Rejected: it reintroduces the same drift for grouped Modules and makes the folder a lie the namespace does not tell. +- **An aggregator at every grouping level** (`modules.agents.enable`). Rejected: the agent Modules have no meaningful "all agents" bundle, and an aggregate enable there would invite turning on tools no Host wants together. + +## Consequences + +- The `agents/` group carries `claude-code`, `pi`, `skills`, and `tools/gitea-axi`, each enabled individually under `modules.agents.*`, with no `modules.agents.enable`. +- The index-file rule means adding a knob to an existing group (a new `desktop/hyprland/*.nix`) nests automatically without a naming decision, while a new top-level Module names its own segment. +- The `skills` Module remains the one deliberate exception to the Enable convention — it wires unconditionally — which the namespace convention does not change. diff --git a/.claude/tasks/0031-module-namespace-tidy.md b/.claude/tasks/0031-module-namespace-tidy.md new file mode 100644 index 0000000..6364bee --- /dev/null +++ b/.claude/tasks/0031-module-namespace-tidy.md @@ -0,0 +1,29 @@ +## What to build + +Tidy the module tree so a Module's option namespace mirrors its directory under `modules/`, adopt that as a documented convention, group the agent-related Modules under a new `agents/` directory, bring `desktop/hyprland/` into conformance, and drop the obsolete reference Module. + +The convention: a Module's option path mirrors its directory path, and a file whose name matches its directory is that directory's index node — it declares the directory's own segment (its `enable`/aggregator) rather than a doubled segment. A file `foo.nix` in directory `d/` declares `modules.<…>.d.foo`. A group directory with no matching index file contributes a namespace segment but no aggregate `enable`. + +Applying it: + +- **Agents grouping.** Relocate the agent Modules under `modules.agents.*`: `claude-code` (its whole directory, assets included) → `modules.agents.claude-code`; `pi` flattened from its directory to a single file → `modules.agents.pi`; the skills Module renamed from `agent-skills` → `agents/skills.nix`; and `gitea-axi` into an `agents/tools/` subgroup → `modules.agents.tools.gitea-axi`. `tools/` is a real namespace segment, not a cosmetic folder. +- **No aggregators.** `agents/` and `tools/` are pure namespace prefixes — no `modules.agents.enable` or `modules.agents.tools.enable`. Agents are enabled à la carte. +- **Skills stays enable-less.** The skills Module keeps its current behaviour (unconditionally wires `programs.agents.skills`, empty list); it is the one deliberate exception to the Enable convention, marked as intentional by a self-contained comment in the file. +- **Desktop conformance.** Nest `hypridle` and `hyprlock` under `modules.desktop.hyprland.*` (matching the index-file rule, `hyprland.nix` being the index), and update `desktop.nix`'s aggregator to the new paths. The 13 flat `desktop/*.nix` Modules keep their `modules.desktop.` names — broader semantic regrouping is explicitly out of scope for this task. +- **Remove the example Module.** Delete `modules/example.nix`; the documented convention and the many real Modules supersede its teaching role. + +Also update the one Host that carries these Modules and the live documentation, and record the convention in the domain model. + +## Acceptance criteria + +- [x] `CONTEXT.md` gains a `Namespace convention` glossary entry stating the directory-mirrors-namespace rule and the index-file rule, in glossary style (no implementation detail). +- [x] An ADR (next number: `0004`) records the decision — nested-mirrors-directory over flat names, a subfolder as a real namespace segment, the index-file rule, and no `agents` aggregator — following the ADR format. +- [x] Agent Modules resolve under `modules.agents.*`: `modules.agents.claude-code.enable`, `modules.agents.pi.enable`, and `modules.agents.tools.gitea-axi.enable` exist; `modules.claude-code`, `modules.pi`, and `modules.gitea-axi` no longer resolve. +- [x] The skills Module lives at `agents/skills.nix` (renamed from `agent-skills.nix`), stays enable-less, still wires `programs.agents.skills`, and carries an in-file comment marking the Enable-convention exception as intentional. +- [x] Neither `modules.agents.enable` nor `modules.agents.tools.enable` exists (pure namespace prefixes, no aggregator). +- [x] `claude-code`'s assets (`CLAUDE.md`, `authentication.md`, `hooks/`, `skills/`) travel with the move and its relative references still resolve. +- [x] `desktop/hyprland/`: `modules.desktop.hyprland.hypridle` and `modules.desktop.hyprland.hyprlock` resolve; the old `modules.desktop.hypridle`/`modules.desktop.hyprlock` no longer exist; `desktop.nix` enables the new paths; `modules.desktop.enable` still brings up the whole session. +- [x] `modules/example.nix` is removed and `modules.example` no longer resolves. +- [x] `hosts/neogaia/default.nix` uses the new option paths for claude-code, pi, and gitea-axi. +- [x] The two live `CLAUDE.md` gotchas — the `gitea-axi` install line and the `claude-code` skill-source path — are updated to the new option/path; `.claude/tasks/*` are left unchanged as historical record. +- [x] `nix flake check` builds `checks.x86_64-linux.neogaia` green (moved files staged so evaluation sees them). diff --git a/modules/claude-code/CLAUDE.md b/modules/agents/claude-code/CLAUDE.md similarity index 100% rename from modules/claude-code/CLAUDE.md rename to modules/agents/claude-code/CLAUDE.md diff --git a/modules/claude-code/authentication.md b/modules/agents/claude-code/authentication.md similarity index 100% rename from modules/claude-code/authentication.md rename to modules/agents/claude-code/authentication.md diff --git a/modules/claude-code/claude-code.nix b/modules/agents/claude-code/claude-code.nix similarity index 100% rename from modules/claude-code/claude-code.nix rename to modules/agents/claude-code/claude-code.nix diff --git a/modules/claude-code/hooks/agent-sudo-guard.sh b/modules/agents/claude-code/hooks/agent-sudo-guard.sh similarity index 100% rename from modules/claude-code/hooks/agent-sudo-guard.sh rename to modules/agents/claude-code/hooks/agent-sudo-guard.sh diff --git a/modules/claude-code/skills/codebase-design/DEEPENING.md b/modules/agents/claude-code/skills/codebase-design/DEEPENING.md similarity index 100% rename from modules/claude-code/skills/codebase-design/DEEPENING.md rename to modules/agents/claude-code/skills/codebase-design/DEEPENING.md diff --git a/modules/claude-code/skills/codebase-design/DESIGN-IT-TWICE.md b/modules/agents/claude-code/skills/codebase-design/DESIGN-IT-TWICE.md similarity index 100% rename from modules/claude-code/skills/codebase-design/DESIGN-IT-TWICE.md rename to modules/agents/claude-code/skills/codebase-design/DESIGN-IT-TWICE.md diff --git a/modules/claude-code/skills/codebase-design/SKILL.md b/modules/agents/claude-code/skills/codebase-design/SKILL.md similarity index 100% rename from modules/claude-code/skills/codebase-design/SKILL.md rename to modules/agents/claude-code/skills/codebase-design/SKILL.md diff --git a/modules/claude-code/skills/craft-skill/GLOSSARY.md b/modules/agents/claude-code/skills/craft-skill/GLOSSARY.md similarity index 100% rename from modules/claude-code/skills/craft-skill/GLOSSARY.md rename to modules/agents/claude-code/skills/craft-skill/GLOSSARY.md diff --git a/modules/claude-code/skills/craft-skill/SKILL.md b/modules/agents/claude-code/skills/craft-skill/SKILL.md similarity index 100% rename from modules/claude-code/skills/craft-skill/SKILL.md rename to modules/agents/claude-code/skills/craft-skill/SKILL.md diff --git a/modules/claude-code/skills/domain-modeling/ADR-FORMAT.md b/modules/agents/claude-code/skills/domain-modeling/ADR-FORMAT.md similarity index 100% rename from modules/claude-code/skills/domain-modeling/ADR-FORMAT.md rename to modules/agents/claude-code/skills/domain-modeling/ADR-FORMAT.md diff --git a/modules/claude-code/skills/domain-modeling/CONTEXT-FORMAT.md b/modules/agents/claude-code/skills/domain-modeling/CONTEXT-FORMAT.md similarity index 100% rename from modules/claude-code/skills/domain-modeling/CONTEXT-FORMAT.md rename to modules/agents/claude-code/skills/domain-modeling/CONTEXT-FORMAT.md diff --git a/modules/claude-code/skills/domain-modeling/SKILL.md b/modules/agents/claude-code/skills/domain-modeling/SKILL.md similarity index 100% rename from modules/claude-code/skills/domain-modeling/SKILL.md rename to modules/agents/claude-code/skills/domain-modeling/SKILL.md diff --git a/modules/claude-code/skills/grill/SKILL.md b/modules/agents/claude-code/skills/grill/SKILL.md similarity index 100% rename from modules/claude-code/skills/grill/SKILL.md rename to modules/agents/claude-code/skills/grill/SKILL.md diff --git a/modules/claude-code/skills/implement/SKILL.md b/modules/agents/claude-code/skills/implement/SKILL.md similarity index 100% rename from modules/claude-code/skills/implement/SKILL.md rename to modules/agents/claude-code/skills/implement/SKILL.md diff --git a/modules/claude-code/skills/improve-codebase/HTML-REPORT.md b/modules/agents/claude-code/skills/improve-codebase/HTML-REPORT.md similarity index 100% rename from modules/claude-code/skills/improve-codebase/HTML-REPORT.md rename to modules/agents/claude-code/skills/improve-codebase/HTML-REPORT.md diff --git a/modules/claude-code/skills/improve-codebase/SKILL.md b/modules/agents/claude-code/skills/improve-codebase/SKILL.md similarity index 100% rename from modules/claude-code/skills/improve-codebase/SKILL.md rename to modules/agents/claude-code/skills/improve-codebase/SKILL.md diff --git a/modules/claude-code/skills/library/nbdev/SKILL.md b/modules/agents/claude-code/skills/library/nbdev/SKILL.md similarity index 100% rename from modules/claude-code/skills/library/nbdev/SKILL.md rename to modules/agents/claude-code/skills/library/nbdev/SKILL.md diff --git a/modules/claude-code/skills/remove-skills/SKILL.md b/modules/agents/claude-code/skills/remove-skills/SKILL.md similarity index 100% rename from modules/claude-code/skills/remove-skills/SKILL.md rename to modules/agents/claude-code/skills/remove-skills/SKILL.md diff --git a/modules/claude-code/skills/review-uncommitted/SKILL.md b/modules/agents/claude-code/skills/review-uncommitted/SKILL.md similarity index 100% rename from modules/claude-code/skills/review-uncommitted/SKILL.md rename to modules/agents/claude-code/skills/review-uncommitted/SKILL.md diff --git a/modules/claude-code/skills/setup-skills/LOCKFILE.md b/modules/agents/claude-code/skills/setup-skills/LOCKFILE.md similarity index 100% rename from modules/claude-code/skills/setup-skills/LOCKFILE.md rename to modules/agents/claude-code/skills/setup-skills/LOCKFILE.md diff --git a/modules/claude-code/skills/setup-skills/SKILL.md b/modules/agents/claude-code/skills/setup-skills/SKILL.md similarity index 100% rename from modules/claude-code/skills/setup-skills/SKILL.md rename to modules/agents/claude-code/skills/setup-skills/SKILL.md diff --git a/modules/claude-code/skills/setup-skills/hash-dir.sh b/modules/agents/claude-code/skills/setup-skills/hash-dir.sh similarity index 100% rename from modules/claude-code/skills/setup-skills/hash-dir.sh rename to modules/agents/claude-code/skills/setup-skills/hash-dir.sh diff --git a/modules/claude-code/skills/test-driven-development/SKILL.md b/modules/agents/claude-code/skills/test-driven-development/SKILL.md similarity index 100% rename from modules/claude-code/skills/test-driven-development/SKILL.md rename to modules/agents/claude-code/skills/test-driven-development/SKILL.md diff --git a/modules/claude-code/skills/test-driven-development/mocking.md b/modules/agents/claude-code/skills/test-driven-development/mocking.md similarity index 100% rename from modules/claude-code/skills/test-driven-development/mocking.md rename to modules/agents/claude-code/skills/test-driven-development/mocking.md diff --git a/modules/claude-code/skills/test-driven-development/refactoring.md b/modules/agents/claude-code/skills/test-driven-development/refactoring.md similarity index 100% rename from modules/claude-code/skills/test-driven-development/refactoring.md rename to modules/agents/claude-code/skills/test-driven-development/refactoring.md diff --git a/modules/claude-code/skills/test-driven-development/tests.md b/modules/agents/claude-code/skills/test-driven-development/tests.md similarity index 100% rename from modules/claude-code/skills/test-driven-development/tests.md rename to modules/agents/claude-code/skills/test-driven-development/tests.md diff --git a/modules/claude-code/skills/to-spec/SKILL.md b/modules/agents/claude-code/skills/to-spec/SKILL.md similarity index 100% rename from modules/claude-code/skills/to-spec/SKILL.md rename to modules/agents/claude-code/skills/to-spec/SKILL.md diff --git a/modules/claude-code/skills/to-spec/SPEC-FORMAT.md b/modules/agents/claude-code/skills/to-spec/SPEC-FORMAT.md similarity index 100% rename from modules/claude-code/skills/to-spec/SPEC-FORMAT.md rename to modules/agents/claude-code/skills/to-spec/SPEC-FORMAT.md diff --git a/modules/claude-code/skills/to-tasks/SKILL.md b/modules/agents/claude-code/skills/to-tasks/SKILL.md similarity index 100% rename from modules/claude-code/skills/to-tasks/SKILL.md rename to modules/agents/claude-code/skills/to-tasks/SKILL.md diff --git a/modules/claude-code/skills/to-tasks/TASK-FORMAT.md b/modules/agents/claude-code/skills/to-tasks/TASK-FORMAT.md similarity index 100% rename from modules/claude-code/skills/to-tasks/TASK-FORMAT.md rename to modules/agents/claude-code/skills/to-tasks/TASK-FORMAT.md diff --git a/modules/claude-code/skills/update-skills/SKILL.md b/modules/agents/claude-code/skills/update-skills/SKILL.md similarity index 100% rename from modules/claude-code/skills/update-skills/SKILL.md rename to modules/agents/claude-code/skills/update-skills/SKILL.md diff --git a/modules/pi/pi.nix b/modules/agents/pi.nix similarity index 100% rename from modules/pi/pi.nix rename to modules/agents/pi.nix diff --git a/modules/agent-skills.nix b/modules/agents/skills.nix similarity index 72% rename from modules/agent-skills.nix rename to modules/agents/skills.nix index aaf10f3..d45472f 100644 --- a/modules/agent-skills.nix +++ b/modules/agents/skills.nix @@ -3,6 +3,11 @@ # skills directory so they are active in every project. The flake's home-manager # module self-gates on the harness being enabled and installs nothing for an # empty selection, so a host without one carries no skills either way. +# +# Unlike every other module, this one declares no `enable` flag and wires +# unconditionally, by design. +# The flake's self-gating above already makes it inert where the harness is +# absent, so a gate would guard nothing. let user = config.user.name; diff --git a/modules/gitea-axi.nix b/modules/agents/tools/gitea-axi.nix similarity index 100% rename from modules/gitea-axi.nix rename to modules/agents/tools/gitea-axi.nix diff --git a/modules/example.nix b/modules/example.nix deleted file mode 100644 index 9b45206..0000000 --- a/modules/example.nix +++ /dev/null @@ -1,13 +0,0 @@ -{ config, lib, ... }: -# Reference example for the module shape: imported unconditionally, but inert -# until a host sets its `enable` flag. -let - cfg = config.modules.example; -in -{ - options.modules.example.enable = lib.mkEnableOption "the reference example module"; - - config = lib.mkIf cfg.enable { - environment.etc."skeleton-example".text = "This Module is enabled.\n"; - }; -}