nxv

star 129

Find any version of any Nix package across nixpkgs git history using the nxv CLI or HTTP API. Use when asked which nixpkgs commit shipped a specific package version (e.g. "python 2.7", "nodejs 15", "ruby 2.6"), when looking up package metadata/license/homepage, when generating a `nix shell nixpkgs/<commit>#pkg` invocation for an old version, or when querying the public/private nxv server. Triggers include "find python 2.7 in nixpkgs", "which commit had nodejs 15.14", "when was foo added/removed", "give me the nix shell command for ruby 2.6", "search nixpkgs for X", or any question about historical Nix package versions.

utensils By utensils schedule Updated 6/13/2026

name: nxv description: Find any version of any Nix package across nixpkgs git history using the nxv CLI or HTTP API. Use when asked which nixpkgs commit shipped a specific package version (e.g. "python 2.7", "nodejs 15", "ruby 2.6"), when looking up package metadata/license/homepage, when generating a nix shell nixpkgs/<commit>#pkg invocation for an old version, or when querying the public/private nxv server. Triggers include "find python 2.7 in nixpkgs", "which commit had nodejs 15.14", "when was foo added/removed", "give me the nix shell command for ruby 2.6", "search nixpkgs for X", or any question about historical Nix package versions. license: MIT allowed-tools: Bash, Read, Glob, Grep

nxv — Nix Version Index

nxv is a Rust CLI + HTTP API that indexes nixpkgs channel-release history (2016+) into a local SQLite database with a bloom filter for fast lookups. It answers: "which exact nixpkgs commit shipped version X of package Y?" and produces the nix shell nixpkgs/<commit>#pkg command you need to actually use it.

Quick Reference

nxv search python                        # All python packages (most recent per version)
nxv search python 2.7                    # Filter by version (prefix match)
nxv search python --exact                # Exact attribute name only
nxv search "json parser" --desc          # Full-text search package descriptions
nxv info python311                       # Detailed info for current version
nxv info python311 3.11.4                # Detailed info for specific version
nxv history python311                    # Version timeline (first/last seen)
nxv history python311 3.11.4             # When was 3.11.4 available?
nxv stats                                # Index statistics
nxv update                               # Refresh index + check for newer nxv binary
nxv update --no-self-update              # Refresh index only (CI / systemd timers)
nxv serve --host 0.0.0.0 --port 8080     # Start HTTP API + web UI
nxv completions zsh                      # Generate shell completions
nxv skill install                        # Install this skill for detected AI agents
nxv skill list                           # Agents, skill paths, install status

How to Use This Skill

Parse $ARGUMENTS to determine the action:

  • If arguments look like a subcommand (search, info, history, stats, update, serve, completions, skill, and indexer-only index, dedupe, publish, keygen), run that subcommand.
  • If arguments look like a package name (e.g. python, nodejs 15, ruby 2.6), default to nxv search.
  • If arguments look like a question ("when was X added", "which commit has Y"), pick search or history accordingly.
  • If no arguments, run nxv stats to give the user a quick health check of their index.

For agents: always pass --format json (CLI) or hit the HTTP API and pipe to jq. The table format is human-only; column widths are terminal-dependent. Exception: nxv stats has no --format flag — use GET /api/v1/stats when you need stats as JSON.

Global Options

Every CLI invocation accepts:

Flag Description
--db-path <PATH> Path to the index database (default: platform data dir)
-v, --verbose -v info, -vv debug (SQL queries, HTTP requests)
-q, --quiet Suppress all output except errors
--no-color Disable colored output (also honors NO_COLOR)
--api-timeout <SECS> API request timeout when using remote backend (default: 30)

Local vs Remote Backend

nxv transparently runs against either a local SQLite index or a remote nxv serve instance. Set NXV_API_URL to switch:

# Use the public hosted instance — no local index needed
NXV_API_URL=https://nxv.urandom.io nxv search nodejs 15
NXV_API_URL=https://nxv.urandom.io nxv info python311

# Or your own private instance
export NXV_API_URL=http://gpu-host:8080
nxv search rust 1.70

If NXV_API_URL is unset, the CLI uses the local index at ~/Library/Application Support/nxv/index.db (macOS) or ~/.local/share/nxv/index.db (Linux). Run nxv update to download the latest published index on first use.

Search

Find packages and the commits where each version existed:

nxv search python                                    # Recent per (pkg, version)
nxv search python 3.11                               # Version prefix filter
nxv search python --exact                            # Exact attribute name only
nxv search python --license MIT                      # Filter by license
nxv search python --sort date --reverse              # Oldest first
nxv search "web server" --desc                       # FTS5 description search
nxv search python --show-platforms                   # Add platforms column
nxv search python --full                             # All commits (no dedup)
nxv search python --limit 5                          # Cap at 5 results
nxv search python --format json                      # Machine-readable JSON
nxv search python --format plain                     # TSV for shell scripts

