Files
millerson-overlay.nix/AGENTS.md
Alexander Miroshnichenko c68a821a00 fix: improve package quality and fix goose-cli build
- Add meta.platforms to all packages for proper platform detection
- Add passthru.category to mcp-gateway for consistency
- Fix meta style inconsistency in mcp-gateway (lib.licenses → licenses)
- Fix pythonImportsCheck in skillsmcp to actually validate the import
- Remove empty maintainers list from skillsmcp
- Add libclang to goose-cli nativeBuildInputs (fixes bindgen/llama-cpp-sys-2 build)
- Add treefmt.toml with nixfmt formatter configuration
- Add nixConfig.extra-substituters for binary cache support
- Delete broken goose-cli/update.py (referenced missing scripts/updater.py)
- Document nix-update usage in AGENTS.md for package updates
- Fix stale project structure diagram in README
2026-05-06 12:54:26 +03:00

9.3 KiB

AGENTS.md - Instructions for AI Agents

This file provides guidance to AI agents (such as Claude, GPT, Goose, etc.) when working with this Nix overlay repository.

Project Overview

This is a Nix flake overlay repository that provides additional packages for Nix/NixOS users. It uses numtide/blueprint as its foundation, which simplifies flake development by providing sensible defaults and automatic package discovery.

Repository URL: git+https://git.millerson.name/alex/millerson-overlay.nix.git

Key Concepts

  1. Don't assume. Don't hide confusion. Surface tradeoffs.
  2. Minimum code that solves the problem. Nothing speculative.
  3. Touch only what you must. Clean up only your own mess.
  4. Define success criteria. Loop until verified.

Blueprint Framework

This project uses numtide/blueprint which:

  • Automatically discovers packages in the packages/ directory
  • Provides perSystem outputs for multi-system builds
  • Handles formatting, checking, and devShell generation
  • Exposes mkPackagesFor function to build packages against any nixpkgs instance

Two Overlay Strategies

  1. overlays.default - Binary-cache-friendly

    • Uses packages built against this flake's nixpkgs revision
    • Better for binary cache hits when using the same nixpkgs
  2. overlays.shared-nixpkgs - Dependency-sharing

    • Builds packages against the consumer's nixpkgs (final)
    • Shares dependencies with the rest of the system
    • No second nixpkgs evaluation
    • Trade-off: binary cache only hits when consumer's nixpkgs matches ours

Repository Structure

nix-overlay/
├── flake.nix                    # Main flake definition with inputs and outputs
├── overlays/
│   ├── default.nix             # Overlay using pre-built packages (binary cache friendly)
│   └── shared-nixpkgs.nix      # Overlay building against consumer's nixpkgs
├── packages/
│   ├── default/                # Meta-package listing all visible packages
│   │   ├── default.nix
│   │   └── package.nix
│   ├── goose-cli/              # Example package: Goose AI agent CLI
│   │   ├── default.nix
│   │   ├── package.nix         # Main package definition
│   │   ├── fetchers.nix        # Custom fetchers (if needed)
│   │   ├── librusty_v8.nix     # V8 library pre-built binary
│   │   └── update.py           # Update script for version bumps
│   └── flake-inputs/           # Utility to cache all flake inputs
│       └── default.nix
├── README.md                   # User-facing documentation
├── AGENTS.md                   # This file - AI agent instructions
├── LICENSE
└── flake.lock

Package Definition Pattern

Standard Package Structure

Each package should follow this structure:

packages/<package-name>/
├── default.nix    # Wrapper that receives blueprint args (pkgs, perSystem, etc.)
└── package.nix    # Actual package definition using pkgs.callPackage pattern

default.nix Pattern

{
  pkgs,
  perSystem,
  ...
}:
pkgs.callPackage ./package.nix {
  # Pass any extra arguments here
}

package.nix Pattern

{
  lib,
  stdenv,
  # ... package-specific dependencies
}:

stdenv.mkDerivation rec {
  pname = "my-package";
  version = "1.0.0";

  src = fetchFromGitHub {
    owner = "user";
    repo = "repo";
    rev = "v${version}";
    hash = "sha256-...";
  };

  # ... build instructions

  meta = with lib; {
    description = "Brief description";
    homepage = "https://...";
    license = licenses.mit;
    maintainers = with maintainers; [ ];
    platforms = platforms.all;
    mainProgram = "program-name";
  };
}

Rust Packages

For Rust packages, use rustPlatform.buildRustPackage:

{
  lib,
  rustPlatform,
  fetchFromGitHub,
  ...
}:

