Only evaluates needed attributes
let
expensive = builtins.trace "Computing expensive" (1 + 1);
in
{ a = 1; b = expensive; }.a # Does not compute expensive
Avoid side effects; use derivations for build actions
buildResult = pkgs.stdenv.mkDerivation { ... };
Access patterns
set.attr
set."attr-with-dashes"
Recursive attribute set
rec { a = 1; b = a + 1; }
nativeBuildInputs = [ pkgs.cmake ];
buildInputs = [ pkgs.openssl ];
installPhase = ''
mkdir -p $out/bin
cp mypackage $out/bin/
'';
}
Required attributes: pname, version, src
Standard phases: unpackPhase, patchPhase, configurePhase, buildPhase, installPhase
Libraries linked at runtime
buildInputs = [ openssl zlib ];
}
config = lib.mkIf config.myModule.enable { # configuration when enabled
};
}
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
};
outputs = { self, nixpkgs, ... }@inputs: { # output attributes
};
}
config = lib.mkIf config.custom.feature.enable { # configuration when enabled
};
}
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.users.username = import ./home.nix;
}
1---2name: nix-ecosystem-33description: This skill should be used when the user asks to "write nix", "nix expression", "flake.nix", "home-manager config", "programs.*", "services.*", or works with Nix language, flakes, or Home Manager. Provides comprehensive Nix ecosystem patterns and best practices.4---56<purpose>7Provide comprehensive patterns for Nix language, flakes, and Home Manager configuration.8</purpose>910<nix_language>11<fundamentals>12<concept name="lazy_evaluation">13<description>Nix is lazily evaluated. Expressions are only computed when needed.</description>14<example>1516<note>Only evaluates needed attributes</note>1718let19expensive = builtins.trace "Computing expensive" (1 + 1);20in21{ a = 1; b = expensive; }.a # Does not compute expensive22</example>23</concept>2425<concept name="pure_functions">26<description>All Nix functions are pure. Same inputs always produce same outputs.</description>27<example>28<note>Pure function - always returns same result for same input</note>29double = x: x * 2;3031<note>Avoid side effects; use derivations for build actions</note>3233buildResult = pkgs.stdenv.mkDerivation { ... };34</example>35</concept>3637<concept name="attribute_sets">38<description>Primary data structure in Nix</description>39<example>40<note>Basic attribute set</note>41{ attr1 = value1; attr2 = value2; }4243<note>Access patterns</note>4445set.attr46set."attr-with-dashes"4748<note>Recursive attribute set</note>4950rec { a = 1; b = a + 1; }51</example>52</concept>53</fundamentals>5455<patterns>56<pattern name="let_in">57<description>Local bindings for complex expressions</description>58<example>59let60 helper = x: x + 1;61 value = helper 5;62in63 value * 264</example>65</pattern>6667<pattern name="with">68<description>Bring attribute set into scope</description>69<example>70with pkgs; [ git vim tmux ]71</example>72<warning>Avoid nested with; prefer explicit references for clarity</warning>73</pattern>7475<pattern name="inherit">76<description>Copy attributes from another set</description>77<example>78{ inherit (pkgs) git vim; inherit name version; }79</example>80</pattern>8182<pattern name="overlay">83<description>Modify or extend nixpkgs</description>84<example>85final: prev: {86 myPackage = prev.myPackage.override { ... };87}88</example>89<decision_tree name="when_to_use">90<question>Do you need to modify existing packages or add new ones globally?</question>91<if_yes>Use overlays to extend nixpkgs</if_yes>92<if_no>Use local package definitions with callPackage</if_no>93</decision_tree>94</pattern>9596<pattern name="callPackage">97<description>Dependency injection pattern</description>98<example>99myPackage = pkgs.callPackage ./package.nix { };100</example>101</pattern>102103<pattern name="mkDerivation">104<description>Standard package builder</description>105<example>106pkgs.stdenv.mkDerivation {107 pname = "mypackage";108 version = "1.0.0";109 src = fetchFromGitHub { ... };110111nativeBuildInputs = [ pkgs.cmake ];112buildInputs = [ pkgs.openssl ];113114installPhase = ''115mkdir -p $out/bin116cp mypackage $out/bin/117'';118}119</example>120<note>Required attributes: pname, version, src</note>121<note>Standard phases: unpackPhase, patchPhase, configurePhase, buildPhase, installPhase</note>122</pattern>123124<pattern name="build_inputs">125<description>Dependency specification in derivations</description>126<example>127{128 # Tools run at build time (compilers, build tools)129 nativeBuildInputs = [ cmake pkg-config ];130131# Libraries linked at runtime132133buildInputs = [ openssl zlib ];134}135</example>136</pattern>137138<pattern name="options_config">139<description>NixOS/Home Manager module structure</description>140<example>141{ config, lib, pkgs, ... }:142{143 options.myModule = {144 enable = lib.mkEnableOption "my module";145 setting = lib.mkOption {146 type = lib.types.str;147 default = "value";148 description = "A setting";149 };150 };151152config = lib.mkIf config.myModule.enable { # configuration when enabled153};154}155</example>156</pattern>157158<pattern name="mkOption">159<description>Define module options with types and defaults</description>160<example>161options.myOption = lib.mkOption {162 type = lib.types.bool;163 default = false;164 description = "Enable my feature";165 example = true;166};167</example>168<note>Common types: lib.types.bool, lib.types.str, lib.types.listOf, lib.types.attrsOf</note>169</pattern>170171<pattern name="mkEnableOption">172<description>Shorthand for boolean enable option</description>173<example>174enable = lib.mkEnableOption "my service";175</example>176</pattern>177</patterns>178179<anti_patterns>180<avoid name="impure_paths">181<description>Directly referencing absolute paths breaks reproducibility</description>182<instead>Use fetchurl, fetchFromGitHub, or relative paths within the repository</instead>183</avoid>184185<avoid name="nested_with">186<description>Multiple nested with statements reduce code clarity</description>187<instead>Prefer explicit attribute access (pkgs.git) for better readability</instead>188</avoid>189190<avoid name="rec_overuse">191<description>Recursive attribute sets can be hard to understand and maintain</description>192<instead>Use let-in for complex recursive definitions</instead>193</avoid>194195<avoid name="string_interpolation_abuse">196<description>Using string interpolation for path operations is error-prone</description>197<instead>Use lib functions for path manipulation (lib.concatStringsSep, builtins.path)</instead>198</avoid>199</anti_patterns>200</nix_language>201202<flakes>203<concept name="flake_structure">204<description>Basic structure of a flake.nix file</description>205<example>206{207 description = "Project description";208209inputs = {210nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";211};212213outputs = { self, nixpkgs, ... }@inputs: { # output attributes214};215}216</example>217</concept>218219<outputs>220<concept name="packages">221<description>Derivations for nix build</description>222<example>223packages.x86_64-linux.default = pkgs.hello;224</example>225</concept>226227<concept name="devShells">228<description>Development environments for nix develop</description>229<example>230devShells.x86_64-linux.default = pkgs.mkShell {231 packages = [ pkgs.nodejs ];232};233</example>234</concept>235236<concept name="apps">237<description>Runnable applications for nix run</description>238<example>239apps.x86_64-linux.default = {240 type = "app";241 program = "${pkgs.hello}/bin/hello";242};243</example>244</concept>245246<concept name="overlays">247<description>Nixpkgs overlays</description>248<example>249overlays.default = final: prev: {250 myPackage = prev.callPackage ./myPackage.nix { };251};252</example>253</concept>254255<concept name="nixosModules">256<description>NixOS modules</description>257<example>258nixosModules.default = { config, lib, pkgs, ... }: {259 options.services.myService = { ... };260 config = { ... };261};262</example>263</concept>264265<concept name="homeManagerModules">266<description>Home Manager modules</description>267<example>268homeManagerModules.default = { config, lib, pkgs, ... }: {269 options.programs.myProgram = { ... };270 config = { ... };271};272</example>273</concept>274275<concept name="nixosConfigurations">276<description>Full NixOS system configurations</description>277<example>278nixosConfigurations.hostname = nixpkgs.lib.nixosSystem {279 system = "x86_64-linux";280 modules = [ ./configuration.nix ];281};282</example>283</concept>284285<concept name="homeConfigurations">286<description>Home Manager configurations</description>287<example>288homeConfigurations."user@host" = home-manager.lib.homeManagerConfiguration {289 pkgs = nixpkgs.legacyPackages.x86_64-linux;290 modules = [ ./home.nix ];291};292</example>293</concept>294</outputs>295296<patterns>297<pattern name="github_input">298<description>Reference GitHub repositories as flake inputs</description>299<example>300inputs = {301 nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";302 # Specific branch303 stable.url = "github:NixOS/nixpkgs/nixos-24.11";304 # Specific revision305 pinned.url = "github:owner/repo/abc123def";306};307</example>308</pattern>309310<pattern name="follows">311<description>Share input between flakes to avoid duplication</description>312<example>313home-manager = {314 url = "github:nix-community/home-manager";315 inputs.nixpkgs.follows = "nixpkgs";316};317</example>318</pattern>319320<pattern name="flake_false">321<description>Non-flake inputs for legacy repositories</description>322<example>323my-source = {324 url = "github:owner/repo";325 flake = false;326};327</example>328</pattern>329330<pattern name="per_system">331<description>Generate outputs for multiple systems</description>332<example>333outputs = { self, nixpkgs, ... }:334let335 systems = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ];336 forAllSystems = nixpkgs.lib.genAttrs systems;337in {338 packages = forAllSystems (system:339 let pkgs = nixpkgs.legacyPackages.${system};340 in { default = pkgs.hello; }341 );342};343</example>344<decision_tree name="when_to_use">345<question>Does your flake need to support multiple platforms?</question>346<if_yes>Use per-system pattern with genAttrs or flake-utils</if_yes>347<if_no>Define outputs for single system directly</if_no>348</decision_tree>349</pattern>350351<pattern name="devShell">352<description>Development environment with packages and hooks</description>353<example>354devShells.default = pkgs.mkShell {355 packages = with pkgs; [ nodejs yarn ];356 shellHook = ''357 echo "Development environment ready"358 '';359};360</example>361</pattern>362</patterns>363364<tools>365<tool name="nix flake update">366<description>Update all inputs to their latest versions</description>367<use_case>Regular dependency updates</use_case>368</tool>369370<tool name="nix flake update input-name">371<description>Update a specific input</description>372<use_case>Selective updates to test compatibility</use_case>373</tool>374375<tool name="nix flake show">376<description>Display all flake outputs</description>377<use_case>Exploring available packages and configurations</use_case>378</tool>379380<tool name="nix flake check">381<description>Validate flake and run checks</description>382<use_case>CI/CD validation, pre-commit checks</use_case>383</tool>384</tools>385</flakes>386387<home_manager>388<concept name="module_structure">389<description>Standard Home Manager module structure</description>390<example>391{ config, pkgs, lib, ... }:392{393options.custom.feature = {394enable = lib.mkEnableOption "feature description";395};396397config = lib.mkIf config.custom.feature.enable { # configuration when enabled398};399}400</example>401</concept>402403<patterns>404<pattern name="by_program">405<description>Organize modules by program name</description>406<example>407home-manager/programs/git.nix408home-manager/programs/neovim.nix409home-manager/programs/tmux.nix410</example>411</pattern>412413<pattern name="by_category">414<description>Organize modules by category</description>415<example>416home-manager/development/default.nix417home-manager/shell/default.nix418home-manager/editors/default.nix419</example>420</pattern>421422<pattern name="imports">423<description>Import multiple modules</description>424<example>425imports = [426 ./programs/git.nix427 ./programs/neovim.nix428 ./shell/fish.nix429];430</example>431</pattern>432433<pattern name="basic_enable">434<description>Enable a program with defaults</description>435<example>436programs.git.enable = true;437</example>438</pattern>439440<pattern name="with_options">441<description>Enable and configure a program</description>442<example>443programs.git = {444 enable = true;445 userName = "name";446 userEmail = "email";447 extraConfig = {448 core.editor = "nvim";449 init.defaultBranch = "main";450 };451};452</example>453<decision_tree name="when_to_use">454<question>Does Home Manager provide built-in module for this program?</question>455<if_yes>Use programs.* with configuration options</if_yes>456<if_no>Use home.file or xdg.configFile for manual configuration</if_no>457</decision_tree>458</pattern>459460<pattern name="package_override">461<description>Use alternative package version</description>462<example>463programs.git = {464 enable = true;465 package = pkgs.gitFull;466};467</example>468</pattern>469470<pattern name="home.file">471<description>Manage dotfiles directly</description>472<example>473home.file.".config/app/config" = {474 source = ./config;475 # or476 text = ''477 key = value478 '';479};480</example>481</pattern>482483<pattern name="xdg.configFile">484<description>XDG config directory files</description>485<example>486xdg.configFile."app/config".source = ./config;487</example>488</pattern>489490<pattern name="home.sessionVariables">491<description>Environment variables for login shells</description>492<example>493home.sessionVariables = {494 EDITOR = "nvim";495 PAGER = "less";496};497</example>498</pattern>499500<pattern name="home.sessionPath">501<description>Add directories to PATH</description>502<example>503home.sessionPath = [ "$HOME/.local/bin" ];504</example>505</pattern>506</patterns>507508<common_modules>509<concept name="programs.git">510<description>Git version control configuration</description>511<example>512programs.git = {513enable = true;514userName = "Your Name";515userEmail = "email@example.com";516signing = {517key = "KEY_ID";518signByDefault = true;519};520aliases = {521co = "checkout";522st = "status";523};524extraConfig = {525core.editor = "nvim";526};527};528</example>529</concept>530531<concept name="programs.neovim">532<description>Neovim editor configuration</description>533<example>534programs.neovim = {535 enable = true;536 viAlias = true;537 vimAlias = true;538 plugins = with pkgs.vimPlugins; [539 vim-commentary540 vim-surround541 ];542 extraConfig = ''543 set number544 set relativenumber545 '';546 extraLuaConfig = ''547 vim.opt.expandtab = true548 '';549};550</example>551</concept>552553<concept name="programs.fish">554<description>Fish shell configuration</description>555<example>556programs.fish = {557 enable = true;558 shellInit = ''559 set -g fish_greeting560 '';561 shellAliases = {562 ll = "ls -lah";563 };564 functions = {565 gitignore = "curl -sL https://www.gitignore.io/api/$argv";566 };567 plugins = [568 { name = "z"; src = pkgs.fishPlugins.z.src; }569 ];570};571</example>572</concept>573574<concept name="programs.tmux">575<description>Terminal multiplexer configuration</description>576<example>577programs.tmux = {578 enable = true;579 terminal = "screen-256color";580 keyMode = "vi";581 plugins = with pkgs.tmuxPlugins; [582 sensible583 yank584 ];585 extraConfig = ''586 set -g mouse on587 '';588};589</example>590</concept>591592<concept name="programs.direnv">593<description>Directory-specific environment loader</description>594<example>595programs.direnv = {596 enable = true;597 nix-direnv.enable = true;598 enableBashIntegration = true;599 enableZshIntegration = true;600};601</example>602</concept>603</common_modules>604605<best_practices>606<practice priority="critical">607Use programs.\* when available instead of manual configuration608</practice>609610<practice priority="critical">611Set home.stateVersion to your initial HM version and do not change after initial setup unless migrating612</practice>613614<practice priority="high">615Group related configurations in separate modules for maintainability616</practice>617618<practice priority="high">619Use lib.mkIf for conditional configuration620</practice>621622<practice priority="medium">623Prefer xdg.configFile over home.file for XDG-compliant apps624</practice>625626<practice priority="medium">627Use home.packages for additional packages not configured via programs.*628</practice>629</best_practices>630631<concept name="state_version">632<description>Track Home Manager state version for compatibility</description>633<example>634home.stateVersion = "24.11"; # Current stable. 25.05 (upcoming).635</example>636<warning>Do not change after initial setup unless migrating</warning>637</concept>638639<concept name="minimal_mode">640<description>HM 24.11+ (25.05 upcoming) supports minimal mode for faster evaluation</description>641<example>642imports = [643 "${modulesPath}/programs/fzf.nix"644];645</example>646<note>Advanced users optimizing evaluation time</note>647</concept>648</home_manager>649650<workflow>651<phase name="analyze">652<objective>Understand Nix expression requirements</objective>653<step>1. Identify target: flake, module, derivation, or expression</step>654<step>2. Check existing patterns in project</step>655<step>3. Consult Serena memories for conventions</step>656</phase>657<phase name="implement">658<objective>Write idiomatic Nix code</objective>659<step>1. Follow patterns from decision trees</step>660<step>2. Use appropriate lib functions</step>661<step>3. Apply best practices for target type</step>662</phase>663<phase name="validate">664<objective>Verify Nix expression correctness</objective>665<step>1. Check syntax with nix flake check</step>666<step>2. Verify evaluation with nix eval</step>667<step>3. Test build with nix build</step>668</phase>669</workflow>670671<error_escalation>672<level severity="low">673<example>Style inconsistency in Nix expression</example>674<action>Note issue, suggest formatting</action>675</level>676<level severity="medium">677<example>Evaluation error or type mismatch</example>678<action>Debug with --show-trace, fix expression</action>679</level>680<level severity="high">681<example>Build failure in derivation</example>682<action>Analyze build log, present options to user</action>683</level>684<level severity="critical">685<example>Impure expression breaking reproducibility</example>686<action>Block operation, require pure alternatives</action>687</level>688</error_escalation>689690<constraints>691<must>Use lib functions for complex operations</must>692<must>Follow project's existing Nix patterns</must>693<must>Maintain reproducibility in all expressions</must>694<avoid>Impure paths and absolute references</avoid>695<avoid>Nested with statements</avoid>696<avoid>Overusing rec for attribute sets</avoid>697</constraints>698699<related_agents>700<agent name="design">Architecture and module dependency analysis for Nix configurations</agent>701<agent name="execute">Implementation of flake outputs, Home Manager modules, and NixOS configurations</agent>702<agent name="code-quality">Nix expression validation, formatting, and best practices enforcement</agent>703</related_agents>704705<related_skills>706<skill name="serena-usage">Symbol operations for navigating Nix expressions and module definitions</skill>707<skill name="context7-usage">Fetch latest nixpkgs and Home Manager documentation</skill>708<skill name="investigation-patterns">Debug evaluation errors and understand derivation failures</skill>709</related_skills>710711<nixos>712<patterns>713<pattern name="basic">714<description>Basic NixOS configuration with Home Manager</description>715<example>716nixosConfigurations.hostname = nixpkgs.lib.nixosSystem {717 system = "x86_64-linux";718 modules = [719 ./configuration.nix720 home-manager.nixosModules.home-manager721 ];722 specialArgs = { inherit inputs; };723};724</example>725</pattern>726727<pattern name="standalone_home_manager">728<description>Standalone Home Manager without NixOS</description>729<example>730homeConfigurations."user@host" = home-manager.lib.homeManagerConfiguration {731 pkgs = nixpkgs.legacyPackages.x86_64-linux;732 modules = [ ./home.nix ];733 extraSpecialArgs = { inherit inputs; };734};735</example>736</pattern>737738<pattern name="as_nixos_module">739<description>Home Manager as a NixOS module</description>740<example>741{742 imports = [ home-manager.nixosModules.home-manager ];743744home-manager.useGlobalPkgs = true;745home-manager.useUserPackages = true;746home-manager.users.username = import ./home.nix;747}748</example>749</pattern>750</patterns>751</nixos>