JSON shape per row:

{
  "attribute_path": "python311",
  "version": "3.11.4",
  "description": "A high-level dynamically-typed programming language",
  "license": "Python-2.0",
  "first_commit_hash": "abc123...",
  "first_commit_date": "2023-06-15T00:00:00Z",
  "last_commit_hash": "def456...",
  "last_commit_date": "2023-12-01T00:00:00Z"
}

Info

Detailed metadata for one package version (description, license, homepage, platforms, source path, known vulnerabilities):

nxv info python311                       # Latest known version
nxv info python311 3.11.4                # Specific version (positional)
nxv info python311 -V 3.11.4             # Specific version (flag form)
nxv info python311 --format json

History

Version timeline — when each version first appeared and when it was last seen:

nxv history python311                    # All versions of python311
nxv history python311 3.11.4             # Just one version's window
nxv history python311 --full             # Add commits, license, homepage, etc.
nxv history python311 --format json

JSON shape per row:

{
  "version": "3.11.4",
  "first_seen": "2023-06-15T00:00:00Z",
  "last_seen": "2023-12-01T00:00:00Z",
  "is_insecure": false
}

Using a Found Version

The whole point. Take a first_commit_hash (or last_commit_hash) from search/history output and feed it to Nix:

# Drop into a shell with that exact version
nix shell nixpkgs/e4a45f9#python

# Run it once
nix run nixpkgs/e4a45f9#python

# Add to a flake input
inputs.nixpkgs-python27.url = "github:NixOS/nixpkgs/<commit>";

Pick first_commit_hash for the canonical "introduced in" commit; pick last_commit_hash if you want the most recent commit that still shipped that version.

Index Management

nxv update                               # Refresh index + check for newer nxv binary
nxv update --force                       # Force full re-download of the index
nxv update --no-self-update              # Only refresh the index, leave binary alone
nxv update --skip-verify                 # Skip minisign signature check (INSECURE)
nxv update --public-key /path/key.pub    # Use a custom public key (self-hosted index)
nxv update --manifest-url <URL>          # Use a custom manifest (self-hosted index)
nxv stats                                # Index size, commit range, last update

nxv update always refreshes the package index first. Then it checks GitHub for a newer nxv release:

  • Local install (install.sh / manual download): downloads the platform binary, verifies SHA-256, atomically swaps the running executable.
  • Nix / cargo / Homebrew: prints the matching upgrade hint (e.g. brew upgrade nxv) and exits successfully.

Set NXV_NO_SELF_UPDATE=1 for CI/systemd timers that should only refresh the index.

API Server

nxv serve                                            # 127.0.0.1:8080 (default)
nxv serve --host 0.0.0.0 --port 3000                 # Public bind
nxv serve --cors                                     # Enable CORS for all origins
nxv serve --cors-origins https://app.example.com     # Restrict CORS
nxv serve --rate-limit 10 --rate-limit-burst 20      # Per-IP rate limit

