- 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
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
- 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
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 { } -
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"