nixpkgs-update

Update nixpkgs packages with nix-update and nixpkgs-review. Activate when user wants to bump a package version, contribute to nixpkgs, update Nix packages, or mentions nix-update, nixpkgs-review, or nixpkgs contribution.

allowed_tools: Task, AskUserQuestion

$ Instalar

git clone https://github.com/majiayu000/claude-skill-registry /tmp/claude-skill-registry && cp -r /tmp/claude-skill-registry/skills/development/nixpkgs-update ~/.claude/skills/claude-skill-registry

// tip: Run this command in your terminal to install the skill


name: nixpkgs-update description: Update nixpkgs packages with nix-update and nixpkgs-review. Activate when user wants to bump a package version, contribute to nixpkgs, update Nix packages, or mentions nix-update, nixpkgs-review, or nixpkgs contribution. allowed-tools: Task, AskUserQuestion

Nixpkgs Package Update

Batch workflow for contributing package updates to NixOS/nixpkgs. Uses Repology API for discovery, strict filtering for easy updates, and git worktrees for parallel execution.

Workflow

1. DISCOVER  → Query Repology API
2. FILTER    → Keep only Rust/Go + by-name + no patches + buildable platform
3. VALIDATE  → Parallel Explore agents confirm "simple" complexity
4. SELECT    → AskUserQuestion (multi-select, only ezpz options)
5. UPDATE    → Parallel agents with git worktrees (10m timeout)
6. REPORT    → Collect and display PR URLs

Phase 1: Discover Outdated Packages

Query Repology API for outdated nixpkgs packages:

Task(
  subagent_type="general-purpose",
  model="haiku",
  prompt="Query Repology API for outdated nixpkgs packages.

Step 1 - Get outdated package names:
curl -s --user-agent 'nixpkgs-update/1.0' \
  'https://repology.org/api/v1/projects/?inrepo=nix_unstable&outdated=1&count=100' | \
  jq -r 'keys[:50][]'

Step 2 - For each package, get version details (respect 1 req/sec rate limit):
curl -s --user-agent 'nixpkgs-update/1.0' \
  'https://repology.org/api/v1/project/<name>' | \
  jq '{name: .[0].visiblename, nixpkgs: ([.[] | select(.repo==\"nix_unstable\")][0].version), newest: ([.[] | select(.status==\"newest\")][0].version)}'

Return list with: name, nixpkgs_version, newest_version."
)

Phase 2: Filter Candidates (Strict)

From Repology results, apply strict filtering. Only keep packages that meet ALL criteria:

Must Pass ALL:

  1. Location: pkgs/by-name/ only (not legacy paths)
  2. Type: Rust (buildRustPackage, cargoHash) OR Go (buildGoModule, vendorHash)
  3. Version bump: Patch or minor version (reject major bumps like 1.x → 2.x)
  4. Platform: Must support current platform (see platform check below)

Check with Glob/Grep:

# Check if package exists in by-name
ls pkgs/by-name/*/<package>/package.nix

# Check if Rust or Go
grep -l "buildRustPackage\|cargoHash" pkgs/by-name/*/<package>/package.nix
grep -l "buildGoModule\|vendorHash" pkgs/by-name/*/<package>/package.nix

Platform Check (CRITICAL)

# Get current system
CURRENT_PLATFORM=$(nix eval --raw --impure --expr 'builtins.currentSystem')
# e.g., "aarch64-darwin" or "x86_64-linux"

# Check if package supports current platform
nix eval .#<package>.meta.platforms --json | jq -e 'contains(["'$CURRENT_PLATFORM'"])'
# OR check for platform restrictions in package.nix:
grep -E "platforms\s*=.*linux" pkgs/by-name/*/<package>/package.nix  # Linux-only, skip on macOS
grep -E "platforms\s*=.*darwin" pkgs/by-name/*/<package>/package.nix  # macOS-only, skip on Linux

Discard packages that cannot be built/tested on current platform.

Discard any package that doesn't pass ALL filters.

Phase 3: Validate Each Candidate

For EACH filtered candidate, spawn Explore agent to verify simplicity:

Task(
  subagent_type="Explore",
  model="haiku",
  prompt="Check pkgs/by-name/*/<package>/package.nix for:
  1. has_patches: any patches = [] or patches directory?
  2. has_complex_postinstall: complex substituteInPlace, wrapProgram with many deps?
  3. has_overrides: overrideAttrs, overrideModAttrs?
  4. complexity: simple/medium/complex
  5. platform_restricted: does it have 'platforms = lib.platforms.linux' or similar restriction?