rustPlatform.buildRustPackage rec {
  pname = "my-rust-app";
  version = "1.0.0";

  src = fetchFromGitHub { ... };
  
  cargoHash = "sha256-...";

  # ... build instructions

  meta = { ... };
}

Adding a New Package

When adding a new package:

  1. Create the directory: mkdir -p packages/<package-name>

  2. Create package.nix with the actual derivation

  3. Create default.nix as a wrapper:

    { pkgs, ... }:
    pkgs.callPackage ./package.nix { }
    
  4. Test the package:

    nix build .#<package-name>
    nix run .#<package-name>
    
  5. Update README.md to document the new package in the Available Packages table

  6. Set appropriate metadata:

    • meta.description - Required, shown in package listings
    • meta.mainProgram - Set for packages providing a CLI executable
    • meta.passthru.category - Optional, used for organization (e.g., "AI Coding Agents")
    • meta.passthru.hideFromDocs - Set to true to exclude from documentation

Common Tasks

Updating a Package Version

  1. Update version in package.nix
  2. Update src.hash (use nix-prefetch-github or let Nix tell you the correct hash)
  3. Update cargoHash for Rust packages (build will fail and tell you the correct hash)
  4. Test: nix build .#<package-name>
  5. Update README if needed

Testing Changes

# Build specific package
nix build .#goose-cli

# Build all packages for current system
nix build .#packages

# Enter dev shell
nix develop

# Check formatting
nix flake check

Working with Overlays

When modifying overlay behavior:

  • overlays/default.nix: Receives packages from blueprint outputs, maps them to final.stdenv.hostPlatform.system
  • overlays/shared-nixpkgs.nix: Receives mkPackagesFor, uses it to build against consumer's final

Important Notes

Do's

  • Use pkgs.callPackage pattern for package definitions
  • Set proper meta attributes (description, license, homepage)
  • Test packages with nix build before committing
  • Use passthru.category for organizational grouping
  • Follow Nixpkgs conventions for package naming and structure

Don'ts

  • Don't modify flake.lock manually - use nix flake update
  • Don't hardcode system-specific paths or assumptions
  • Don't forget to set meta.mainProgram for CLI tools
  • Don't use with pkgs; at top level (can cause scope issues)
  • Don't commit packages that don't build

Debugging Tips

Package Doesn't Build

  1. Check the error message carefully
  2. Verify all dependencies are listed
  3. Check if the source hash is correct
  4. For Rust packages, verify cargoHash matches

Overlay Not Working

  1. Verify the overlay is correctly imported
  2. Check if the package exists in packages output
  3. For shared-nixpkgs, ensure mkPackagesFor is available

Binary Cache Issues

  • The default overlay is more likely to get cache hits
  • The shared-nixpkgs overlay builds from source unless nixpkgs revisions match

Resources

Updating Packages

Use nix-update to bump versions and update hashes:

# Update a package to the latest version
nix-update <package-name>

# Update to a specific version
nix-update <package-name> --version <version>

# Update a package pinned to a commit hash (e.g. skillsmcp)
nix-update <package-name> --version=branch=main

After updating, always test the build:

nix build .#<package-name>

Package-Specific Notes

  • goose-cli: Also updates librusty_v8 hashes automatically via the custom fetcher
  • mcp-gateway: Standard Rust package, nix-update handles version + cargoHash
  • skillsmcp: Pinned to a commit hash; use --version=branch=main or specify the target commit with --commit

Git Workflow

Committing Completed Work

Every completed job or feature must be committed to the git repository.

When preparing git commits, always use the conventional-commit skill to create proper commit messages following conventional commit conventions.

This ensures:

  • Clean git history with proper commit message formatting
  • No work is left uncommitted
  • Consistent commit message style across the project

Advanced Git Operations

For advanced Git workflows (rebasing, cherry-picking, bisect, worktrees, reflog, history recovery), use the git-advanced-workflows skill.

This skill provides:

  • Master advanced Git workflows including rebasing, cherry-picking, bisect, worktrees, and reflog
  • Maintain clean history and recover from any situation
  • Manage complex Git histories, collaborate on feature branches, or troubleshoot repository issues

Example Workflow: Adding a New Package

# 1. Create package directory
mkdir -p packages/my-tool

# 2. Create package.nix (use appropriate template above)

# 3. Create default.nix wrapper
cat > packages/my-tool/default.nix << 'EOF'
{ pkgs, ... }:
pkgs.callPackage ./package.nix { }
EOF

# 4. Test build
nix build .#my-tool

# 5. If build fails, fix issues, then retry

# 6. Update README.md with new package info

# 7. Commit changes using conventional-commit skill
git add packages/my-tool README.md
# Then invoke: skill: "conventional-commit"