# Nix Tool Preference Directive ## Core Instruction **Always prioritize Nix-based tools (`nix_nix`, `nix_nix_versions`, `nix-shell`, `nix run`, etc.) for querying packages, versions, options, environments, and reproducible workflows whenever relevant.** Nix ensures declarative, isolated, reproducible results. Use these before generic searches, manual installs, or distro tools. ## Trigger Conditions - Package discovery/version info: `nix_nix` or `nix_nix_versions`. - Environment setup: `nix-shell`, `nix develop`. - NixOS/Home-manager config: `nix_nix action=options`. - Reproducibility/CI: Nix flakes/builds. **Fallback**: Native tools if Nix unsuitable; note Nix alternative. ## Specific Tools ### **`nix_nix`** - Query NixOS, Home Manager, Darwin, flakes, and more | Parameter | Description | |-----------|-------------| | `action` | `search`, `info`, `stats`, `options`, `channels`, `flake-inputs`, `cache` | | `source` | `nixos`, `home-manager`, `darwin`, `flakes`, `flakehub`, `nixvim`, `wiki`, `nix-dev`, `noogle`, `nixhub` | | `query` | Search term, name, or prefix | | `type` | `packages`, `options`, `programs`, `list`, `ls`, `read` | | `channel` | `unstable`, `stable`, `25.05` | | `limit` | 1-100 (or 1-2000 for flake-inputs read) | ### **`nix_nix_versions`** - Get package version history from NixHub.io | Parameter | Description | |-----------|-------------| | `package` | Package name | | `version` | Specific version to find (optional) | | `limit` | 1-50 | ## Key Use-Cases | Use-Case | Tool/Command | Example | |----------|--------------|---------| | Search packages | `nix_nix` | `nix_nix action=search query=ripgrep source=nixos` | | Find options | `nix_nix` | `nix_nix action=options query=services.nginx source=nixos` | | Flake inputs | `nix_nix` | `nix_nix action=flake-inputs query=read source=flakes` | | Version history | `nix_nix_versions` | `nix_nix_versions package=nodejs` | | Temporary tool | `nix run` | `nix run nixpkgs#ripgrep -- search_term` | | Project env | `nix develop` | Loads `flake.nix` deps | | Pure shell | `nix-shell --pure` | Isolated env | ## Agent Integration - **Query packages/options first**: Use `nix_nix` before assuming availability. - **Pin versions**: Check `nix_nix_versions` for stable choices. - **Generate configs**: Create `shell.nix`/flakes based on queries. - **Verify**: `nix --version` if needed. ## Example `shell.nix` ````nix { pkgs ? import {} }: pkgs.mkShell { buildInputs = with pkgs; [ nodejs_20 python311 ripgrep ]; } ```` ## Flake Creation for Packages **Guideline**: Create `flake.nix` for building packages, reproducible dev shells, multi-language support, and cross-platform compatibility. **Triggers**: - Building language-specific packages (e.g., Rust via `crane`). - Configurable dev environments (Rust/Node/Go/etc.). - Use `nix_nix` first: e.g., `nix_nix action=search query=crane source=flakes` for libs. **Key Structure**: - **inputs**: `nixpkgs`, `flake-parts`, lang tools (`crane`, `fenix`, etc.). - **outputs**: `packages.default`, `devShells.default` with `shellHook`. - Multi-system: `x86_64-linux`, `aarch64-darwin`, etc. **Example `flake.nix`** (Rust MCP server + configurable dev envs via `dev-environments`): ````nix { description = "Rust documentation MCP server"; inputs = { flake-parts.url = "github:hercules-ci/flake-parts"; nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; dev-environments.url = "github:Govcraft/dev-environments"; crane = { url = "github:ipetkov/crane"; }; }; outputs = inputs@{ flake-parts, nixpkgs, crane, ... }: flake-parts.lib.mkFlake { inherit inputs; } { imports = [ inputs.dev-environments.flakeModules.rust inputs.dev-environments.flakeModules.golang inputs.dev-environments.flakeModules.node inputs.dev-environments.flakeModules.typst ]; systems = [ "x86_64-linux" "aarch64-linux" "aarch64-darwin" "x86_64-darwin" ]; perSystem = { config, self', inputs', pkgs, system, ... }: let craneLib = inputs.crane.mkLib pkgs; # Common arguments shared between all builds commonArgs = { src = craneLib.cleanCargoSource ./.; buildInputs = with pkgs; [ openssl ] ++ pkgs.lib.optionals pkgs.stdenv.isDarwin [ # Additional darwin specific inputs pkgs.darwin.apple_sdk.frameworks.Security pkgs.darwin.apple_sdk.frameworks.SystemConfiguration ]; nativeBuildInputs = with pkgs; [ pkg-config perl ]; }; # Build *just* the cargo dependencies cargoArtifacts = craneLib.buildDepsOnly commonArgs; # Build the actual crate itself rustdocs-mcp-server = craneLib.buildPackage (commonArgs // { inherit cargoArtifacts; }); in { # Add the package packages = { default = rustdocs-mcp-server; rustdocs-mcp-server = rustdocs-mcp-server; }; # Golang Development Environment Options # ---------------------------------- # enable: boolean - Enable/disable the Golang environment # goVersion: enum - Go toolchain version ("1.18", "1.19", "1.20", "1.21, "1.22", "1.23") (default: "1.23") # withTools: list of strings - Additional Go tools to include (e.g., "golint", "gopls") # extraPackages: list of packages - Additional packages to include go-dev = { # enable = true; # goVersion = "1.23"; # withTools = [ "gopls" "golint" ]; # extraPackages = [ ]; }; # Rust Development Environment Options # ---------------------------------- # enable: boolean - Enable/disable the Rust environment # rustVersion: enum - Rust toolchain ("stable", "beta", "nightly") (default: "stable") # withTools: list of strings - Additional Rust tools to include (converted to cargo-*) # extraPackages: list of packages - Additional packages to include # ide.type: enum - IDE preference ("rust-rover", "vscode", "none") (default: "none") rust-dev = { enable = true; rustVersion = "stable"; # Example configuration: # withTools = [ ]; # Will be prefixed with cargo- extraPackages = [ pkgs.openssl pkgs.openssl.dev pkgs.pkg-config ]; # Add openssl libs, dev libs, and pkg-config # ide.type = "none"; }; # Node.js Development Environment Options # ------------------------------------- # enable: boolean - Enable/disable the Node environment # nodeVersion: string - Version of Node.js to use (default: "20") # withTools: list of packages - Global tools to include (default: ["typescript" "yarn" "pnpm"]) # extraPackages: list of packages - Additional packages to include # ide.type: enum - IDE preference ("vscode", "webstorm", "none") (default: "none") node-dev = { # Example configuration: # enable = true; # nodeVersion = "20"; # withTools = [ "typescript" "yarn" "pnpm" ]; # extraPackages = [ ]; # ide.type = "none"; }; typst-dev = { # Example configuration: # enable = true; # withTools = [ "typst-fmt" "typst-lsp" ]; # extraPackages = [ ]; # ide.type = "none"; }; # Create the combined shell devShells.default = pkgs.mkShell { buildInputs = nixpkgs.lib.flatten (nixpkgs.lib.attrValues config.env-packages ++ [ ]); # Combine existing hooks with new exports for OpenSSL shellHook = '' ${nixpkgs.lib.concatStringsSep "\n" (nixpkgs.lib.attrValues config.env-hooks)} # Export paths for openssl-sys build script export OPENSSL_DIR="${pkgs.openssl.out}" export OPENSSL_LIB_DIR="${pkgs.openssl.out}/lib" export OPENSSL_INCLUDE_DIR="${pkgs.openssl.dev}/include" # Ensure pkg-config can find the openssl .pc file export PKG_CONFIG_PATH="${pkgs.openssl.dev}/lib/pkgconfig:${pkgs.pkg-config}/lib/pkgconfig:$PKG_CONFIG_PATH" # Debug: List contents of OpenSSL lib directory to verify echo "OpenSSL lib directory contents:" ls -la ${pkgs.openssl.out}/lib || echo "Failed to list OpenSSL lib directory" echo ">>> OpenSSL environment variables set by shellHook <<<" ''; }; # Add app for `nix run` apps = { default = { type = "app"; program = "${rustdocs-mcp-server}/bin/rustdocs_mcp_server"; }; }; }; }; } ```` **Usage**: - `nix develop` for dev shell. - `nix build` for package. - `nix run` for app. ## uv2nix for Python Projects **When to use**: Python projects with `uv.lock` - handles complex dependencies not in nixpkgs. **Inputs needed**: ```nix pyproject-nix.url = "github:pyproject-nix/pyproject.nix"; uv2nix.url = "github:pyproject-nix/uv2nix"; pyproject-build-systems.url = "github:pyproject-nix/build-system-pkgs"; ``` **Critical API details**: - Function is `loadWorkspace`, NOT `loadUvWorkspace` (despite tool name) - Use `python = pkgs.python313`, NOT `inherit (pkgs) python313` - Creates virtual environments via `mkVirtualEnv`, not traditional derivations **Overlay composition order** (must be exact): 1. `pyproject-build-systems.overlays.default` 2. Project overlay from `workspace.mkPyprojectOverlay` 3. Custom `pyprojectOverrides` **Pattern**: ```nix workspace = uv2nix.lib.workspace.loadWorkspace { workspaceRoot = ./.; }; overlay = workspace.mkPyprojectOverlay { sourcePreference = "wheel"; }; pythonSet = (pkgs.callPackage pyproject-nix.build.packages { python = pkgs.python313; }).overrideScope (lib.composeManyExtensions [ pyproject-build-systems.overlays.default overlay pyprojectOverrides ]); in { packages.default = pythonSet.mkVirtualEnv "env-name" workspace.deps.default; } ``` **Output**: Virtual env with executables in `result/bin/`. ## Prohibitions - Avoid non-reproducible installs (e.g., `apt`). - Avoid non-declarative package management (e.g., `nix-env -iA nixos.ripgrep` or `nix profile add nixpkgs#ripgrep`) - Always check Nix tools first. **Next**: Query a package with `nix_nix` or generate `shell.nix`.