Return JSON: {has_patches: bool, complexity: 'simple'|'medium'|'complex', platform_restricted: bool, platforms: string}
Only packages with has_patches=false AND complexity='simple' AND supports current platform are acceptable."
)

Only packages with has_patches=false AND complexity=simple AND supports current platform proceed to selection.

Phase 4: Present Candidates (Multi-Select)

Present ONLY validated easy candidates:

AskUserQuestion(
  questions=[{
    "question": "Which packages would you like to update? (select multiple)",
    "header": "Packages",
    "options": [
      {"label": "some-rust-pkg (1.0.0 → 1.0.1)", "description": "Rust, simple, cross-platform"},
      {"label": "some-go-pkg (0.5.0 → 0.5.1)", "description": "Go, simple, cross-platform"}
    ],
    "multiSelect": true
  }]
)

Never show:

  • "may need manual work"
  • "complex"
  • "has patches"
  • Major version bumps
  • Platform-restricted packages that can't be tested locally

Phase 5: Parallel Updates with Git Worktrees

Why Worktrees?

Multiple agents cannot git switch on the same repo simultaneously. Worktrees provide isolated working directories sharing the same git history.

Setup Worktrees

For each selected package, create isolated worktree:

# From main repo (stays on master, untouched)
git worktree add /tmp/nixpkgs-<package>-<version> -b <package>-<version> master

Launch Parallel Agents

// Single message with N Task calls, each with its own worktree:
Task(subagent_type="general-purpose", run_in_background=true, prompt="Update pkg1 in /tmp/nixpkgs-pkg1-v1...")
Task(subagent_type="general-purpose", run_in_background=true, prompt="Update pkg2 in /tmp/nixpkgs-pkg2-v2...")

Update Agent Prompt Template

Update the nixpkgs package: <PACKAGE>
Current version: <OLD_VERSION>
Target version: <NEW_VERSION>

## Setup
Working directory: /tmp/nixpkgs-<PACKAGE>-<NEW_VERSION>
(Worktree already created, you are on branch <PACKAGE>-<NEW_VERSION>)

## IMPORTANT RULES
- **10 MINUTE TIMEOUT**: If any build step exceeds 10 minutes, ABORT and report failure
- **NEVER SKIP nixpkgs-review**: This step is MANDATORY, not optional
- Use `timeout 600` prefix for long-running commands

## Steps

1. **Verify worktree:**
   cd /tmp/nixpkgs-<PACKAGE>-<NEW_VERSION>
   git status  # Should show branch <PACKAGE>-<NEW_VERSION>

2. **Run nix-update (with timeout):**
   timeout 600 nix run nixpkgs#nix-update -- <PACKAGE>

   If timeout: ABORT, cleanup worktree, report "build timeout"

3. **Build and verify (with timeout):**
   timeout 600 nix build .#<PACKAGE>

   If timeout: ABORT, cleanup worktree, report "build timeout"
   If build fails: ABORT, cleanup worktree, report "build failed"

   ./result/bin/<BINARY> --version

4. **Test dependent packages (MANDATORY - DO NOT SKIP):**
   timeout 600 nix run nixpkgs#nixpkgs-review -- wip --print-result

   If timeout: ABORT, cleanup worktree, report "review timeout"
   This step is NOT optional. Never skip it.

5. **Commit:**
   git add -A
   git commit -m "$(cat <<'EOF'
<PACKAGE>: <OLD_VERSION> -> <NEW_VERSION>

https://github.com/<OWNER>/<REPO>/releases/tag/v<NEW_VERSION>
EOF
)"

6. **Push to fork:**
   git push --set-upstream fork <PACKAGE>-<NEW_VERSION>

