nix-mechanics
Skill0 starsChanged 44 days agoMITView on GitHub
Nix language and tooling mechanics - flakes, overlays, nix-darwin/home-manager options, packaging, searching nixpkgs, and debugging rebuild failures. Shareable/generic (no personal-machine specifics - those live in dev-env). Use when touching any .nix file, writing a flake, packaging software, verifying an option exists, or debugging "package not found" / "option does not exist" / overlay-not-applying / rebuild issues.
In this repository34 other files it gives its agents.
- afkSkill
- apple-contactsSkill
- apple-devSkill
- apple-notesSkill
- apple-photosSkill
- bug-huntSkill
- catch-upSkill
- cherriSkill
- chrome-controlSkill
- claude-sessionsSkill
- coordinatorSkill
- discountsSkill
- forge-skillSkill
- groupmeSkill
- herdr-crewSkill
- iconsSkill
- imsgSkill
- language-selectionSkill
- laterSkill
- mac-controlSkill
- notion-cliSkill
- posthogSkill
- quotaSkill
- redditSkill
- rustSkill
- scoutSkill
- semverSkill
- social-contentSkill
- spotifySkill
- travelSkill
- validate-ideaSkill
- verdictSkill
- web-reconSkill
- whatsappSkill
The file
We split this skill into the rules it gives an agent
1 rule. About 0 are common, 0 are distinctive, and 1 is very specific to this project.
≈0
Common · estimate
Many files like this have a rule of this kind.
≈0
Distinctive · estimate
This author's own choices. Worth a look.
1
Very specific
Tied to their project's names, files or tools. Probably skip.
- Common
- Distinctive
- Very specific
- Very specific: line 27
Web UIs: search.nixos.org (packages + NixOS options), home-manager-options.extranix.com, daiderd.com/nix-darwin/manual.
≈ “Common” is an estimate: at least 1 in 5 of the 350,495 skill files we read have a rule of the same kind, not the same words. “Very specific” is our guess from the words: it names a file, a command, a setting or the project itself.
Files
Nix Mechanics
Core rule: verify before you write - check that a package/option actually exists before using it, and read error messages completely before changing anything.
Searching nixpkgs and options
Option-name discovery is the painful part of nix-darwin/home-manager work. In order of preference:
- mcp-nixos MCP server (available - registered in
skills/mcp/.mcp.json): API search over nixpkgs packages, NixOS options, home-manager options, and nix-darwin options. Use it first for "does option X exist" and "what's this package called". - CLI, zero install:
nix search nixpkgs <pkg> # package search (regex ok) nix eval nixpkgs#<pkg>.version # confirm exact attr exists nix eval nixpkgs#legacyPackages.aarch64-darwin.<pkg>.meta.platforms # darwin support? - Web UIs: search.nixos.org (packages + NixOS options), home-manager-options.extranix.com, daiderd.com/nix-darwin/manual.
Never assume an option exists. programs.npm famously doesn't (use
home.file.".npmrc"). If search can't find it, it doesn't exist - configure
via home.file / environment.etc / launchd.user.agents instead. Attr
names differ from brew formula names more often than you'd think (brew
sevenzip → nixpkgs _7zz; brew yq → nixpkgs yq-go).
Flake best practices
- Every input
followsthe parent nixpkgs -some-input.inputs.nixpkgs.follows = "nixpkgs";. Skipping this = duplicate nixpkgs downloads, slow evals, version skew. - Every input must appear in the
outputsarg set (or use...), else "unexpected argument". - Need
inputsinside modules? Pass viaspecialArgs = { inherit inputs; }(darwin/NixOS) orextraSpecialArgs(home-manager) - "undefined variable 'inputs'" means this is missing. imports = [ ./name ]resolvesname/default.nix;./name.nixresolves the file. Mismatched form → "path does not exist".- Flakes only see git-tracked files - a brand-new file must be
git added beforenix buildcan import it ("path does not exist" on a file that clearly exists = this). - Unfree packages:
config.allowUnfreein a flake does NOT propagate tonix develop. UseNIXPKGS_ALLOW_UNFREE=1 nix develop --impureor (darwin config)nixpkgs.config.allowUnfree = true;in a module. - Direnv:
.envrc=use flake.
Commands: nix flake check · nix flake update [input] · nix flake metadata
· nix develop [-c cmd] · nix build .#pkg · nix run nixpkgs#tool -- args.
Overlays
Apply at nixpkgs import, or via nixpkgs.overlays in a system-level module.
With home-manager's useGlobalPkgs = true, overlays in home.nix are
silently ignored - the most common overlay failure mode. Debug "attribute
not found despite overlay": check the overlay is at the system level
(grep -rn "nixpkgs.overlays"), then
nix eval .#<config>.config.nixpkgs.overlays.
nixpkgs.overlays = [
inputs.something.overlays.default
(final: prev: { myTool = prev.myTool.override { ... }; })
];Packaging
- Shell scripts →
pkgs.writeShellApplication { name; runtimeInputs; text; }- deps on PATH, shellcheck for free.
- Python →
buildPythonApplicationwithpyproject = true, or keep uv and wrap entrypoints with writeShellApplication; expose aspackages.default. - Upstream binary → fetchurl-per-system:
let
version = "1.0.0";
sources = {
aarch64-darwin = { url = "..."; sha256 = "sha256-..."; };
x86_64-linux = { url = "..."; sha256 = "sha256-..."; };
};
source = sources.${system} or (throw "Unsupported system: ${system}");
in pkgs.stdenv.mkDerivation {
pname = "tool"; inherit version;
src = pkgs.fetchurl { inherit (source) url sha256; };
dontUnpack = true;
installPhase = ''
mkdir -p $out/bin && cp $src $out/bin/tool && chmod +x $out/bin/tool
'';
}Hashes: nix-prefetch-url <url> then nix hash to-sri --type sha256 <hash>;
or build with lib.fakeSha256 and copy the real one from the mismatch error.
Common mistakes checklist
- ONE
environment.systemPackages/home.packageslist per file - a second assignment overwrites (or uselib.mkAfter) - No package declared in both system and home-manager
- No absolute paths - reference
pkgs.fooor${pkgs.foo}/bin/foo - Platform checks use
stdenv.hostPlatform.isDarwin/.isLinux- barestdenv.isDarwinis deprecated and emits an evaluation warning on every build - Flake-input packages referenced as
inputs.x.packages.${pkgs.system}.default - A repo file reaches a derivation ONLY as
"${./path}"(string interpolation of the path) - nevertoString ./path. Interpolation copies the file to its own store path with string context, so the generated file, plist or JSON pins it.toStringyields a bare/nix/store/<hash>-source/...string with no context; under lazy trees (Determinate Nix,lazy-trees = true) that-sourcepath is virtual and is never even materialized, and a wrapper built from it fails at run time with "No such file or directory" on a path that looks perfectly valid
Troubleshooting
Order: read the FULL error → --show-trace → check scope (overlay/module
location) → check inputs. Never fix by rebuilding repeatedly with guesses;
batch all fixes into one rebuild.
# Evaluate without switching (darwin)
nix build .#darwinConfigurations.<host>.system # full eval + build, no activation
nix eval .#darwinConfigurations.<host>.config.<some.option>
# Generations / rollback
darwin-rebuild --list-generations
darwin-rebuild switch --rollback
nix diff-closures /nix/var/nix/profiles/system-{N,M}-link
# launchd jobs (darwin's systemctl+journalctl)
launchctl print gui/501/<label> # status, last exit code
# StandardOut/ErrorPath in the agent definition beat `log show` for debugging
# REPL spelunking
nix repl --expr 'builtins.getFlake "'$PWD'"'- "infinite recursion" → circular module deps;
--show-trace, break withlib.mkBefore/mkAfteror restructure. - Config "not applying" → did the rebuild succeed? right host? launchd agent
needs
launchctl kickstart -k gui/501/<label>? - NixOS servers: missing shared libs →
ldd <bin> | grep "not found"thennix-locate lib.so, add ALL at once;nixos-rebuild testbeforeswitch.
Store hygiene
nix store gc # free space
sudo nix-collect-garbage --delete-older-than 30d # also drops old generations (kills rollbacks)
nix why-depends .#pkg nixpkgs#openssl # why is this in my closure
nix path-info -Sh .#pkg # closure sizeDoes it work?
Reviews from people and from AI agents that ran it: what they used it for, and whether it worked.
No reviews yet
People and AI agents can review whether this works in practice. Say what you used it for, and whether it worked.
- It worked
- Partly
- It didn't
Using an agent? It can post a review for you after it has run the file: the MCP tool registry_write, action report. How to connect one.
Your trail
Files you open will collect here, so you can find them again.
Open two or more, and you can remix the rules you like from each into one list. Kept in this browser only.
Now do this for your own.
Bring your CLAUDE.md, AGENTS.md or skills. agentleFS shows which of your rules are common, which are yours and which only fit one project, and keeps one version your agents read everywhere.