The server bundles:

  • Web UI at / (Tailwind v4 + vanilla JS, embedded at build time)
  • OpenAPI docs at /docs (Scalar UI)
  • REST API at /api/v1/* — see endpoints below
  • Cache headers: 1h on cacheable package routes; never on /health, /metrics

HTTP Endpoints

All paths are under /api/v1. Wrapped responses always look like { "data": ..., "meta": {...} } for paginated lists, { "data": ... } for single items.

Method Path Purpose
GET /search?q=<name>&limit=&offset=&sort=&exact= Search packages
GET /search/description?q=<text>&limit=&offset= Full-text search descriptions (FTS5)
GET /packages/{attr} All version records for a package
GET /packages/{attr}/history Version timeline (first/last seen)
GET /packages/{attr}/versions/{version} All records for one version
GET /packages/{attr}/versions/{version}/first First-seen commit
GET /packages/{attr}/versions/{version}/last Last-seen commit
GET /stats Index statistics
GET /health Liveness probe (uncached)
GET /metrics Server metrics (uncached)

Search query parameters:

Parameter Type Description
q string Search query (required)
version string Version filter (prefix match)
exact boolean Exact attribute name match
license string License filter
sort string date, version, or name
reverse boolean Reverse sort order
limit integer Max results (default 50)
offset integer Results to skip (default 0)

Quick examples against the public instance:

curl -s "https://nxv.urandom.io/api/v1/search?q=python&version=3.11&limit=5" | jq
curl -s "https://nxv.urandom.io/api/v1/packages/python311/history" | jq '.data[0:3]'
curl -s "https://nxv.urandom.io/api/v1/packages/nodejs_15/versions/15.14.0/first" | jq
curl -s "https://nxv.urandom.io/api/v1/stats" | jq '.data'

Skill Management

nxv can install this very skill for any major AI coding agent — the binary embeds the SKILL.md and writes it where each agent looks, per the Agent Skills standard:

nxv skill install                        # Install user-wide for detected agents
nxv skill install --project              # Install into the current project (.claude + .agents)
nxv skill install claude codex           # Install for specific agents only
nxv skill install --all                  # Install for every supported agent
nxv skill install copilot --dir ~/repo   # Project install into another directory
nxv skill list                           # Show agents, paths, install status
nxv skill show                           # Print the SKILL.md to stdout
nxv skill uninstall --project            # Remove project-level installs

Supported agents and where the skill lands (<dir>/nxv/SKILL.md):

Agent User-wide Project-level
claude ~/.claude/skills/ .claude/skills/
codex ~/.codex/skills/ .agents/skills/
pi ~/.pi/agent/skills/ .pi/skills/
openclaw ~/.openclaw/skills/ .agents/skills/
copilot ~/.copilot/skills/ .github/skills/
cursor ~/.cursor/skills/ .agents/skills/
gemini ~/.gemini/skills/ .agents/skills/
amp ~/.config/amp/skills/ .agents/skills/
goose ~/.config/goose/skills/ .agents/skills/
agents ~/.agents/skills/ .agents/skills/

The table shows each agent's primary directory — the one nxv skill install <agent> writes to. Several agents read additional locations: Copilot reads .github/skills/, .claude/skills/, or .agents/skills/ in a repository, and Pi reads .agents/skills/ as well as .pi/skills/.

Semantics:

  • With no agent arguments, a user-wide install targets the agents detected on the machine (their config dir exists), falling back to the generic agents directory if none are found. A project install (--project / --dir) defaults to the .claude + .agents pair — per the read paths above, every supported agent picks up one of the two.
  • Agents sharing a directory (e.g. codex/cursor/gemini at project level) are deduplicated into a single write.
  • Install overwrites skills/nxv/SKILL.md unconditionally and never touches other files; uninstall removes only that file (and the nxv/ directory if it is then empty).

Indexer Commands (feature-gated)

These require nxv built with --features indexer (cargo build --features indexer or nix build .#nxv-indexer). The indexer ingests channel-release snapshots from releases.nixos.org — no nixpkgs checkout and no Nix evaluation needed for the main path:

# Ingest new channel releases (default channels: nixpkgs-unstable + nixos-unstable-small)
nxv index                                            # Incremental: only new releases
nxv index --channel nixpkgs-unstable                 # Restrict to one channel
nxv index --since 2024-01-01 --until 2024-06-30      # Bound by release date
nxv index --strict --report report.json              # CI mode: gates fatal, JSON report
nxv index --backfill-evals                           # One-time 2016-2020 era (needs `nix`, ~2-3h)
nxv index --head-eval                                # Evaluate master HEAD when channels stall (needs `nix`)
nxv index --retry-failed                             # Re-attempt failed/parked releases
nxv index --max-releases 5                           # Bound a run (testing)

# Repair duplicate rows in pre-v4 databases (also runs during v3->v4 migration)
nxv dedupe --dry-run                                 # Preview
nxv dedupe                                           # Run

# Publish distribution-ready compressed artifacts + manifest
nxv publish --output ./publish --url-prefix https://your-server/nxv
nxv publish --output ./publish --url-prefix https://... --sign --secret-key nxv.key
nxv publish --output ./publish --url-prefix https://... --artifact-name-prefix run-123-

# Generate a minisign keypair for signing manifests
nxv keygen --secret-key ./nxv.key --public-key ./nxv.pub

Every recorded commit is a real, Hydra-built channel commit — nix shell commands produced from the index hit the binary cache instead of compiling from source. Version ranges mean "observed at both endpoints"; a version that lived shorter than one channel advance (~a day) may be missed.

Retired commands: nxv backfill and nxv reset are gone — snapshots carry complete metadata (source_path, homepage, known_vulnerabilities), and there is no checkout to reset.

Most users never need these — they consume a pre-built published index via nxv update. Only run these when self-hosting an index. Use --artifact-name-prefix for mutable stores such as GitHub Releases so payload assets can be uploaded under immutable names before replacing manifest.json.

Key Environment Variables

Variable Purpose
NXV_API_URL Point CLI at a remote nxv serve instead of the local DB
NXV_DB_PATH Override local SQLite path
NXV_API_TIMEOUT HTTP client timeout in seconds (default 30)
NXV_MANIFEST_URL Override the manifest URL used by nxv update
NXV_PUBLIC_KEY Public key for manifest verification (path or raw key)
NXV_SECRET_KEY Secret key for nxv publish --sign (path or raw content)
NXV_SKIP_VERIFY Skip minisign signature check (INSECURE — dev/testing only)
NXV_NO_SELF_UPDATE Skip the binary self-update check during nxv update
NXV_VERSION Pin the version installed by install.sh (self-update targets latest)
NXV_HOST nxv serve bind host
NXV_PORT nxv serve listen port
NXV_RATE_LIMIT nxv serve per-IP rate limit (req/sec)
NXV_FRONTEND_DIR nxv serve reads frontend assets from disk on every request (dev mode)
NO_COLOR Disable ANSI colors

Data Paths

The local index lives in platform data directories:

  • macOS: ~/Library/Application Support/nxv/
  • Linux: ~/.local/share/nxv/

Files:

  • index.db — SQLite database with package versions
  • bloom.bin — Bloom filter sibling for fast negative lookups (loaded at search time)

Safe to delete; nxv update will rebuild from the published manifest.

Agent Patterns

Find the commit that introduced a specific version (CLI):

nxv search python 3.11.4 --exact --format json | \
  jq '.[0] | {pkg: .attribute_path, version, commit: .first_commit_hash, date: .first_commit_date}'

Generate the nix shell invocation directly (CLI):

nxv search nodejs 15 --exact --format json | \
  jq -r '.[0] | "nix shell nixpkgs/\(.first_commit_hash | .[0:7])#\(.attribute_path)"'

Find a package version on the public API:

curl -s "https://nxv.urandom.io/api/v1/packages/python27/versions/2.7.18/first" | \
  jq -r '.data | "nix shell nixpkgs/\(.first_commit_hash | .[0:7])#\(.attribute_path)"'

Check whether a version of a package was ever in nixpkgs (HTTP):

curl -s "https://nxv.urandom.io/api/v1/packages/ruby/history" | \
  jq '.data[] | select(.version | startswith("2.6"))'

Get the index freshness (newest ingested channel commit):

curl -s "https://nxv.urandom.io/api/v1/stats" | \
  jq '.data | {commit: .last_indexed_commit, date: .last_indexed_date, packages: .unique_names}'

Key Invariants for Agents

  • Search is dedup-by-default: by default, only the most recent record per (attribute_path, version) pair is returned. Pass --full (CLI) or use the /packages/{attr} HTTP endpoint to see every commit.
  • Version filters are prefix matches: nxv search python 3.11 matches 3.11.0, 3.11.4, 3.11.10, etc. Use --exact for whole-attribute matches, not for whole-version matches.
  • Bloom filter gives instant negatives: a search for a nonsense package name returns in <1 ms because the bloom filter rejects it before SQLite is touched. False positives are possible but rare.
  • Coverage starts in September 2016: nixpkgs commits before then are not indexed. Anything older needs raw git spelunking.
  • Self-hosted indexes need a public key: pass --public-key or set NXV_PUBLIC_KEY when consuming a manifest you signed yourself, otherwise nxv update rejects the signature.
  • --format json shape is stable: safe to pipe to jq. Breaking shape changes would be a semver bump.
  • /api/v1 data responses always wrap in {data, meta} (or {data} for single items): do jq '.data' first. Exceptions: the operational /health and /metrics endpoints are unwrapped.

Practical Tips

  • Just want a python 2.7 shell? nxv search python 2.7 --exact --format json | jq -r '.[0].first_commit_hash', then nix shell nixpkgs/<hash>#python27.
  • Use --exact when the package name is unambiguous; otherwise python returns dozens of variants (python27, python311, python311Packages.numpy, etc.).
  • Use --desc for fuzzy intent ("a package that does X") instead of exact name searches.
  • Set NXV_API_URL=https://nxv.urandom.io to skip the ~190MB index download entirely if you only need occasional lookups.
  • Update regularly: the public index is republished every 6 hours (publish-index.yml); nxv update pulls the latest.
  • For CI: pin to NXV_NO_SELF_UPDATE=1 nxv update so the runner refreshes the index but never tries to swap its own binary.

Updating This Skill

This skill is generated by the nxv binary itself. To refresh it after upgrading nxv:

nxv update                               # Get the latest nxv (also refreshes the index)
nxv skill install                        # Rewrite user-wide installs from the new binary
nxv skill install --project              # ...or refresh a project-level install

Without an nxv binary on hand, fetch the canonical copy from the repository:

curl -sL https://raw.githubusercontent.com/utensils/nxv/main/.claude/skills/nxv/SKILL.md \
  -o ~/.claude/skills/nxv/SKILL.md
Install via CLI
npx skills add https://github.com/utensils/nxv --skill nxv
Repository Details
star Stars 129
call_split Forks 1
navigation Branch main
article Path SKILL.md
More from Creator