nix-best-practices
Nix patterns for flakes, overlays, unfree handling, and binary overlays. Use when working with flake.nix or shell.nix.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Nix patterns for flakes, overlays, unfree handling, and binary overlays. Use when working with flake.nix or shell.nix.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
How to declaratively add, change, or remove AI coding agent assets — skills, MCP servers, plugin/capability installs, RTK hooks, shared instructions — in this home-manager repo's mods/agents/*.nix module. Use this whenever the user asks to add a skill, add an MCP server, install a plugin for Claude/Codex/OpenCode/Pi, gate something to a specific machine, update a pinned skill, or asks why removing something from mods/agents/*.nix didn't actually remove it after a rebuild. Also use this before writing any new code under mods/agents/ or mods/dotfiles/agents/scripts/, even if the user doesn't name this skill directly — this architecture has specific, non-obvious rules (see "The one rule that matters" and "The three layers") that are easy to violate by copying an old pattern.
Resolve conflicts after Stackman stops during a rebase. Use when stackman sync reports rebase conflicts, when the user asks to continue a Stackman rebase, or when Git is in a conflicted rebase caused by Stackman rebasing a branch onto its parent/upstream branch.
This skill should be used when the user asks about "neovim config", "nvim setup", "vim best practices", "neovim patterns", "modern neovim", "lua configuration", "neovim 0.10", or wants guidance on configuring Neovim following current standards and conventions.
Use when the user wants to handle GitHub pull request feedback, review comments, reviewer suggestions, pasted PR comments, or a PR URL with comments that need triage, code changes, or drafted reviewer replies.
Use when the user explicitly asks to store, create, organize, read from obsidian notes or obsidian vault.
Guide for this Neovim configuration -- a modular Lua-based IDE rooted at mods/dotfiles/nvim/. Use when configuring plugins, adding keybindings, setting up LSP servers, debugging, or extending the config. Covers lazy.nvim, plugin_registry, snacks.nvim pickers, blink.cmp completion, dual LSP architecture, DAP debugging, and which-key v3 aggregation.
| name | nix-best-practices |
| description | Nix patterns for flakes, overlays, unfree handling, and binary overlays. Use when working with flake.nix or shell.nix. |
Standard flake.nix structure:
{
description = "Project description";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs {
inherit system;
};
in {
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [
# packages here
];
};
});
}
When adding overlay inputs, use follows to share the parent nixpkgs and avoid downloading multiple versions:
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
# Overlay follows parent nixpkgs
some-overlay.url = "github:owner/some-overlay";
some-overlay.inputs.nixpkgs.follows = "nixpkgs";
# Chain follows through intermediate inputs
another-overlay.url = "github:owner/another-overlay";
another-overlay.inputs.nixpkgs.follows = "some-overlay";
};
All inputs must be listed in outputs function even if not directly used:
outputs = { self, nixpkgs, some-overlay, another-overlay, ... }:
Overlays modify or add packages to nixpkgs:
let
pkgs = import nixpkgs {
inherit system;
overlays = [
overlay1.overlays.default
overlay2.overlays.default
# Inline overlay
(final: prev: {
myPackage = prev.myPackage.override { ... };
})
];
};
in
Use numtide/nixpkgs-unfree for EULA-licensed packages without requiring user config:
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
nixpkgs-unfree.url = "github:numtide/nixpkgs-unfree/nixos-unstable";
nixpkgs-unfree.inputs.nixpkgs.follows = "nixpkgs";
# Unfree overlay follows nixpkgs-unfree
proprietary-tool.url = "github:owner/proprietary-tool-overlay";
proprietary-tool.inputs.nixpkgs.follows = "nixpkgs-unfree";
};
This chains: proprietary-tool → nixpkgs-unfree → nixpkgs
Users add to ~/.config/nixpkgs/config.nix:
{ allowUnfree = true; }
let
pkgs = import nixpkgs {
inherit system;
config.allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) [
"specific-package"
];
};
in
Note: config.allowUnfree in flake.nix doesn't work with nix develop - use nixpkgs-unfree or user config.
When nixpkgs builds a community version lacking features (common with open-core tools), create an overlay that fetches official binaries.
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = nixpkgs.legacyPackages.${system};
version = "1.0.0";
# Platform-specific binaries
sources = {
"x86_64-linux" = {
url = "https://example.com/tool-linux-amd64-v${version}";
sha256 = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
};
"aarch64-linux" = {
url = "https://example.com/tool-linux-arm64-v${version}";
sha256 = "sha256-BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=";
};
"x86_64-darwin" = {
url = "https://example.com/tool-darwin-amd64-v${version}";
sha256 = "sha256-CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC=";
};
"aarch64-darwin" = {
url = "https://example.com/tool-darwin-arm64-v${version}";
sha256 = "sha256-DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD=";
};
};
source = sources.${system} or (throw "Unsupported system: ${system}");
toolPackage = pkgs.stdenv.mkDerivation {
pname = "tool";
inherit version;
src = pkgs.fetchurl {
inherit (source) url sha256;
};
sourceRoot = ".";
dontUnpack = true;
installPhase = ''
mkdir -p $out/bin
cp $src $out/bin/tool
chmod +x $out/bin/tool
'';
meta = with pkgs.lib; {
description = "Tool description";
homepage = "https://example.com";
license = licenses.unfree; # or appropriate license
platforms = builtins.attrNames sources;
};
};
in {
packages.default = toolPackage;
packages.tool = toolPackage;
overlays.default = final: prev: {
tool = toolPackage;
};
})
// {
overlays.default = final: prev: {
tool = self.packages.${prev.system}.tool;
};
};
}
nix-prefetch-url https://example.com/tool-linux-amd64-v1.0.0
# Returns hash in base32, convert to SRI format:
nix hash to-sri --type sha256 <base32-hash>
Or use SRI directly:
nix-prefetch-url --type sha256 https://example.com/tool-linux-amd64-v1.0.0
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [
nodejs
python3
];
shellHook = ''
echo "Dev environment ready"
'';
};
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [ postgresql ];
# Set at shell entry
DATABASE_URL = "postgres://localhost/dev";
# Or in shellHook for dynamic values
shellHook = ''
export PROJECT_ROOT="$(pwd)"
'';
};
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [
openssl
postgresql
];
# Expose headers and libraries
shellHook = ''
export C_INCLUDE_PATH="${pkgs.openssl.dev}/include:$C_INCLUDE_PATH"
export LIBRARY_PATH="${pkgs.openssl.out}/lib:$LIBRARY_PATH"
export PKG_CONFIG_PATH="${pkgs.openssl.dev}/lib/pkgconfig:$PKG_CONFIG_PATH"
'';
};
.envrc for flake projects:
use flake
For unfree packages without nixpkgs-unfree:
export NIXPKGS_ALLOW_UNFREE=1
use flake --impure
# Update all inputs
nix flake update
# Update specific input
nix flake update some-input
# Check flake validity
nix flake check
# Show flake metadata
nix flake metadata
# Enter dev shell
nix develop
# Run command in dev shell
nix develop -c <command>
# Build package
nix build .#packageName
# Run package
nix run .#packageName
All inputs must be listed in outputs function:
# Wrong
outputs = { self, nixpkgs }: ...
# Right (if you have more inputs)
outputs = { self, nixpkgs, other-input, ... }: ...
config.allowUnfree in flake.nix doesn't propagate to nix develop. Use:
~/.config/nixpkgs/config.nixNIXPKGS_ALLOW_UNFREE=1 nix develop --impureUse follows to chain inputs to a single nixpkgs source.
Ensure overlay is in the overlays list when importing nixpkgs:
pkgs = import nixpkgs {
inherit system;
overlays = [ my-overlay.overlays.default ];
};
Re-fetch with nix-prefetch-url and update the hash. Hashes change when upstream updates binaries at the same URL.
This project uses lib/builders.nix with mkDarwinSystem and mkNixOSSystem helpers that wire up:
extraSpecialArgs (pkgs-unstable, custom flake inputs)darwin-base.nix (all Macs) -> darwin-{personal,work,maclab}.nixcommon.nix (all machines) -> darwin.nix (all Macs) -> home-<machine>.nixUses mkOutOfStoreSymlink for dotfile management. A mkSym helper in shell.nix creates these concisely. Edits take effect immediately without rebuild.
mods/languages/all.nix aggregates all language tooling. Shared between base-packages.nix (shell) and neovim.nix (extraPackages).
uvx.nix and npmx.nix install tools via uv tool install and npm install -g in home-manager activation hooks.
nixpkgs.follows (proctmux, secret_inject, animal_rescue, scrollbacktamer)home-supermicro.nix could be consolidated to use the common.nix profileuseGlobalPkgs = true would avoid duplicate nixpkgs config