Imported from brandonpollack23/rcfiles-nix (
AGENTS.md). Install upstream withnpx skills add brandonpollack23/rcfiles-nix. Copyright stays with the author.
Brandon Pollack Nix Config
This is a personal, flake-based NixOS configuration. CLAUDE.md is a symlink to
this file, so keep all repository-wide agent instructions here.
Working rules
- Treat
flake.nix,lib/default.nix, imported modules, host metadata, and CI workflows as the source of truth. README prose and comments can become stale. - Preserve unrelated local changes. Do not rewrite, stage, or discard files outside the task.
- Keep changes declarative and scoped to the smallest file that owns the behavior. Avoid compatibility layers or new abstractions without a concrete second consumer.
- Do not deploy, activate, reboot, update inputs, rotate secrets, or push to a cache unless the user explicitly asks. These are state-changing operations, not validation steps.
- Update
README.mdwhen a change affects human-facing setup, architecture, secret workflows, host onboarding, or operational commands.
Repository architecture
| Path | Responsibility |
|---|---|
flake.nix |
Flake inputs and automatic NixOS host discovery |
flake.lock |
Exact input revisions; change only as part of an intentional input update |
lib/default.nix |
mkHost, input/package wiring, shared module assembly, and platform selection |
hosts/<name>/meta.nix |
Arguments passed to mkHost, such as stateVersion, users, SSH keys, and desktop support |
hosts/<name>/default.nix |
Machine-specific boot, filesystems, networking identity, timezone, and hardware imports |
hosts/<name>/home-overrides/<user>/ |
Per-host Home Manager overrides for a user, auto-imported by name (e.g. git.nix layers onto users/<user>/home/git.nix) |
modules/common.nix |
Baseline CLI packages and settings shared by every host |
modules/common/ |
Focused shared modules for Nix, secrets, locale, and SSH |
modules/nixos.nix |
NixOS-only shared policy (e.g. programs.nh store cleanup) |
modules/darwin.nix |
Darwin-only shared policy (currently empty placeholder) |
modules/desktop.nix |
GUI packages and desktop services, gated by enableDesktop |
modules/{auto-upgrade,rebuild}.nix |
Cross-platform dispatch to NixOS or Darwin implementations |
old/ |
Dormant code kept for reference; nothing here is imported |
users/<name>/default.nix |
Cross-platform system-level user identity |
users/<name>/{nixos,darwin}.nix |
Platform-specific system-level user configuration |
users/<name>/home/ |
Home Manager configuration, packages, dotfiles, and user scripts |
.github/workflows/update-flake.yml |
Scheduled input update, flake check, per-host builds, and Cachix publication |
Every directory under hosts/ containing meta.nix is automatically exposed as
nixosConfigurations.<directory-name>. Do not add a manual host list to
flake.nix.
CI currently enumerates every directory directly under hosts/, while the
flake skips directories without meta.nix. Therefore, do not leave incomplete
or placeholder host directories in hosts/.
Configuration placement
- Host-only settings belong in
hosts/<name>/default.nix. Keep shared policy out of host files. - Do not hand-edit
hosts/*/hardware-configuration.nixduring normal changes; it is generated bynixos-generate-config. Make intentional hardware overrides in the host'sdefault.nix. - CLI tools available on all hosts belong in
modules/common.nix. GUI packages and desktop services belong inmodules/desktop.nix. - Split substantial reusable behavior into a focused file under
modules/and import it from the appropriate entry point. - Cross-platform user identity belongs in
users/<name>/default.nix; NixOS- or Darwin-only system options belong in the matching platform file. - User programs, dotfiles, activation hooks, and user-facing scripts belong
under
users/<name>/home/. - Machine-specific Home Manager tweaks for a user belong in
hosts/<host>/home-overrides/<user>/<name>.nix.mkHostauto-imports every.nixfile there into that user's home config, so it merges onto the matching base module (e.g.git.nix). Use this instead of ad-hoc untracked includes like~/.gitconfig.local. - Packages supplied by flake inputs must be resolved in
lib/default.nixand passed throughspecialArgs. Modules must not reach into the flakeinputsattribute set directly. - Prefer a flake's package or module output over applying an overlay. Use an overlay only when modifying the package set is the actual requirement.
Nix conventions
- Use flakes and locked inputs. Do not introduce channels,
<nixpkgs>lookup paths, or impure environment-dependent imports. - When adding a compatible input, make its
nixpkgsinput follow the rootnixpkgswhere upstream supports that pattern. - Format changed Nix files with
alejandra. Keep its two-space style and avoid unrelated formatting churn. - Define reusable module options with precise
lib.types, descriptions, and sensible defaults. Uselib.mkIf,lib.mkDefault, and assertions where they express real module semantics. - Keep platform-specific options behind the existing
isDarwindispatch or in platform-specific files. - Add comments for constraints and non-obvious reasons, not line-by-line translations of the code.
- Git-backed flakes omit untracked files. If a new file is not yet staged, use
path:.for an interim validation or make only that file Git-visible when staging is in scope; never stage unrelated changes.
State versions
stateVersion in each host's meta.nix is the installation compatibility
version and is the single source for both system.stateVersion and
home.stateVersion.
- Never bump it merely because
nixpkgsor NixOS was updated. - Change it only for a deliberate migration after reviewing the affected module compatibility behavior.
Darwin compatibility
Darwin support is dormant: lib/default.nix, platform dispatch modules, and
users/brpol/darwin.nix retain the path, but the current flake exposes no
darwinConfigurations and has no active nix-darwin input.
- Treat the
isDarwin = truebranch as a compatibility contract and do not introduce unconditional NixOS-only assumptions into shared wiring. - Keep NixOS and Darwin implementations in their existing platform-specific files.
- Do not claim Darwin was validated unless a real Darwin output is available and evaluated.
Shell script conventions
- Home Manager scripts live as
.shsource files underusers/<name>/home/scripts/and are packaged withpkgs.writeShellApplicationin that directory'sdefault.nix. - Declare every external command in
runtimeInputs; do not rely on the interactive user'sPATH. - Keep setup helpers idempotent where practical. Preserve explicit interactive behavior for commands that authenticate, unlock credentials, or generate keys.
- In Nix-generated shell, quote runtime values and use
lib.escapeShellArgwhen interpolating configurable strings. - Systemd and launchd scripts must use package-qualified executables or an
explicit service
path.
Secrets and credentials
secrets/secrets.yamlmust remain SOPS-encrypted. Never commit plaintext, private age keys, SSH private keys, Cachix tokens, or decrypted command output..sops.yamlcontains public recipients and is the source of truth for who can decrypt the encrypted file.- Use
edit-nix-secretsandupdate-secret-keysonly when the user requests a secret change; both can prompt for credentials and rewrite encrypted files. - The Cachix write token is decrypted by sops-nix and read from its runtime secret path by the Nix post-build hook. Do not replace it with a literal, environment file, or repository secret.
- SSH public keys are not secrets, but verify their host/user identity before
granting access in
meta.nix.
Flake inputs and binary caches
Current system cache configuration lives in modules/common/nix-daemon.nix;
CI cache configuration lives in .github/workflows/update-flake.yml.
cache.nixos.orgis the standard NixOS cache.nix-community.cachix.orgis documented by the Neovim nightly input.brandonpollack23.cachix.orgis this repository's read/write cache.
For a new flake input:
- Check its official repository or documentation for a binary cache.
- Verify the exact substituter URL and public key against an authoritative upstream source, preferably at the locked revision.
- Explain the trust boundary and ask the user before adding a trusted key.
- Keep local Nix settings and CI pull-cache settings consistent.
Never add a cache or trusted key copied only from an unaffiliated config, comment, or search result.
Common workflows
Add a host
- Create
hosts/<hostname>/default.nix,hosts/<hostname>/hardware-configuration.nix, andhosts/<hostname>/meta.nix. - Put the original install compatibility version in
meta.nix; setenableDesktop = falsefor headless hosts. - Keep hardware, bootloader, hostname, timezone, and filesystems in the host directory. Put shared behavior in modules.
- Add only the SSH public keys that host should trust.
- If the host must decrypt SOPS secrets, register its generated SSH host key through the documented secret workflow after first boot.
- Build the new host output before activation.
Add or update an input
- Prefer
nix flake update <name>for a targeted update. - Review both
flake.nixandflake.lock; do not hand-edit lock-file graph data. - Check whether the input can follow root
nixpkgs, exports a package/module instead of requiring an overlay, and documents a credible cache. - Build every host affected by shared input or package wiring.
Validation
Use the narrowest useful check first, then finish with repository-wide validation.
# Format changed Nix files.
alejandra path/to/changed.nix
# Check formatting without rewriting.
alejandra --check path/to/changed.nix
# Syntax-check changed shell sources.
bash -n path/to/changed.sh
# Build an affected host without creating a result symlink.
nix build \
.#nixosConfigurations.<host>.config.system.build.toplevel \
--no-link --print-build-logs
# Required final repository check.
nix flake check --print-build-logs
# If the change introduces unstaged flake-referenced files, validate the path
# source as well; the ordinary Git-backed check remains required before merge.
nix flake check path:. --print-build-logs
# Check whitespace and inspect the final scope.
git diff --check
git status --short
- Run the targeted host build for each affected host. For shared modules,
lib/default.nix, or shared inputs, build every discovered host. - Always run
nix flake check --print-build-logsbefore finishing, including documentation-only changes. - Use
nix flake check path:. --print-build-logswhile validating unstaged new files; CI will use the committed Git source. nix flake checkdoes not replace a system toplevel build; CI performs both.- Do not use
nrs,nixos-rebuild switch,darwin-rebuild switch, or the auto-upgrade service as tests. They mutate a live machine. - Do not run
nix flake updateunless input updates are part of the request.
Completion checklist
- The change is in the correct host, module, user, or Home Manager layer.
- Generated hardware files, state versions, secrets, and
flake.lockwere not changed accidentally. - New flake-referenced files are Git-visible.
- Changed Nix and shell files pass their focused checks.
- Every affected host builds when practical.
nix flake check --print-build-logspasses.git diff --checkpasses and unrelated user changes remain untouched.