7. **Create PR:**
   gh pr create --repo NixOS/nixpkgs \
     --title "<PACKAGE>: <OLD_VERSION> -> <NEW_VERSION>" \
     --body "$(cat <<'EOF'
## Description
Updates `<PACKAGE>` from <OLD_VERSION> to <NEW_VERSION>.

## Testing
- [x] Built locally
- [x] Ran nixpkgs-review wip

## Links
- Release: https://github.com/<OWNER>/<REPO>/releases/tag/v<NEW_VERSION>
EOF
)"

8. **Return:** PR URL or error message

## On Failure
If any step fails or times out:
1. Cleanup: git worktree remove /tmp/nixpkgs-<PACKAGE>-<NEW_VERSION> --force
2. Delete branch: git branch -D <PACKAGE>-<NEW_VERSION>
3. Report failure with reason

Cleanup Worktrees

After all agents complete, cleanup:

git worktree remove /tmp/nixpkgs-<package>-<version>
# Repeat for each worktree

Phase 6: Collect Results

Use AgentOutputTool to gather results:

AgentOutputTool(agentId="agent1")
AgentOutputTool(agentId="agent2")

Present summary:

## Update Results

| Package      | Version          | Status | PR     |
|--------------|------------------|--------|--------|
| some-rust    | 1.0.0 → 1.0.1    | ✅     | #12345 |
| some-go      | 0.5.0 → 0.5.1    | ⏱️     | timeout |

Cleanup worktrees after reporting.

Quick Reference

Platform Detection

# Get current system
nix eval --raw --impure --expr 'builtins.currentSystem'
# Returns: aarch64-darwin, x86_64-linux, aarch64-linux, x86_64-darwin

# Check package platforms
nix eval .#<pkg>.meta.platforms --json

# Common platform patterns in package.nix:
# lib.platforms.linux     → Linux only (skip on macOS)
# lib.platforms.darwin    → macOS only (skip on Linux)
# lib.platforms.unix      → Both Linux and macOS (OK)
# lib.platforms.all       → All platforms (OK)

Git Worktrees

# Create worktree with new branch
git worktree add /tmp/nixpkgs-<pkg>-<ver> -b <pkg>-<ver> master

# List worktrees
git worktree list

# Remove worktree
git worktree remove /tmp/nixpkgs-<pkg>-<ver>

# Force remove (if dirty)
git worktree remove /tmp/nixpkgs-<pkg>-<ver> --force

# Prune stale worktrees
git worktree prune

Timeout Commands

# 10 minute timeout for builds
timeout 600 nix build .#<pkg>

# Check exit code: 124 = timeout
if [ $? -eq 124 ]; then echo "TIMEOUT"; fi

Repology API

# Get outdated nixpkgs packages (User-Agent required!)
curl -s --user-agent "nixpkgs-update/1.0" \
  "https://repology.org/api/v1/projects/?inrepo=nix_unstable&outdated=1&count=50" | \
  jq -r 'keys[:20][]'

# Check specific package versions
curl -s --user-agent "nixpkgs-update/1.0" \
  "https://repology.org/api/v1/project/<name>" | \
  jq '{nixpkgs: ([.[] | select(.repo=="nix_unstable")][0].version), newest: ([.[] | select(.status=="newest")][0].version)}'

Nix Commands

# Update package (auto-updates hashes)
timeout 600 nix run nixpkgs#nix-update -- <pkg>

# Build package
timeout 600 nix build .#<pkg>

# Test dependent packages (MANDATORY)
timeout 600 nix run nixpkgs#nixpkgs-review -- wip --print-result

Commit Format

<pkg>: <old-version> -> <new-version>

Candidate Criteria Summary

CriteriaRequired Value
Locationpkgs/by-name/
TypeRust OR Go
has_patchesfalse
complexitysimple
Version bumppatch/minor only
PlatformMust support current system

If ANY criterion fails, discard the candidate. Never present options that can't be tested locally.

Failure Handling

FailureAction
Build timeout (>10m)Discard, cleanup, report
Build errorDiscard, cleanup, report
Review timeout (>10m)Discard, cleanup, report
Platform mismatchNever present to user