This repository has been archived on 2026-08-30. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
dotfiles/AGENTS.md

7.0 KiB

dotfiles-nixos

One flake builds every machine I own.

Repository Conventions

  • Follow docs/technical-writing.md for comments, user-facing descriptions, commit prose, pull-request prose, and Markdown documentation.
  • Comments posted to the forge under the operator's account must end with — Pi. The sign-off identifies the agent as the author instead of the operator.
  • Commit messages follow Conventional Commits, defined in docs/conventional-commits.md. Use a scope for the changed module or host, such as fish, nvim, or neogaia.
  • Keep commit messages about the Git history, not the forge workflow. Do not reference issue or pull-request numbers unless the commit itself requires a stable external reference.
  • Use gitea-axi for Gitea issues, pull requests, labels, reviews, comments, and milestones. It resolves this repository from the origin remote inside the checkout.

Dotfiles Conventions

Desktop

  • When adding a graphical application, add a window-rewrite icon mapping in modules/desktop/waybar.nix. The workspace indicator uses this mapping to show an application icon instead of the generic default glyph. Match the mapping on the window class. Run hyprctl clients -j | jq -r '.[].class' | sort -u to list classes in the running session.
  • Set Hyprland session environment variables in modules/desktop/hyprland/hyprland.nix with env = KEY,VALUE. home.sessionVariables do not reach the Hyprland session because UWSM does not source hm-session-vars.sh. Source cursor values from config.stylix.cursor. Set XCURSOR_* and HYPRCURSOR_* to the same theme for Bibata.
  • Configure the Steam desktop client as an XWayland application. SDL Wayland selectors do not make the visible client native Wayland. Keep fractional scaling sharp with Hyprland's xwayland.force_zero_scaling and Steam's STEAM_FORCE_DESKTOPUI_SCALING.

Firefox

  • Manage Firefox search engines through programs.firefox.search with force = true. Hide built-in engines with <engine>.metaData.hidden = true because omission does not remove them. Use current engine ids, such as default = "ddg" instead of "DuckDuckGo". Decode the built search.json.mozlz4 with mozlz4a -d <search.json.mozlz4> to check the result.
  • Avoid Home Manager Firefox extension settings unless the whole profile can use the legacy extension-storage backend. Any non-empty profiles.<name>.extensions.settings.<id>.settings sets extensions.webextensions.ExtensionStorageIDB.enabled = false for the whole profile.

Neovim

  • Nixvim's flake input follows the root nixpkgs source, but its Home Manager module does not reuse the host's pkgs instance. Keep programs.nixvim.nixpkgs.useGlobalPackages = true. That setting makes Nixvim use the shared package set without warning that its source default changed.

AI Tooling

  • Use produced literals for Herdr key names that include shifted punctuation. For example, use prefix+< instead of prefix+shift+comma.
  • Treat ~/.pi/agent/skills as generated output from Home Manager. Do not edit skills in that directory. A new file created there stays outside the repo. Shared global skills come from the skills flake through modules/agents/skills.nix. Update the skills flake input, then rebuild.
  • Keep generated .agents/skills/.gitignore files from ignoring symlinked skills. Pi skill discovery honors .gitignore, .ignore, and .fdignore inside scanned skill directories. An ignored symlinked skill does not load even when .agents/skills/<name>/SKILL.md exists.
  • Write directly to flake-managed Pi extension, prompt, and skill directories only for throwaway development or local experiments. Home Manager activation can overwrite or hide unmanaged files in those directories. Promote finished work into the dotfiles module before treating it as deployed.

Gotchas

Architecture

  • Guest modules are host-agnostic wiring, while host files own deployment-specific service configuration such as served volumes and host paths. For example, guests/copyparty.nix should expose options and translate them into guest mounts/service settings, while hosts/pikachu/default.nix chooses /inbox, /media, and their backing paths.
  • self.lib.registry.collect { hosts = self.nixosConfigurations; } reads only top-level host config.registry declarations. Registry declarations inside guest interiors live under config.containers.<guest>.config.registry. The collected registry does not include those guest-interior declarations. Publish guest values from host-side code, or extend the collector to recurse into guests. See #65.
  • A NixOS module function argument default such as registry ? config.registry does not safely handle an unprovided module argument. The module system still queries _module.args.registry. Evaluation fails when that argument is absent. For an optional special-argument fallback, bind module arguments through @args. Test args ? <name> inside the module body.

Build Inputs

  • chaotic-nyx must not follow this flake's nixpkgs. Chaotic builds its packages against its own pinned nixpkgs. Its overlay defaults to onTopOf = "flake-nixpkgs", the cache-friendly path. That setup lets nyx-cache.chaotic.cx serve the CachyOS kernel instead of building it from source. Chaotic packages do not see this flake's unstable or stable overlays.

Deployment

  • Remote deploy helpers that run target-side sudo over SSH need a TTY. Use ssh -t unless the target command cannot prompt for sudo credentials.

Host Environment

  • This host has no python or python3 command on its ordinary PATH. For one-off Python commands, use Nix explicitly, such as nix shell nixpkgs#python3 -c python3 <script>.
  • nixos-generate-config --show-hardware-config needs root on this machine, even when it only prints. Without root, it fails with Failed to retrieve subvolume info for /. The root filesystem uses btrfs.
  • Nix flake evaluation ignores untracked files in this checkout. Stage or commit new auto-loaded modules before evaluating the flake. Otherwise, nix flake check and nixos-rebuild --flake cannot see those modules. They can then report missing options that exist only in the working tree.

Secrets

  • sops.secrets.<name>.owner must name a user known on the decrypting host. Do not set the owner to a guest-only service user unless the host also declares that user. Use a host-visible owner plus a shared group mode when the guest service can read the decrypted secret file through its group.

Service Migrations

  • Actual Budget's NixOS service runs actual-server with WorkingDirectory = services.actual.settings.dataDir. The actual-server CLI wrapper sets ACTUAL_CONFIG_PATH=./config.json when the working directory contains config.json. That environment variable overrides the config path generated by the NixOS module. During migration from old community-script state, move or rewrite a copied /data/config.json. Otherwise, the copied file shadows the declarative module settings.