Files
lux/AGENTS.md
T

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 nixos and homeManager.
  • 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.mkIf or lib.mkMerge, never around imports.
  • 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 _ so import-tree does 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 as host-base and workstation-base.
  • modules/hosts/<name>/default.nix: host features that assemble NixOS aspects into flake.modules.nixos.<name>.
  • modules/secrets/: secret-related features shared by hosts.
  • modules/flake-parts.nix: flake-parts entrypoint; defines systems, formatter, and flake.nixosConfigurations.
  • modules/lib/: shared schemas, constructors, and helpers exposed through repo.helpers, especially mkHost and mkCaddyReverseProxy.
  • modules/data.nix: canonical shared repo data, including the single repo.account, machine inventory, desktop preferences, services, and theme data.
  • modules/lib/schema.nix: shared metadata schema for repo.* and NixOS meta.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, and zenith are nixos aspects assembled from smaller aspects.
  • flake.nixosConfigurations instantiates every entry in repo.machines with config.repo.helpers.mkHost.
  • Hosts define machine data under repo.machines.<name> and host-specific NixOS composition under flake.modules.nixos.<name>.
  • mkHost wires the single repo.account into users.users.<name> and home-manager.users.<name>.
  • NixOS modules may read config.meta.machine; Home Manager modules should read host facts through osConfig.meta.machine and user facts through config.home or repo.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 nixos and homeManager.
  • Inheritance Aspect: use by importing a parent aspect and extending it.
  • Conditional Aspect: use lib.mkMerge plus lib.mkIf for 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.nix and 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 under modules/.
  • Do not place arbitrary non-feature .nix files under modules/ 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, prefer config.home or repo.account instead 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.