Files
local-cal/.ruler/09-NIX.md
Dmytro Stanchiev 206f028fdf init ruler
Signed-off-by: Dmytro Stanchiev <git@dmytros.dev>
2026-04-06 20:48:07 -04:00

10 KiB

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

{ 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):

{
  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:

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:

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.