Files
NixOS/docs/constitution.md
2026-03-23 15:51:13 -06:00

11 KiB
Raw Permalink Blame History

AI Constitution for the NixOS Repository

Scope and Audience

  • Audience: AI assistants and contributors needing an authoritative description of repository rules, structure, and workflows.
  • Scope: Repo-wide conventions, module categories, host roles, secrets handling, proxy rules, documentation locations, and maintenance triggers.
  • Authority: This constitution is the source of truth for AI. If human-facing docs differ, update both with the recorded resolution in specs/001-ai-docs/research.md.

Repository Overview

  • Architecture: Flake-based repo using flake-parts with inputs for pkgs (stable/unstable), stylix, home-manager, sops-nix, and service overlays. Common modules are composed through parts/core.nix and parts/hosts.nix.
  • Host outputs: parts/hosts.nix publishes NixOS hosts through flake.nixosConfigurations and standalone Home Manager hosts through flake.homeConfigurations.
  • Module auto-import: modules/modules.nix auto-imports legacy flat modules under modules/apps, modules/dev, modules/scripts, modules/servers, modules/services, modules/shell, modules/websites, and modules/network, excluding librewolf.nix, and also discovers nested nixos.nix files under those trees. config/base.nix registers modules/home-manager.nix as a Home Manager shared module, which discovers nested home.nix files under modules/ for every Home Manager user. Factories live in modules/factories/ (mkserver, mkscript), and shared options are in modules/nix and modules/users.
  • Home Manager helper layer: Common Home Manager wrapper logic belongs in parts/core.nix helpers under inputs.self.lib when it is repeated across multiple home.nix modules. Current helpers include split-loader support plus hmModule, hmShellType, and hmOnlyUser for shared enablement and shell-selection patterns.
  • Hosts and toggles: Host definitions live in hosts/<name>/configuration.nix with host-specific toggles in hosts/<name>/toggles.nix. The my namespace carries toggles for apps/dev/scripts/services/shell, feature flags like enableProxy and enableContainers, and per-host interfaces and ips maps.
  • Standalone Home Manager hosts: Home-only hosts may live under hosts/<name>/home.nix with hosts/<name>/toggles.nix, and should only enable modules that have a home.nix surface or are otherwise known to be Home Manager-compatible on that platform.
  • Port assignment: Service ports should live with the service module when the port is intrinsic to a server definition under modules/servers/. Miscellaneous or host-specific ports that do not belong to a server module should be centralized in my.ports in modules/modules.nix and referenced via config.my.ports.* (use toString config.my.ports.* where a string is required).
  • Main server and proxies: my.mainServer selects the host that should serve traffic by default (default vps). Reverse proxies use helpers in parts/core.nix (proxy, proxyReverse, proxyReverseFix, proxyReversePrivate) and pick IPs from my.ips plus the hostName/ip set by mkserver options. Nginx defaults to proxyReverse for any server with enableProxy = true unless useDefaultProxy = false or the server is listed in the Fix/Private proxy lists.
  • Secure hosts and secrets: my.secureHost gates SOPS secrets. Secure hosts load secrets from secrets/*.yaml and wireguard definitions; non-secure hosts (e.g., hosts/emacs) skip secret-dependent services. Default SOPS file is secrets/secrets.yaml via config/base.nix. Proxy-only services that need private certificates must still define their cert secrets when enableProxy = true.

Coding Conventions

  • No blank lines between code blocks; keep markdown examples tight.
  • Minimize comments; prefer clear naming and shared helpers (modules/factories/mkserver.nix, modules/factories/mkscript.nix) to avoid duplication.
  • Use business-level, technology-agnostic language in AI docs; reserve implementation detail for module code.
  • Nix structure: flatten single-child attribute sets into their full path; keep multi-child sets nested for readability; merge siblings under a shared parent; flatten the shallowest subtree first to reduce indentation without losing clarity.
  • Nix attribute ordering: prefer options before config in module bodies; inside attribute sets keep inherit statements first, then boolean leaf assignments, then other leaf assignments, then nested attribute sets; when simple leaves and nested children share a parent, place the simple leaves first.
config.services.jellyfin.enable = true; # preferred single-leaf form
config.services = {
  nginx.enable = true;
  jellyfin = {
    enable = true;
    port = 1234;
  };
};
{
  options.my.example.enable = lib.mkEnableOption "example";
  config = lib.mkIf config.my.example.enable {
    services.example = {
      enable = true;
      port = 1234;
      nested = {
        value = "x";
      };
    };
  };
}

Terminology and Naming Standards

  • Module: Prefer a feature directory under modules/<category>/<name>/ with nixos.nix for system concerns and home.nix for Home Manager concerns. Legacy flat modules at modules/<category>/<name>.nix remain valid during migration.
  • Factory: Shared option constructors in modules/factories/ (use mkserver for server modules, mkscript for script units).
  • Options: Settings under the my namespace (e.g., my.services.<service>, my.scripts.<script>).
  • Toggles: Enablement maps in hosts/<name>/toggles.nix controlling categories (apps/dev/shell/scripts/services/servers/units) and features (enableProxy, enableContainers). Future standalone Home Manager or Darwin homes should mirror that shape in home-specific toggle files instead of embedding Home Manager settings in NixOS modules.
  • Servers: Reverse-proxied services under modules/servers/, normally created with mkserver options (including useDefaultProxy to opt out of default proxyReverse).
  • Websites: Static nginx vhosts under modules/websites/ (portfolio/blog, mb-report), gated by my.websites.*.enableProxy.
  • Scripts: Units defined via mkscript with enable, install, service, users, timer, and package fields.
  • Playbooks: Workflow guides under docs/playbooks/ for repeatable tasks.
  • Reference map: Navigation index under docs/reference/index.md for paths and responsibilities.

Secrets Map and secureHost Behavior

  • Secrets files: secrets/certs.yaml, secrets/env.yaml, secrets/gallery.yaml, secrets/homepage.yaml, secrets/keys.yaml, secrets/wireguard.yaml, secrets/secrets.yaml, plus secrets/ssh/ for host keys.
  • Placement rules: Keep secrets aligned to their file purpose (certificates → certs.yaml; environment/service env vars → env.yaml; media/gallery creds → gallery.yaml; homepage widgets → homepage.yaml; SSH/private keys → keys.yaml; WireGuard peers → wireguard.yaml; misc defaults → secrets.yaml).
  • secureHost gating: Only hosts with my.secureHost = true load SOPS secrets and WireGuard interfaces. Hosts with secureHost = false must avoid secret-dependent services and skip SOPS entries.
  • VPS enrollment flow: The vps host generates its own key on first boot, then operators enroll the public key, re-encrypt secrets, and redeploy. Follow docs/playbooks/enroll-vps.md.

Module Categories and Active Hosts

  • Module categories: apps, dev, scripts, servers, services, shell, websites, network, users, nix. Factories sit in modules/factories/ and are imported explicitly; patch artifacts live at the repo root in patches/.
  • Split-module preference: For categories that need both system and Home Manager behavior, co-locate both surfaces in modules/<category>/<name>/nixos.nix and modules/<category>/<name>/home.nix. Keep helpers local to that directory only when they are feature-specific; otherwise promote them into shared helpers/factories.
  • Home module helper rule: Extract repeated Home Manager wrapper code into parts/core.nix once at least a few modules share the same structure. Keep only feature-specific package lists, files, and service settings inside each home.nix.
  • User config split: Personal configs may also split across config/<name>.nix for NixOS-side account/secrets state and config/<name>-home.nix for Home Manager-only state imported from the user home module.
  • Active hosts: workstation, server, miniserver, galaxy, emacs, vps. Host roles and secure status are defined in hosts/<name>/configuration.nix and toggles in hosts/<name>/toggles.nix.
  • Standalone Home Manager hosts: mac is a planned aarch64-darwin Home Manager target under flake.homeConfigurations, intended to reuse workstation-style dev and shell modules without Linux GUI app modules.

Precedence and Conflict Resolution

  • Precedence: This constitution is authoritative for AI. Human docs must be updated to match. If conflicts are found, align human docs to the constitution and log the resolution in specs/001-ai-docs/research.md.
  • Conflict handling steps: identify the divergent rule, cite the source files, decide the authoritative rule per this constitution, update both the source file and the relevant doc, and record the decision and timestamp.

Maintenance Triggers and Update Process

  • Triggers: New factory/helper, new module category, new host, new toggle set, new proxy rule, new secret category/file, change to my.mainServer or my.ips, stylix scheme changes, or new auto-import filters/import trees.
  • Update flow: (1) Amend the relevant module or toggle files; (2) Update docs/constitution.md for rules/terminology changes; (3) Update playbooks under docs/playbooks/ affected by the change; (4) Update docs/reference/index.md for navigation paths; (5) Note the decision in specs/001-ai-docs/research.md and refresh quickstart.md if discoverability shifts.
  • Validation: Confirm discoverability within two clicks (constitution → reference map/playbook), secrets map completeness, and alignment with success criteria SC-001SC-004.

Quick Reference and Navigation

  • Constitution: docs/constitution.md (this file)
  • Reference map: docs/reference/index.md (paths, hosts, secrets, proxies, stylix)
  • MCP server reference: docs/reference/mcp-server.md (tools, invocation, sync checks)
  • Playbook: docs/playbooks/add-module.md — add a module in the right category and confirm auto-import.
  • Playbook: docs/playbooks/split-home-manager.md — migrate a mixed module into paired nixos.nix and home.nix files.
  • Playbook: docs/playbooks/add-server.md — add a reverse-proxied server via mkserver and proxy rules.
  • Playbook: docs/playbooks/add-script.md — add a script unit via mkscript with install/service/timer options.
  • Playbook: docs/playbooks/add-host-toggle.md — add or update host toggle maps under hosts/<name>/toggles.nix.
  • Playbook: docs/playbooks/add-secret.md — add a SOPS secret in the correct file and wire it into modules.
  • Playbook: docs/playbooks/add-wireguard-peer.md — add a WireGuard peer and update secrets/hosts.
  • Playbook: docs/playbooks/enroll-vps.md — enroll a VPS key, re-encrypt secrets, redeploy.
  • Playbook: docs/playbooks/vps-rebuild.md — rebuild the VPS with the expected deploy flow.
  • Playbook template: docs/playbooks/template.md
  • Planning artifacts: specs/001-ai-docs/ (plan, research, data-model, quickstart, contracts)