Blueprint reads packages from the git index, not the working directory. New packages must be staged with 'git add' before they appear in flake outputs. Add this to both the Blueprint Framework section and the 'Adding a New Package' workflow.
9.7 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
- Don't assume. Don't hide confusion. Surface tradeoffs.
- Minimum code that solves the problem. Nothing speculative.
- Touch only what you must. Clean up only your own mess.
- Define success criteria. Loop until verified.
Blueprint Framework
This project uses numtide/blueprint which:
- Automatically discovers packages in the
packages/directory - Provides
perSystemoutputs for multi-system builds - Handles formatting, checking, and devShell generation
- Exposes
mkPackagesForfunction to build packages against any nixpkgs instance
Important: Blueprint's package discovery reads from the git index, not the working directory. New package directories must be staged with git add before they appear in flake outputs. Unstaged files are invisible to nix build, nix flake show, and nix run.
Two Overlay Strategies
-
overlays.default- Binary-cache-friendly- Uses packages built against this flake's nixpkgs revision
- Better for binary cache hits when using the same nixpkgs
-
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
- Builds packages against the consumer's nixpkgs (
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:
-
Create the directory:
mkdir -p packages/<package-name> -
Create
package.nixwith the actual derivation -
Create
default.nixas a wrapper:{ pkgs, ... }: pkgs.callPackage ./package.nix { }
3.5. Stage the package: git add packages/<package-name>/
Blueprint discovers packages from the git index, not the working directory.
Without this step, the package won't appear in flake outputs.
-
Test the package:
nix build .#<package-name> nix run .#<package-name> -
Update README.md to document the new package in the Available Packages table
-
Set appropriate metadata:
meta.description- Required, shown in package listingsmeta.mainProgram- Set for packages providing a CLI executablemeta.passthru.category- Optional, used for organization (e.g., "AI Coding Agents")meta.passthru.hideFromDocs- Set totrueto exclude from documentation
Common Tasks
Updating a Package Version
- Update
versioninpackage.nix - Update
src.hash(usenix-prefetch-githubor let Nix tell you the correct hash) - Update
cargoHashfor Rust packages (build will fail and tell you the correct hash) - Test:
nix build .#<package-name> - 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: Receivespackagesfrom blueprint outputs, maps them tofinal.stdenv.hostPlatform.systemoverlays/shared-nixpkgs.nix: ReceivesmkPackagesFor, uses it to build against consumer'sfinal
Important Notes
Do's
- ✅ Use
pkgs.callPackagepattern for package definitions - ✅ Set proper
metaattributes (description, license, homepage) - ✅ Test packages with
nix buildbefore committing - ✅ Use
passthru.categoryfor organizational grouping - ✅ Follow Nixpkgs conventions for package naming and structure
Don'ts
- ❌ Don't modify
flake.lockmanually - usenix flake update - ❌ Don't hardcode system-specific paths or assumptions
- ❌ Don't forget to set
meta.mainProgramfor 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
- Check the error message carefully
- Verify all dependencies are listed
- Check if the source hash is correct
- For Rust packages, verify
cargoHashmatches
Overlay Not Working
- Verify the overlay is correctly imported
- Check if the package exists in
packagesoutput - For
shared-nixpkgs, ensuremkPackagesForis available
Binary Cache Issues
- The
defaultoverlay is more likely to get cache hits - The
shared-nixpkgsoverlay 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_v8hashes automatically via the custom fetcher - mcp-gateway: Standard Rust package,
nix-updatehandles version + cargoHash - skillsmcp: Pinned to a commit hash; use
--version=branch=mainor 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"