# 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 <nixpkgs> {} }:

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/<package-name>`.

## 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`.
