Commit 8b5dc56ab4be

Vincent Demeester <vincent@sbr.pm>
2025-12-04 21:57:08
feat: Enhance Nixpkgs skill with modern patterns and maintainer workflow
Add comprehensive enhancements based on 2024-2025 nixpkgs best practices: **New Maintainer.md workflow** (27 KB): - Complete guide for becoming a nixpkgs maintainer - Adding yourself to maintainer-list.nix with GitHub ID - Ofborg CI bot commands and usage (@ofborg build/test/eval) - Interpreting ofborg check results (eval, darwin, nixos) - Triaging issues (bug reports, version requests, security) - Reviewing and merging PRs with nixpkgs-merge-bot - Keeping packages updated (monitoring, r-ryantm bot) - Security update workflow with CVE references - Common maintainer scenarios and best practices - Maintainer responsibilities and permissions **Enhanced Review.md workflow**: - Added ofborg integration section - Automatic checks (ofborg-eval, check-maintainers, check-meta) - Triggering manual builds with @ofborg commands - Interpreting build results (green/red/orange status) - When to use ofborg build vs test commands - Integration with nixpkgs-review (uses ofborg eval results) - Added ofborg to resources **Enhanced AddPackage.md workflow**: - **finalAttrs pattern** (modern recommended approach): * Self-referencing in package definitions * Better override support with overrideAttrs * Avoids rec {} recursion issues * When to use vs when NOT to use (hash mismatch warning) - **Meta attributes without 'with lib'** (modern style) - **Common review feedback patterns** (10 examples): * "Use pkgs/by-name structure" * "Add yourself as maintainer" * "Set mainProgram" * "Use finalAttrs pattern" * "Format with nixfmt" * Commit message format corrections * Description improvements * License specification * Dependency optimization - **Real package examples** (6 complete examples): * Simple Go CLI tool * Rust application with system libraries (pkg-config, openssl, darwin) * C++ application with CMake * Python application with pyproject * Shell script wrapper with makeWrapper * Desktop GUI application with Qt6 and desktop entry - Additional resources: finalAttrs discussion, overriding guide **Updated Nixpkgs SKILL.md**: - Added Maintainer workflow to routing table - Complete workflow coverage for contribution lifecycle **Research and Sources**: - Studied finalAttrs pattern discussions (#293452, #315337, #310373) - Reviewed pkgs/by-name structure and conventions - Analyzed ofborg README and commands - Examined maintainer-list.nix format and validation - Researched nixpkgs-review integration with ofborg - Consulted nixpkgs stdenv documentation for modern patterns These enhancements bring the Nixpkgs skill up-to-date with current best practices as of late 2024/early 2025, covering the complete contribution lifecycle from adding packages through long-term maintenance. Sources: - https://github.com/NixOS/nixpkgs/issues/315337 - https://github.com/NixOS/nixpkgs/issues/293452 - https://github.com/NixOS/nixpkgs/blob/master/maintainers/README.md - https://github.com/NixOS/ofborg - https://nixos.wiki/wiki/OfBorg Co-Authored-By: Claude <noreply@anthropic.com> Signed-off-by: Vincent Demeester <vincent@sbr.pm>
1 parent 95f0085
Changed files (4)
dots
.config
dots/.config/claude/skills/Nixpkgs/workflows/AddPackage.md
@@ -88,7 +88,9 @@ pkgs/
 
 ## Package Template
 
-### Basic Package Structure
+### Basic Package Structure (Modern Pattern)
+
+**Using finalAttrs** (recommended for new packages):
 
 ```nix
 # pkgs/by-name/pa/package-name/package.nix
@@ -99,14 +101,14 @@ pkgs/
   # Add build dependencies here
 }:
 
-stdenv.mkDerivation rec {
+stdenv.mkDerivation (finalAttrs: {
   pname = "package-name";
   version = "1.0.0";
 
   src = fetchFromGitHub {
     owner = "owner";
     repo = "repo";
-    rev = "v${version}";
+    rev = "v${finalAttrs.version}";
     hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
   };
 
@@ -118,17 +120,37 @@ stdenv.mkDerivation rec {
     # Runtime dependencies (libraries)
   ];
 
-  meta = with lib; {
+  meta = {
     description = "Brief description of what this package does";
     homepage = "https://github.com/owner/repo";
-    license = licenses.mit;
-    maintainers = with maintainers; [ your-github-username ];
-    platforms = platforms.linux;
+    license = lib.licenses.mit;
+    maintainers = with lib.maintainers; [ your-github-username ];
+    platforms = lib.platforms.linux;
     mainProgram = "package-name";
   };
+})
+```
+
+**Traditional rec pattern** (still acceptable):
+
+```nix
+stdenv.mkDerivation rec {
+  pname = "package-name";
+  version = "1.0.0";
+
+  src = fetchFromGitHub {
+    owner = "owner";
+    repo = "repo";
+    rev = "v${version}";
+    hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
+  };
+
+  # ... rest of package
 }
 ```
 
+**Important**: When using `finalAttrs`, reference version/pname within src as `finalAttrs.version` and `finalAttrs.pname`. Avoid using `with lib;` in meta - use explicit `lib.licenses`, `lib.platforms` instead for better overriding support.
+
 ## Language-Specific Builders
 
 ### Go Package (buildGoModule)
@@ -458,6 +480,156 @@ Before submitting PR:
 - [ ] Commit message follows convention
 - [ ] Signed commit (`-s` flag)
 
+## Modern Nix Patterns
+
+### The finalAttrs Pattern
+
+The `finalAttrs` pattern provides self-referencing within package definitions:
+
+```nix
+stdenv.mkDerivation (finalAttrs: {
+  pname = "package";
+  version = "1.0.0";
+
+  # Can reference finalAttrs.version here
+  src = fetchurl {
+    url = "https://example.com/${finalAttrs.pname}-${finalAttrs.version}.tar.gz";
+    hash = "...";
+  };
+
+  # Can also reference in build phases
+  buildPhase = ''
+    echo "Building ${finalAttrs.pname} version ${finalAttrs.version}"
+  '';
+})
+```
+
+**Benefits**:
+- Better override support (`overrideAttrs` works correctly)
+- No need for `rec { }` (avoids recursion issues)
+- Clearer intent when self-referencing
+
+**When to use**:
+- Recommended for all new packages
+- Especially when referencing pname/version in src, phases, or scripts
+- Migration from `rec` is encouraged but not required
+
+**When NOT to use finalAttrs.pname/version in src hash**:
+```nix
+# DON'T DO THIS - hash won't change when overriding
+src = fetchurl {
+  url = "https://example.com/${finalAttrs.pname}-${finalAttrs.version}.tar.gz";
+  hash = "sha256-fixedhash...";  # This hash is for specific version!
+};
+```
+
+Overriding version will cause hash mismatch. Instead, users must override both version AND hash when needed.
+
+### Meta Attributes Without 'with lib'
+
+Modern style avoids `with lib;` in meta for better overriding:
+
+```nix
+# Modern (recommended)
+meta = {
+  description = "Package description";
+  license = lib.licenses.mit;
+  maintainers = with lib.maintainers; [ yourhandle ];
+  platforms = lib.platforms.linux;
+};
+
+# Old style (still works, but less preferred)
+meta = with lib; {
+  description = "Package description";
+  license = licenses.mit;
+  maintainers = with maintainers; [ yourhandle ];
+  platforms = platforms.linux;
+};
+```
+
+The `with lib.maintainers` is acceptable since it's a simple lookup list.
+
+## Common Review Feedback
+
+Expect reviewers to ask for these improvements:
+
+### 1. "Please use pkgs/by-name structure"
+```nix
+# Move from:
+pkgs/tools/networking/package-name/default.nix
+
+# To:
+pkgs/by-name/pa/package-name/package.nix
+```
+
+### 2. "Add yourself as maintainer"
+```nix
+meta = {
+  maintainers = with lib.maintainers; [ yourhandle ];
+};
+```
+
+### 3. "Set mainProgram"
+```nix
+meta = {
+  mainProgram = "binary-name";  # The primary executable
+};
+```
+
+### 4. "Use finalAttrs pattern"
+```nix
+# Change from:
+stdenv.mkDerivation rec {
+
+# To:
+stdenv.mkDerivation (finalAttrs: {
+```
+
+### 5. "Format with nixfmt"
+```bash
+nixfmt pkgs/by-name/pa/package-name/package.nix
+```
+
+### 6. "Fix commit message format"
+```bash
+# Should be:
+package-name: init at 1.0.0
+
+# Not:
+Add package-name
+Added new package package-name
+```
+
+### 7. "Add package description"
+```nix
+meta = {
+  description = "Brief, clear description of what this does";
+  # Not: "A package for..."
+  # Not: "package-name is a..."
+};
+```
+
+### 8. "Specify correct license"
+```nix
+# Check upstream LICENSE file
+meta = {
+  license = lib.licenses.mit;  # Match upstream exactly
+};
+```
+
+### 9. "Remove unnecessary dependencies"
+```nix
+# Only include dependencies actually used
+# Reviewers may ask: "Is pkg-config actually needed?"
+```
+
+### 10. "Use nativeBuildInputs for build tools"
+```nix
+# Move build tools from buildInputs
+nativeBuildInputs = [ cmake pkg-config ];
+buildInputs = [ openssl ];  # Only runtime deps
+```
+
 ## Common Issues
 
 ### Package Name
@@ -506,9 +678,336 @@ platforms.unix        # Linux + macOS
 platforms.all
 ```
 
+## Real Package Examples
+
+### Example 1: Simple CLI Tool (Go)
+
+A minimal Go CLI tool with no extra dependencies:
+
+```nix
+# pkgs/by-name/he/hello-go/package.nix
+{
+  lib,
+  buildGoModule,
+  fetchFromGitHub,
+}:
+
+buildGoModule rec {
+  pname = "hello-go";
+  version = "1.2.3";
+
+  src = fetchFromGitHub {
+    owner = "example";
+    repo = "hello-go";
+    rev = "v${version}";
+    hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
+  };
+
+  vendorHash = "sha256-BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=";
+
+  ldflags = [
+    "-s"
+    "-w"
+    "-X main.version=${version}"
+  ];
+
+  meta = {
+    description = "Simple hello world CLI tool";
+    homepage = "https://github.com/example/hello-go";
+    license = lib.licenses.mit;
+    maintainers = with lib.maintainers; [ yourhandle ];
+    mainProgram = "hello-go";
+  };
+}
+```
+
+### Example 2: Rust Application with Dependencies
+
+A Rust application that needs system libraries:
+
+```nix
+# pkgs/by-name/my/my-rust-app/package.nix
+{
+  lib,
+  rustPlatform,
+  fetchFromGitHub,
+  pkg-config,
+  openssl,
+  stdenv,
+  darwin,
+}:
+
+rustPlatform.buildRustPackage rec {
+  pname = "my-rust-app";
+  version = "2.1.0";
+
+  src = fetchFromGitHub {
+    owner = "example";
+    repo = "my-rust-app";
+    rev = "v${version}";
+    hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
+  };
+
+  cargoHash = "sha256-BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=";
+
+  nativeBuildInputs = [ pkg-config ];
+
+  buildInputs =
+    [ openssl ]
+    ++ lib.optionals stdenv.hostPlatform.isDarwin [
+      darwin.apple_sdk.frameworks.Security
+      darwin.apple_sdk.frameworks.SystemConfiguration
+    ];
+
+  meta = {
+    description = "Rust application for doing something useful";
+    homepage = "https://github.com/example/my-rust-app";
+    license = lib.licenses.asl20;
+    maintainers = with lib.maintainers; [ yourhandle ];
+    mainProgram = "my-rust-app";
+  };
+}
+```
+
+### Example 3: C/C++ Application with CMake
+
+Traditional C++ application using CMake build system:
+
+```nix
+# pkgs/by-name/my/myapp/package.nix
+{
+  lib,
+  stdenv,
+  fetchFromGitHub,
+  cmake,
+  pkg-config,
+  zlib,
+  libpng,
+  boost,
+}:
+
+stdenv.mkDerivation (finalAttrs: {
+  pname = "myapp";
+  version = "3.0.1";
+
+  src = fetchFromGitHub {
+    owner = "example";
+    repo = "myapp";
+    rev = "v${finalAttrs.version}";
+    hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
+  };
+
+  nativeBuildInputs = [
+    cmake
+    pkg-config
+  ];
+
+  buildInputs = [
+    zlib
+    libpng
+    boost
+  ];
+
+  cmakeFlags = [
+    "-DENABLE_TESTS=OFF"
+    "-DBUILD_SHARED_LIBS=ON"
+  ];
+
+  meta = {
+    description = "C++ application for processing images";
+    homepage = "https://github.com/example/myapp";
+    license = lib.licenses.gpl3Only;
+    maintainers = with lib.maintainers; [ yourhandle ];
+    platforms = lib.platforms.unix;
+    mainProgram = "myapp";
+  };
+})
+```
+
+### Example 4: Python Application
+
+Python CLI tool installed as application (not library):
+
+```nix
+# pkgs/by-name/py/pytool/package.nix
+{
+  lib,
+  python3Packages,
+  fetchFromGitHub,
+}:
+
+python3Packages.buildPythonApplication rec {
+  pname = "pytool";
+  version = "1.5.0";
+  pyproject = true;
+
+  src = fetchFromGitHub {
+    owner = "example";
+    repo = "pytool";
+    rev = "v${version}";
+    hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
+  };
+
+  build-system = with python3Packages; [
+    setuptools
+    wheel
+  ];
+
+  dependencies = with python3Packages; [
+    click
+    requests
+    pyyaml
+  ];
+
+  nativeCheckInputs = with python3Packages; [
+    pytestCheckHook
+  ];
+
+  pythonImportsCheck = [ "pytool" ];
+
+  meta = {
+    description = "Python tool for data processing";
+    homepage = "https://github.com/example/pytool";
+    license = lib.licenses.mit;
+    maintainers = with lib.maintainers; [ yourhandle ];
+    mainProgram = "pytool";
+  };
+}
+```
+
+### Example 5: Application with Wrapper
+
+Application that needs runtime dependencies in PATH:
+
+```nix
+# pkgs/by-name/my/myshell/package.nix
+{
+  lib,
+  stdenv,
+  fetchFromGitHub,
+  makeWrapper,
+  bash,
+  git,
+  curl,
+  jq,
+}:
+
+stdenv.mkDerivation (finalAttrs: {
+  pname = "myshell";
+  version = "0.5.0";
+
+  src = fetchFromGitHub {
+    owner = "example";
+    repo = "myshell";
+    rev = "v${finalAttrs.version}";
+    hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
+  };
+
+  nativeBuildInputs = [ makeWrapper ];
+
+  installPhase = ''
+    runHook preInstall
+
+    mkdir -p $out/bin
+    cp myshell.sh $out/bin/myshell
+    chmod +x $out/bin/myshell
+
+    # Wrap to add runtime dependencies to PATH
+    wrapProgram $out/bin/myshell \
+      --prefix PATH : ${
+        lib.makeBinPath [
+          bash
+          git
+          curl
+          jq
+        ]
+      }
+
+    runHook postInstall
+  '';
+
+  meta = {
+    description = "Shell script wrapper for git operations";
+    homepage = "https://github.com/example/myshell";
+    license = lib.licenses.mit;
+    maintainers = with lib.maintainers; [ yourhandle ];
+    mainProgram = "myshell";
+  };
+})
+```
+
+### Example 6: Desktop Application
+
+GUI application with desktop entry:
+
+```nix
+# pkgs/by-name/my/myapp-gui/package.nix
+{
+  lib,
+  stdenv,
+  fetchFromGitHub,
+  cmake,
+  pkg-config,
+  qt6,
+  wrapQtAppsHook,
+  makeDesktopItem,
+  copyDesktopItems,
+}:
+
+stdenv.mkDerivation (finalAttrs: {
+  pname = "myapp-gui";
+  version = "2.0.0";
+
+  src = fetchFromGitHub {
+    owner = "example";
+    repo = "myapp-gui";
+    rev = "v${finalAttrs.version}";
+    hash = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
+  };
+
+  nativeBuildInputs = [
+    cmake
+    pkg-config
+    wrapQtAppsHook
+    copyDesktopItems
+  ];
+
+  buildInputs = [
+    qt6.qtbase
+    qt6.qtsvg
+  ];
+
+  desktopItems = [
+    (makeDesktopItem {
+      name = "myapp-gui";
+      exec = "myapp-gui";
+      icon = "myapp-gui";
+      desktopName = "MyApp GUI";
+      comment = "GUI application for MyApp";
+      categories = [ "Utility" ];
+    })
+  ];
+
+  postInstall = ''
+    install -Dm644 resources/icon.png $out/share/icons/hicolor/256x256/apps/myapp-gui.png
+  '';
+
+  meta = {
+    description = "Graphical user interface for MyApp";
+    homepage = "https://github.com/example/myapp-gui";
+    license = lib.licenses.gpl3Plus;
+    maintainers = with lib.maintainers; [ yourhandle ];
+    platforms = lib.platforms.linux;
+    mainProgram = "myapp-gui";
+  };
+})
+```
+
 ## Resources
 
 - [Nixpkgs Manual - Quick Start](https://nixos.org/manual/nixpkgs/stable/#chap-quick-start)
 - [pkgs/by-name README](https://github.com/NixOS/nixpkgs/blob/master/pkgs/by-name/README.md)
 - [Package Naming](https://nixos.org/manual/nixpkgs/stable/#sec-package-naming)
 - [Contributing to Nixpkgs](https://github.com/NixOS/nixpkgs/blob/master/CONTRIBUTING.md)
+- [Nixpkgs finalAttrs Discussion](https://github.com/NixOS/nixpkgs/issues/315337)
+- [Nixpkgs Overriding Guide](https://nixos.org/manual/nixpkgs/stable/#chap-overrides)
dots/.config/claude/skills/Nixpkgs/workflows/Maintainer.md
@@ -0,0 +1,665 @@
+# Maintainer Workflow
+
+Package maintenance in NixOS/nixpkgs: triaging issues, reviewing PRs, and keeping packages updated.
+
+## When to Use
+
+- "nixpkgs maintainer"
+- "package maintenance"
+- "triage issues"
+- "maintainer responsibilities"
+
+## Quick Reference
+
+### Becoming a Maintainer
+
+```bash
+# 1. Add yourself to maintainer-list.nix
+vim maintainers/maintainer-list.nix
+
+# 2. Add entry (alphabetically sorted)
+yourhandle = {
+  name = "Your Name";
+  github = "YourGitHubUsername";
+  githubId = 123456;
+};
+
+# 3. Test the format
+nix-build lib/tests/maintainers.nix
+
+# 4. Add yourself to package
+vim pkgs/by-name/pa/package-name/package.nix
+# In meta.maintainers: [ maintainers.yourhandle ]
+
+# 5. Create PR
+git commit -s -m "maintainers: add yourhandle"
+```
+
+### Ofborg Commands
+
+```bash
+# Build specific packages
+@ofborg build package-name
+
+# Run NixOS tests
+@ofborg test test-name
+
+# Re-evaluate (if evaluation failed)
+@ofborg eval
+
+# Multiple commands
+@ofborg build hello @ofborg test nginx
+```
+
+## Maintainer Responsibilities
+
+### Primary Role
+
+**Main responsibility**: Keep packages in a functioning state and keep up with updates.
+
+Maintainers have decision-making power over their packages but are not the sole contributors. Anyone can propose changes, including bots and other contributors.
+
+### Key Duties
+
+1. **Monitor Updates** - Watch for new upstream releases
+2. **Review PRs** - Review and merge changes to maintained packages
+3. **Triage Issues** - Address bugs and feature requests
+4. **Keep Packages Working** - Fix breakages and test failures
+5. **Respond to Mentions** - Reply to @-mentions within reasonable time
+6. **Security Updates** - Prioritize CVE fixes and security patches
+
+## Becoming a Maintainer
+
+### Step 1: Add Yourself to maintainer-list.nix
+
+```nix
+# maintainers/maintainer-list.nix
+{
+  # ...
+  yourhandle = {
+    # Required
+    name = "Your Full Name";
+    github = "YourGitHubUsername";
+    githubId = 123456;  # Get from https://api.github.com/users/YourGitHubUsername
+
+    # Optional
+    email = "you@example.com";
+    matrix = "@you:matrix.org";
+    keys = [{
+      fingerprint = "AAAA BBBB CCCC DDDD EEEE  FFFF 0000 1111 2222 3333";
+    }];
+  };
+}
+```
+
+**Finding your GitHub ID**:
+```bash
+# Using API
+curl https://api.github.com/users/YourGitHubUsername | jq .id
+
+# Or use gh CLI
+gh api /users/YourGitHubUsername --jq .id
+```
+
+**Handle naming**:
+- Use lowercase
+- If GitHub username starts with number, prefix with underscore
+- Keep it simple and related to your GitHub username
+
+### Step 2: Test Format
+
+```bash
+# Ensure maintainer-list.nix is valid
+nix-build lib/tests/maintainers.nix
+
+# Should complete without errors
+```
+
+### Step 3: Add to Package
+
+```nix
+# In package definition
+meta = with lib; {
+  # ...
+  maintainers = with maintainers; [ yourhandle ];
+};
+```
+
+### Step 4: Submit PR
+
+```bash
+git add maintainers/maintainer-list.nix
+git commit -s -m "maintainers: add yourhandle"
+git push
+gh pr create --title "maintainers: add yourhandle" --body "Adding myself as a maintainer for package-name"
+```
+
+### What Happens Next
+
+After PR is merged:
+- Invited to @NixOS/nixpkgs-maintainers GitHub team
+- Eligible for package review requests
+- Part of CI review process
+- Can use nixpkgs-merge-bot for your packages
+
+## Using Ofborg
+
+Ofborg is the CI bot that automatically builds and tests packages.
+
+### Automatic Checks
+
+Ofborg automatically runs these checks on every PR:
+
+1. **ofborg-eval**: Validates Nix expression syntax
+2. **ofborg-eval-check-maintainers**: Verifies maintainers exist
+3. **ofborg-eval-check-meta**: Ensures meta attributes present
+4. **ofborg-eval-darwin**: Checks macOS builds
+5. **ofborg-eval-nixos**: Checks NixOS builds
+
+### Manual Commands
+
+Trigger ofborg in PR comments:
+
+#### Build Packages
+
+```bash
+# Build single package
+@ofborg build package-name
+
+# Build multiple packages
+@ofborg build package1 package2 package3
+
+# Build with attribute path
+@ofborg build pythonPackages.requests
+
+# Ofborg will run:
+# nix-build ./default.nix -A package-name
+```
+
+#### Run Tests
+
+```bash
+# Run specific test
+@ofborg test nginx
+
+# Run multiple tests
+@ofborg test nginx apache
+
+# Ofborg will run:
+# nix-build ./default.nix -A nixosTests.nginx
+```
+
+#### Re-evaluate
+
+```bash
+# Force re-evaluation (only if eval failed)
+@ofborg eval
+```
+
+#### Multiple Commands
+
+```bash
+# Combine commands
+@ofborg build hello @ofborg test hello
+
+# Or on separate lines
+@ofborg build firefox
+@ofborg test firefox
+```
+
+### Interpreting Ofborg Results
+
+**Green checkmarks (✓)**:
+- Package built successfully
+- Tests passed
+- Evaluation succeeded
+
+**Red X (✗)**:
+- Build failed
+- Tests failed
+- Evaluation error
+
+**Orange dot**:
+- Skipped (marked as broken, unsupported platform)
+- Not evaluated yet
+
+Click "Details" to see:
+- Build logs
+- Error messages
+- Evaluation output
+
+### When to Use Ofborg Commands
+
+**Use `@ofborg build`**:
+- After fixing build failure
+- To test on platforms you don't have access to
+- To verify changes to dependencies
+
+**Use `@ofborg test`**:
+- After changing NixOS modules
+- To verify service configurations
+- After updating packages that tests depend on
+
+**Use `@ofborg eval`**:
+- Only when evaluation check fails
+- After fixing syntax errors
+- Usually not needed (auto-runs on every push)
+
+## Triaging Issues
+
+### Issue Categories
+
+1. **Bug Reports** - Package broken or malfunctioning
+2. **Version Requests** - Request to update to newer version
+3. **Feature Requests** - New functionality or options
+4. **Security** - CVE reports or vulnerabilities
+5. **Documentation** - Unclear or missing docs
+
+### Triage Process
+
+#### 1. Verify the Issue
+
+```bash
+# Try to reproduce
+nix-build -A package-name
+
+# Check if already fixed
+git log --oneline -- pkgs/path/to/package/
+
+# Search for duplicate issues
+# Use GitHub search: is:issue is:open package-name
+```
+
+#### 2. Label the Issue
+
+Common labels:
+- `0.kind: bug` - Something is broken
+- `0.kind: enhancement` - Feature request
+- `2.status: stale` - No activity for extended period
+- `3.severity: security` - Security vulnerability
+- `6.topic: *` - Topic-specific (python, darwin, etc.)
+- `10.rebuild-*` - Impact on rebuilds
+
+#### 3. Respond
+
+**For valid bugs**:
+```markdown
+Thank you for the report. I can confirm this is a bug.
+
+The issue is caused by [explanation].
+
+I'll work on a fix. In the meantime, you can work around this by [workaround].
+```
+
+**For version requests**:
+```markdown
+Thanks for the request. I'll update this package to the latest version.
+
+In the meantime, you can use the unstable channel or override the package:
+
+\`\`\`nix
+package-name.overrideAttrs (old: {
+  version = "newversion";
+  src = fetchurl {
+    url = "...";
+    hash = "...";
+  };
+})
+\`\`\`
+```
+
+**For duplicates**:
+```markdown
+This is a duplicate of #12345. Please follow that issue for updates.
+```
+
+**For security issues**:
+```markdown
+Thank you for the security report. I'll prioritize fixing this.
+
+Related CVE: CVE-2024-XXXXX
+
+Tracking this with urgency.
+```
+
+#### 4. Take Action
+
+- **Fix bugs**: Create PR with fix
+- **Update versions**: Use nix-update and create PR
+- **Close invalid**: Close with explanation
+- **Request info**: Ask for more details if unclear
+
+### Issue Best Practices
+
+1. **Respond promptly** - Within a few days if possible
+2. **Be respectful** - Kind even when closing invalid issues
+3. **Provide context** - Explain why closing or deferring
+4. **Link related work** - Reference related issues/PRs
+5. **Use labels** - Help others find and categorize
+6. **Request help** - Mention other maintainers if needed
+
+## Reviewing Pull Requests
+
+### PR Review Checklist
+
+As a maintainer, review PRs touching your packages:
+
+- [ ] **Builds successfully** - Check ofborg results
+- [ ] **Tests pass** - All relevant tests green
+- [ ] **Code quality** - Follows nixpkgs conventions
+- [ ] **Commit message** - Clear and follows format
+- [ ] **No regressions** - Doesn't break dependent packages
+- [ ] **Documentation** - Updated if needed
+- [ ] **Breaking changes** - Documented if applicable
+
+### Review Comments
+
+**Request changes**:
+```markdown
+Thanks for the PR! A few comments:
+
+1. The commit message should follow the format: `package-name: 1.0 -> 2.0`
+2. Please add yourself to `meta.maintainers`
+3. The build is failing on darwin - see ofborg results
+
+Could you address these? Thanks!
+```
+
+**Approve**:
+```markdown
+LGTM! Thank you for the contribution.
+
+Builds successfully on x86_64-linux and tests pass.
+```
+
+**Request ofborg builds**:
+```markdown
+Looks good. Let's test on more platforms:
+
+@ofborg build package-name
+```
+
+### Merging PRs
+
+#### Using nixpkgs-merge-bot
+
+For packages you maintain:
+
+```markdown
+@nixpkgs-merge-bot merge
+```
+
+Requirements:
+- You're listed in meta.maintainers
+- All required checks pass
+- PR meets security constraints
+
+#### Manual Merge
+
+If merge-bot unavailable:
+
+1. Ensure all checks pass
+2. Click "Squash and merge" or "Rebase and merge"
+3. Edit commit message if needed
+4. Confirm merge
+
+### Merge Conflicts
+
+**Simple approach**: Ask contributor to rebase
+
+```markdown
+Could you please rebase on latest master? There are conflicts in the package definition.
+
+\`\`\`bash
+git fetch upstream
+git rebase upstream/master
+git push --force-with-lease
+\`\`\`
+```
+
+**Complex conflicts**: Offer to help or take over
+
+```markdown
+These conflicts are complex. I can take over the PR if you'd like, or I can help resolve them. Let me know your preference!
+```
+
+## Keeping Packages Updated
+
+### Monitoring Updates
+
+#### Manual Checks
+
+```bash
+# Check latest release on GitHub
+gh release list -R owner/repo
+
+# Check package repository
+curl -s https://api.github.com/repos/owner/repo/releases/latest | jq .tag_name
+```
+
+#### Automated Tools
+
+**repology.org**: Tracks package versions across distros
+- Visit https://repology.org/project/package-name/versions
+- See if nixpkgs is behind
+
+**GitHub watch**: Enable notifications for releases
+- Go to package repository
+- Click "Watch" → "Custom" → "Releases"
+
+#### r-ryantm bot
+
+Many packages are automatically updated by r-ryantm bot:
+- Creates PRs for version bumps
+- Updates hashes automatically
+- Runs basic builds
+- Maintainers just need to review and merge
+
+### Update Workflow
+
+```bash
+# 1. Create update branch
+git checkout -b update/package-name
+
+# 2. Update with nix-update
+nix-update --build --commit package-name
+
+# 3. Test thoroughly
+nix-build -A package-name
+./result/bin/package-name --version
+
+# 4. Review with nixpkgs-review
+nixpkgs-review wip
+
+# 5. Push and create PR
+git push -u origin update/package-name
+gh pr create --title "package-name: 1.0.0 -> 1.1.0"
+```
+
+### Handling Security Updates
+
+**Priority**: Security updates should be handled urgently
+
+```bash
+# 1. Update immediately
+nix-update --version=1.0.1 package-name
+
+# 2. Build and test
+nix-build -A package-name
+nixpkgs-review wip
+
+# 3. Commit with CVE reference
+git commit -s -m "package-name: 1.0.0 -> 1.0.1 (security)
+
+Fixes CVE-2024-XXXXX: Description of vulnerability
+
+Security advisory: https://..."
+
+# 4. Create PR with security label
+gh pr create --label "3.severity: security"
+
+# 5. Consider backporting to stable
+# Mention in PR description if should be backported
+```
+
+## Common Maintainer Scenarios
+
+### Scenario 1: Package Breaks After Update
+
+```bash
+# Someone else updated a dependency, your package breaks
+
+# 1. Investigate
+nix-build -A your-package --keep-failed
+# Check error logs
+
+# 2. Fix
+# Option A: Update your package
+nix-update --build your-package
+
+# Option B: Add patch
+vim pkgs/.../fix-new-dependency.patch
+
+# Option C: Pin dependency temporarily
+buildInputs = [ (dependency.overrideAttrs ...) ];
+
+# 3. Create PR
+git commit -s -m "your-package: fix build after dependency update"
+```
+
+### Scenario 2: User Reports Bug
+
+```bash
+# 1. Reproduce
+nix-build -A package-name
+./result/bin/package-name  # Try to trigger bug
+
+# 2. Fix locally
+vim pkgs/by-name/pa/package-name/package.nix
+nix-build -A package-name
+# Verify fix
+
+# 3. Create PR
+git commit -s -m "package-name: fix bug-description
+
+Fixes #12345"
+
+# 4. Comment on issue
+# "Fixed in #12346. Will be in unstable soon."
+```
+
+### Scenario 3: Inactive Co-Maintainer
+
+If co-maintainer doesn't respond for 3+ months:
+
+```markdown
+# In PR description
+@inactive-maintainer hasn't responded to mentions in 3 months.
+
+Per maintainer guidelines, proceeding with this change.
+
+Removing from maintainers list as they appear inactive.
+```
+
+### Scenario 4: Breaking Change Needed
+
+```markdown
+# Create discussion issue first
+**Title**: Proposal: Breaking change to package-name
+
+## Motivation
+[Why this change is needed]
+
+## Breaking Changes
+- Configuration format change
+- API changes
+- Migration path
+
+## Timeline
+Proposing for next release cycle.
+
+## Migration Guide
+[How users should update]
+
+---
+
+Tagging co-maintainers: @user1 @user2
+```
+
+## Maintainer Best Practices
+
+1. **Respond timely** - Aim for response within a week
+2. **Be kind** - Remember contributors are volunteers
+3. **Document decisions** - Explain why in issues/PRs
+4. **Test thoroughly** - Don't merge broken packages
+5. **Welcome contributors** - Encourage and guide new contributors
+6. **Ask for help** - Mention other maintainers when stuck
+7. **Keep updated** - Regular version bumps prevent drift
+8. **Security first** - Prioritize CVE fixes
+9. **Communicate** - Update issues when working on fixes
+10. **Share knowledge** - Help onboard new maintainers
+
+## Maintainer Permissions
+
+### What Maintainers Can Do
+
+- Merge PRs for packages they maintain
+- Use @nixpkgs-merge-bot for their packages
+- Close/reopen issues for their packages
+- Label issues related to their packages
+- Make decisions about package direction
+- Revert changes that break their packages
+
+### What Maintainers Cannot Do
+
+- Merge PRs for packages they don't maintain (without approval)
+- Force merge without passing checks
+- Ignore committer/community feedback
+- Make changes that break other packages without fixing them
+
+### Conflicts and Resolution
+
+If disagreement with another maintainer:
+1. Discuss in the issue/PR
+2. Seek input from other maintainers
+3. Bring to #nixpkgs-dev if needed
+4. Maintainer of affected package has priority
+
+## Stepping Down
+
+If you can't maintain a package anymore:
+
+```bash
+# Remove yourself from maintainers list
+vim pkgs/by-name/pa/package-name/package.nix
+
+# In meta.maintainers, remove your handle
+
+git commit -s -m "package-name: remove myself as maintainer
+
+No longer have time to maintain this package.
+Looking for new maintainer."
+```
+
+Optional: Create issue seeking new maintainer
+
+```markdown
+**Title**: Looking for new maintainer: package-name
+
+I'm stepping down as maintainer of package-name due to time constraints.
+
+Looking for someone interested in maintaining this package. Responsibilities include:
+- Keeping up with updates
+- Reviewing PRs
+- Fixing bugs
+
+Please comment if interested!
+```
+
+## Resources
+
+- [Maintainer README](https://github.com/NixOS/nixpkgs/blob/master/maintainers/README.md)
+- [Maintainer List](https://github.com/NixOS/nixpkgs/blob/master/maintainers/maintainer-list.nix)
+- [Ofborg Documentation](https://github.com/NixOS/ofborg)
+- [nixpkgs-merge-bot](https://github.com/NixOS/nixpkgs-merge-bot)
+- [Reviewing Contributions](https://ryantm.github.io/nixpkgs/contributing/reviewing-contributions/)
dots/.config/claude/skills/Nixpkgs/workflows/Review.md
@@ -35,6 +35,18 @@ nixpkgs-review wip --staged
 nixpkgs-review rev HEAD
 ```
 
+### Ofborg Commands
+```bash
+# Trigger builds on PR (comment on GitHub)
+@ofborg build package-name
+
+# Run NixOS tests
+@ofborg test test-name
+
+# Re-evaluate (only if eval failed)
+@ofborg eval
+```
+
 ## Setup
 
 ### Install nixpkgs-review
@@ -394,8 +406,76 @@ done
 parallel nixpkgs-review pr {} --no-shell --post-result ::: 12345 12346 12347
 ```
 
+## Using Ofborg
+
+Ofborg is the nixpkgs CI bot that automatically builds and tests packages.
+
+### Automatic Checks
+
+Ofborg runs automatically on every PR:
+- **ofborg-eval**: Validates Nix expressions
+- **ofborg-eval-check-maintainers**: Verifies maintainers exist
+- **ofborg-eval-check-meta**: Ensures meta attributes present
+- **ofborg-eval-darwin**: Checks macOS builds
+- **ofborg-eval-nixos**: Checks NixOS builds
+
+Check ofborg results in the PR "Checks" tab.
+
+### Triggering Manual Builds
+
+Comment on the PR to trigger ofborg:
+
+```bash
+# Build specific package
+@ofborg build package-name
+
+# Build multiple packages
+@ofborg build package1 package2
+
+# Run NixOS tests
+@ofborg test nginx
+
+# Re-evaluate (only if eval failed)
+@ofborg eval
+
+# Multiple commands
+@ofborg build firefox @ofborg test firefox
+```
+
+### Interpreting Results
+
+**Green checkmark (✓)**: Build succeeded
+**Red X (✗)**: Build failed - click "Details" for logs
+**Orange dot**: Skipped (broken/unsupported platform)
+
+### When to Use Ofborg
+
+Use `@ofborg build`:
+- Test on platforms you don't have (aarch64, darwin)
+- Verify complex dependency changes
+- After fixing build failures
+
+Use `@ofborg test`:
+- After changing NixOS modules
+- Verify service configurations
+- After updating packages that tests depend on
+
+### Integration with nixpkgs-review
+
+nixpkgs-review automatically uses ofborg evaluation results:
+```bash
+# Uses ofborg's evaluation if available
+nixpkgs-review pr 12345
+
+# Force local evaluation
+nixpkgs-review pr 12345 --eval local
+```
+
+This saves time by reusing ofborg's work on determining changed packages.
+
 ## Resources
 
 - [nixpkgs-review](https://github.com/Mic92/nixpkgs-review)
+- [Ofborg](https://github.com/NixOS/ofborg)
 - [Reviewing Contributions](https://ryantm.github.io/nixpkgs/contributing/reviewing-contributions/)
 - [Nixpkgs Manual - Contributing](https://nixos.org/manual/nixpkgs/stable/#chap-contributing)
dots/.config/claude/skills/Nixpkgs/SKILL.md
@@ -25,6 +25,7 @@ When the user's request matches specific nixpkgs operations, route to the approp
 | **Add Package** | "add package", "new package", "init package", "create package" | `workflows/AddPackage.md` |
 | **Update Package** | "update package", "bump version", "upgrade package", "nix-update" | `workflows/UpdatePackage.md` |
 | **Fix Package** | "fix package", "broken package", "build failing", "package doesn't work" | `workflows/FixPackage.md` |
+| **Maintainer** | "maintainer", "triage issues", "package maintenance", "become maintainer" | `workflows/Maintainer.md` |
 
 **When to use workflows:**
 - Route when the user explicitly asks about one of these operations