5.4 KiB
5.4 KiB
AGENTS.md
Purpose
This repo uses the Dendritic Pattern with flake-parts.
Design and change the configuration as a composition of features, not as a host-first tree.
For deeper design rationale and pattern descriptions, refer to .agents/dendritic-design-with-flake-parts.wiki.
Core Terms
- Feature: a flake-parts module under
modules/that defines one coherent concern. - Aspect: a reusable module published at
flake.modules.<module class>.<aspect name>. - Module class: the configuration context of an aspect. This repo primarily uses
nixosandhomeManager. - Feature module: the flake-parts module that defines aspects, flake outputs, options, or shared helpers.
In this repo, flake.nix imports ./modules recursively via inputs.import-tree. Any non-private .nix file under modules/ is therefore treated as a feature module.
Design Principles
- Work bottom-up. Define features first; assemble hosts from features.
- Keep semantic ownership local. A feature should contain the configuration for that concern across all relevant module classes.
- Name aspects semantically. The aspect name should usually match the file or directory name that defines it.
- Prefer small, composable aspects. Build larger configurations with
imports. - Import aspects unconditionally and only within the same module class.
- Put conditions inside module content with
lib.mkIforlib.mkMerge, never aroundimports. - Avoid importing the same aspect multiple times along one import path.
- Keep private helper files next to the feature that uses them and prefix them with
_soimport-treedoes not import them as feature modules. - Put shared schemas and constructors in dedicated shared modules, not ad hoc host files.
Repo Structure
modules/capabilities/: reusable leaf capability features and most aspect definitions.modules/capabilities/services/: reusable service capabilities, especially hosted daemons and network services.modules/profiles/: bundle features that assemble capabilities into larger profiles such ashost-baseandworkstation-base.modules/hosts/<name>/default.nix: host features that assemble NixOS aspects intoflake.modules.nixos.<name>.modules/secrets/: secret-related features shared by hosts.modules/flake-parts.nix: flake-parts entrypoint; defines systems, formatter, andflake.nixosConfigurations.modules/lib/: shared schemas, constructors, and helpers exposed throughrepo.helpers, especiallymkHostandmkCaddyReverseProxy.modules/data.nix: canonical shared repo data, including the singlerepo.account, machine inventory, desktop preferences, services, and theme data.modules/lib/schema.nix: shared metadata schema forrepo.*and NixOSmeta.machine.
How Features Are Applied Here
- Reusable NixOS concerns are published as
flake.modules.nixos.<name>. - Reusable Home Manager concerns are published as
flake.modules.homeManager.<name>. - Hosts are aspects too.
orion,polaris, andzenitharenixosaspects assembled from smaller aspects. flake.nixosConfigurationsinstantiates every entry inrepo.machineswithconfig.repo.helpers.mkHost.- Hosts define machine data under
repo.machines.<name>and host-specific NixOS composition underflake.modules.nixos.<name>. mkHostwires the singlerepo.accountintousers.users.<name>andhome-manager.users.<name>.- NixOS modules may read
config.meta.machine; Home Manager modules should read host facts throughosConfig.meta.machineand user facts throughconfig.homeorrepo.account.
Preferred Aspect Patterns
- Simple Aspect: use for one self-contained concern in one or more module classes.
- Multi Context Aspect: use when one concern must configure both
nixosandhomeManager. - Inheritance Aspect: use by importing a parent aspect and extending it.
- Conditional Aspect: use
lib.mkMergepluslib.mkIffor conditional content.
Use Collector Aspect only when composition through imports or shared library helpers is insufficient.
Change Rules
- When adding a reusable leaf feature, add or extend aspects under
modules/capabilities/and let profiles or hosts opt into them explicitly. - When adding a hosted service or network daemon feature, prefer
modules/capabilities/services/. - When adding a bundle of existing capabilities, put it under
modules/profiles/. - When adding a host, create
modules/hosts/<name>/default.nixand keep host-local generated files private as_hardware.nix,_disk.nix, or similar. - When a feature needs local data or helper code, keep it inside that feature directory and prefix non-feature files with
_when they live undermodules/. - Do not place arbitrary non-feature
.nixfiles undermodules/unless they are intentionally private and excluded from recursive import. - If a concern is shared across hosts, it belongs in a reusable feature, not inline in one host unless it is truly host-specific.
Practical Heuristics
- If you are about to edit a host because of a reusable concern, that concern probably wants its own feature.
- If a Home Manager module needs host facts, prefer
osConfig.meta.machine; for user facts, preferconfig.homeorrepo.accountinstead of duplicating literals. - If a concern spans system and user space, keep both aspects in one feature so the behavior stays coherent.
- If imports would need to be conditional, redesign the aspect boundary instead.