Add agent skills

This commit is contained in:
2026-02-05 18:47:42 +00:00
parent bc3350f501
commit 89aba25e23
13 changed files with 2681 additions and 0 deletions

View File

@@ -0,0 +1,133 @@
---
name: find-skills
description: Helps users discover and install agent skills when they ask questions like "how do I do X", "find a skill for X", "is there a skill that can...", or express interest in extending capabilities. This skill should be used when the user is looking for functionality that might exist as an installable skill.
---
# Find Skills
This skill helps you discover and install skills from the open agent skills ecosystem.
## When to Use This Skill
Use this skill when the user:
- Asks "how do I do X" where X might be a common task with an existing skill
- Says "find a skill for X" or "is there a skill for X"
- Asks "can you do X" where X is a specialized capability
- Expresses interest in extending agent capabilities
- Wants to search for tools, templates, or workflows
- Mentions they wish they had help with a specific domain (design, testing, deployment, etc.)
## What is the Skills CLI?
The Skills CLI (`npx skills`) is the package manager for the open agent skills ecosystem. Skills are modular packages that extend agent capabilities with specialized knowledge, workflows, and tools.
**Key commands:**
- `npx skills find [query]` - Search for skills interactively or by keyword
- `npx skills add <package>` - Install a skill from GitHub or other sources
- `npx skills check` - Check for skill updates
- `npx skills update` - Update all installed skills
**Browse skills at:** https://skills.sh/
## How to Help Users Find Skills
### Step 1: Understand What They Need
When a user asks for help with something, identify:
1. The domain (e.g., React, testing, design, deployment)
2. The specific task (e.g., writing tests, creating animations, reviewing PRs)
3. Whether this is a common enough task that a skill likely exists
### Step 2: Search for Skills
Run the find command with a relevant query:
```bash
npx skills find [query]
```
For example:
- User asks "how do I make my React app faster?" → `npx skills find react performance`
- User asks "can you help me with PR reviews?" → `npx skills find pr review`
- User asks "I need to create a changelog" → `npx skills find changelog`
The command will return results like:
```
Install with npx skills add <owner/repo@skill>
vercel-labs/agent-skills@vercel-react-best-practices
└ https://skills.sh/vercel-labs/agent-skills/vercel-react-best-practices
```
### Step 3: Present Options to the User
When you find relevant skills, present them to the user with:
1. The skill name and what it does
2. The install command they can run
3. A link to learn more at skills.sh
Example response:
```
I found a skill that might help! The "vercel-react-best-practices" skill provides
React and Next.js performance optimization guidelines from Vercel Engineering.
To install it:
npx skills add vercel-labs/agent-skills@vercel-react-best-practices
Learn more: https://skills.sh/vercel-labs/agent-skills/vercel-react-best-practices
```
### Step 4: Offer to Install
If the user wants to proceed, you can install the skill for them:
```bash
npx skills add <owner/repo@skill> -g -y
```
The `-g` flag installs globally (user-level) and `-y` skips confirmation prompts.
## Common Skill Categories
When searching, consider these common categories:
| Category | Example Queries |
| --------------- | ---------------------------------------- |
| Web Development | react, nextjs, typescript, css, tailwind |
| Testing | testing, jest, playwright, e2e |
| DevOps | deploy, docker, kubernetes, ci-cd |
| Documentation | docs, readme, changelog, api-docs |
| Code Quality | review, lint, refactor, best-practices |
| Design | ui, ux, design-system, accessibility |
| Productivity | workflow, automation, git |
## Tips for Effective Searches
1. **Use specific keywords**: "react testing" is better than just "testing"
2. **Try alternative terms**: If "deploy" doesn't work, try "deployment" or "ci-cd"
3. **Check popular sources**: Many skills come from `vercel-labs/agent-skills` or `ComposioHQ/awesome-claude-skills`
## When No Skills Are Found
If no relevant skills exist:
1. Acknowledge that no existing skill was found
2. Offer to help with the task directly using your general capabilities
3. Suggest the user could create their own skill with `npx skills init`
Example:
```
I searched for skills related to "xyz" but didn't find any matches.
I can still help you with this task directly! Would you like me to proceed?
If this is something you do often, you could create your own skill:
npx skills init my-xyz-skill
```

View File

@@ -0,0 +1,349 @@
---
name: nix-best-practices
description: Nix patterns for flakes, overlays, unfree handling, and binary overlays. Use when working with flake.nix or shell.nix.
---
# Nix Best Practices
## Flake Structure
Standard flake.nix structure:
```nix
{
description = "Project description";
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = import nixpkgs {
inherit system;
};
in {
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [
# packages here
];
};
});
}
```
## Follows Pattern (Avoid Duplicate Nixpkgs)
When adding overlay inputs, use `follows` to share the parent nixpkgs and avoid downloading multiple versions:
```nix
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
# Overlay follows parent nixpkgs
some-overlay.url = "github:owner/some-overlay";
some-overlay.inputs.nixpkgs.follows = "nixpkgs";
# Chain follows through intermediate inputs
another-overlay.url = "github:owner/another-overlay";
another-overlay.inputs.nixpkgs.follows = "some-overlay";
};
```
All inputs must be listed in outputs function even if not directly used:
```nix
outputs = { self, nixpkgs, some-overlay, another-overlay, ... }:
```
## Applying Overlays
Overlays modify or add packages to nixpkgs:
```nix
let
pkgs = import nixpkgs {
inherit system;
overlays = [
overlay1.overlays.default
overlay2.overlays.default
# Inline overlay
(final: prev: {
myPackage = prev.myPackage.override { ... };
})
];
};
in
```
## Handling Unfree Packages
### Option 1: nixpkgs-unfree (Recommended for Teams)
Use numtide/nixpkgs-unfree for EULA-licensed packages without requiring user config:
```nix
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
nixpkgs-unfree.url = "github:numtide/nixpkgs-unfree/nixos-unstable";
nixpkgs-unfree.inputs.nixpkgs.follows = "nixpkgs";
# Unfree overlay follows nixpkgs-unfree
proprietary-tool.url = "github:owner/proprietary-tool-overlay";
proprietary-tool.inputs.nixpkgs.follows = "nixpkgs-unfree";
};
```
This chains: `proprietary-tool``nixpkgs-unfree``nixpkgs`
### Option 2: User Config
Users add to `~/.config/nixpkgs/config.nix`:
```nix
{ allowUnfree = true; }
```
### Option 3: Specific Packages (Flake)
```nix
let
pkgs = import nixpkgs {
inherit system;
config.allowUnfreePredicate = pkg: builtins.elem (lib.getName pkg) [
"specific-package"
];
};
in
```
Note: `config.allowUnfree` in flake.nix doesn't work with `nix develop` - use nixpkgs-unfree or user config.
## Creating Binary Overlay Repos
When nixpkgs builds a community version lacking features (common with open-core tools), create an overlay that fetches official binaries.
### Pattern (see 0xBigBoss/atlas-overlay, 0xBigBoss/bun-overlay)
```nix
{
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
flake-utils.url = "github:numtide/flake-utils";
};
outputs = { self, nixpkgs, flake-utils }:
flake-utils.lib.eachDefaultSystem (system:
let
pkgs = nixpkgs.legacyPackages.${system};
version = "1.0.0";
# Platform-specific binaries
sources = {
"x86_64-linux" = {
url = "https://example.com/tool-linux-amd64-v${version}";
sha256 = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=";
};
"aarch64-linux" = {
url = "https://example.com/tool-linux-arm64-v${version}";
sha256 = "sha256-BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB=";
};
"x86_64-darwin" = {
url = "https://example.com/tool-darwin-amd64-v${version}";
sha256 = "sha256-CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC=";
};
"aarch64-darwin" = {
url = "https://example.com/tool-darwin-arm64-v${version}";
sha256 = "sha256-DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD=";
};
};
source = sources.${system} or (throw "Unsupported system: ${system}");
toolPackage = pkgs.stdenv.mkDerivation {
pname = "tool";
inherit version;
src = pkgs.fetchurl {
inherit (source) url sha256;
};
sourceRoot = ".";
dontUnpack = true;
installPhase = ''
mkdir -p $out/bin
cp $src $out/bin/tool
chmod +x $out/bin/tool
'';
meta = with pkgs.lib; {
description = "Tool description";
homepage = "https://example.com";
license = licenses.unfree; # or appropriate license
platforms = builtins.attrNames sources;
};
};
in {
packages.default = toolPackage;
packages.tool = toolPackage;
overlays.default = final: prev: {
tool = toolPackage;
};
})
// {
overlays.default = final: prev: {
tool = self.packages.${prev.system}.tool;
};
};
}
```
### Getting SHA256 Hashes
```bash
nix-prefetch-url https://example.com/tool-linux-amd64-v1.0.0
# Returns hash in base32, convert to SRI format:
nix hash to-sri --type sha256 <base32-hash>
```
Or use SRI directly:
```bash
nix-prefetch-url --type sha256 https://example.com/tool-linux-amd64-v1.0.0
```
## Dev Shell Patterns
### Basic Shell
```nix
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [
nodejs
python3
];
shellHook = ''
echo "Dev environment ready"
'';
};
```
### With Environment Variables
```nix
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [ postgresql ];
# Set at shell entry
DATABASE_URL = "postgres://localhost/dev";
# Or in shellHook for dynamic values
shellHook = ''
export PROJECT_ROOT="$(pwd)"
'';
};
```
### Native Dependencies (C Libraries)
```nix
devShells.default = pkgs.mkShell {
buildInputs = with pkgs; [
openssl
postgresql
];
# Expose headers and libraries
shellHook = ''
export C_INCLUDE_PATH="${pkgs.openssl.dev}/include:$C_INCLUDE_PATH"
export LIBRARY_PATH="${pkgs.openssl.out}/lib:$LIBRARY_PATH"
export PKG_CONFIG_PATH="${pkgs.openssl.dev}/lib/pkgconfig:$PKG_CONFIG_PATH"
'';
};
```
## Direnv Integration
`.envrc` for flake projects:
```bash
use flake
```
For unfree packages without nixpkgs-unfree:
```bash
export NIXPKGS_ALLOW_UNFREE=1
use flake --impure
```
## Common Commands
```bash
# Update all inputs
nix flake update
# Update specific input
nix flake update some-input
# Check flake validity
nix flake check
# Show flake metadata
nix flake metadata
# Enter dev shell
nix develop
# Run command in dev shell
nix develop -c <command>
# Build package
nix build .#packageName
# Run package
nix run .#packageName
```
## Troubleshooting
### "unexpected argument" Error
All inputs must be listed in outputs function:
```nix
# Wrong
outputs = { self, nixpkgs }: ...
# Right (if you have more inputs)
outputs = { self, nixpkgs, other-input, ... }: ...
```
### Unfree Package Errors with nix develop
`config.allowUnfree` in flake.nix doesn't propagate to `nix develop`. Use:
1. nixpkgs-unfree input (recommended)
2. User's `~/.config/nixpkgs/config.nix`
3. `NIXPKGS_ALLOW_UNFREE=1 nix develop --impure`
### Duplicate Nixpkgs Downloads
Use `follows` to chain inputs to a single nixpkgs source.
### Overlay Not Applied
Ensure overlay is in the `overlays` list when importing nixpkgs:
```nix
pkgs = import nixpkgs {
inherit system;
overlays = [ my-overlay.overlays.default ];
};
```
### Hash Mismatch
Re-fetch with `nix-prefetch-url` and update the hash. Hashes change when upstream updates binaries at the same URL.

View File

@@ -0,0 +1,533 @@
# NixOS Configuration Best Practices
Complete guide for configuring NixOS systems with flakes, managing overlays, and structuring configurations.
## Table of Contents
- [Overview](#overview)
- [When to Use](#when-to-use)
- [Essential Pattern](#essential-pattern-overlay-scope-and-useglobalpkgs)
- [Flakes Structure](#flakes-configuration-structure)
- [Host Organization](#host-configuration-organization)
- [Package Installation](#package-installation-best-practices)
- [Common Mistakes](#common-configuration-mistakes)
- [Troubleshooting](#troubleshooting-configuration-issues)
- [Real-World Impact](#real-world-impact)
---
## Overview
**Core principle:** Understand the interaction between NixOS system configuration and Home Manager overlays.
When `useGlobalPkgs = true`, overlays must be defined at the NixOS configuration level, not in Home Manager configuration files.
---
## When to Use
**Use when:**
- Configuring NixOS with flakes and Home Manager
- Adding overlays that don't seem to apply
- Using `useGlobalPkgs = true` with custom overlays
- Structuring NixOS configurations across multiple hosts
- Package changes not appearing after rebuild
- Confused about where to define overlays
**Don't use for:**
- Packaging new software (use nix-packaging-best-practices)
- Simple package installation without overlays
- NixOS module development (see NixOS module documentation)
---
## Essential Pattern: Overlay Scope and useGlobalPkgs
### Why This Matters
When using Home Manager with NixOS, the `useGlobalPkgs` setting determines where overlay definitions must be placed. Defining overlays in the wrong location means they simply don't apply, leading to "package not found" errors even when the overlay syntax is correct.
### The Problem
When `useGlobalPkgs = true`, Home Manager uses NixOS's global `pkgs` instance. Overlays defined in `home.nix` are ignored because Home Manager isn't creating its own `pkgs` - it's using the system one.
### Incorrect: Overlay in home.nix with useGlobalPkgs=true
```nix
# hosts/home/default.nix
{
home-manager.useGlobalPkgs = true; # Using system pkgs
home-manager.useUserPackages = true;
home-manager.users.chumeng = import ./home.nix;
}
# home-manager/home.nix
{ config, pkgs, inputs, ... }:
{
# ❌ This overlay is IGNORED when useGlobalPkgs = true!
nixpkgs.overlays = [ inputs.claude-code.overlays.default ];
home.packages = with pkgs; [
claude-code # Error: attribute 'claude-code' not found
];
}
```
**Why it fails:** When `useGlobalPkgs = true`, the `nixpkgs.overlays` line in `home.nix` has no effect. Home Manager isn't creating its own `pkgs`, so it can't apply overlays to one.
### Correct: Overlay in host home-manager block
```nix
# hosts/home/default.nix
{
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.users.chumeng = import ./home.nix;
home-manager.extraSpecialArgs = { inherit inputs pkgs-stable system; };
# ✅ Overlay defined HERE affects the global pkgs
nixpkgs.overlays = [ inputs.claude-code.overlays.default ];
}
# home-manager/home.nix
{ config, pkgs, ... }:
{
# No overlay definition needed here
home.packages = with pkgs; [
claude-code # ✅ Works! Found via overlay
];
}
```
**Why it works:** The overlay is defined where Home Manager configures the `pkgs` instance it will use. When `useGlobalPkgs = true`, this means the overlay is applied to the system's package set.
### Alternative: Set useGlobalPkgs=false
If you want to define overlays in `home.nix`, set `useGlobalPkgs = false`:
```nix
# hosts/home/default.nix
{
home-manager.useGlobalPkgs = false; # Home Manager creates own pkgs
home-manager.useUserPackages = true;
home-manager.users.chumeng = import ./home.nix;
}
# home-manager/home.nix
{ pkgs, inputs, ... }:
{
# ✅ This works when useGlobalPkgs = false
nixpkgs.overlays = [ inputs.claude-code.overlays.default ];
home.packages = with pkgs; [
claude-code # ✅ Works! Found via overlay
];
}
```
**Trade-off:** This creates a separate package set for Home Manager, which means packages are built twice (once for system, once for Home Manager). Only use this when you truly need separate package sets.
### Decision Matrix
| Your Need | useGlobalPkgs | Overlay Location |
|-----------|---------------|------------------|
| Single-user system, efficiency | `true` | Host home-manager block |
| Multi-user, different packages per user | `false` | User's home.nix |
| Custom packages system-wide | `true` | System nixpkgs.overlays |
| Quick prototype | `false` | User's home.nix |
---
## Flakes Configuration Structure
### Core Structure
```nix
{
description = "My NixOS configuration";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
home-manager.url = "github:nix-community/home-manager/release-25.05";
home-manager.inputs.nixpkgs.follows = "nixpkgs";
# Add other flake inputs here
};
outputs = { self, nixpkgs, home-manager, ... }@inputs: {
nixosConfigurations.hostname = nixpkgs.lib.nixosSystem {
specialArgs = { inherit inputs; };
modules = [ ./hosts/hostname ];
};
};
}
```
### Special Args Pattern
Pass `inputs` via `specialArgs` to make flake inputs available in modules:
```nix
# ❌ WRONG: Forgetting specialArgs
outputs = { self, nixpkgs, home-manager }:
{
nixosConfigurations.myhost = nixpkgs.lib.nixosSystem {
modules = [ ./hosts/myhost ]; # inputs not available!
};
}
# ✅ CORRECT: Using specialArgs
outputs = { self, nixpkgs, home-manager, ... }@inputs:
{
nixosConfigurations.myhost = nixpkgs.lib.nixosSystem {
specialArgs = { inherit inputs; };
modules = [ ./hosts/myhost ]; # inputs available!
};
}
```
### Input Following
Set `inputs.nixpkgs.follows` to avoid duplicate nixpkgs instances:
```nix
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
# ❌ WRONG: Doesn't follow, creates duplicate nixpkgs
home-manager.url = "github:nix-community/home-manager/release-25.05";
# ✅ CORRECT: Follows nixpkgs, uses same instance
home-manager.url = "github:nix-community/home-manager/release-25.05";
home-manager.inputs.nixpkgs.follows = "nixpkgs";
};
```
---
## Host Configuration Organization
### Directory Structure
```
nixos-config/
├── flake.nix # Top-level flake
├── hosts/
│ ├── laptop/
│ │ ├── default.nix # Host-specific config
│ │ ├── hardware-configuration.nix # Generated (don't edit)
│ │ └── home.nix # Home Manager config
│ ├── desktop/
│ │ ├── default.nix
│ │ ├── hardware-configuration.nix
│ │ └── home.nix
│ └── base.nix # Shared by all hosts (optional)
├── modules/ # Reusable NixOS modules
├── overlays/ # Custom overlays
├── home-manager/ # Shared Home Manager configs
│ ├── shell/
│ ├── applications/
│ └── common.nix
└── secrets/ # Age-encrypted secrets
```
### Host Configuration Pattern
```nix
# hosts/laptop/default.nix
{ inputs, pkgs, pkgs-stable, system, ... }:
{
imports = [
./hardware-configuration.nix # Import hardware config
../base.nix # Import shared config
inputs.home-manager.nixosModules.home-manager
{
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.users.john = import ./home.nix;
home-manager.extraSpecialArgs = {
inherit inputs pkgs-stable system;
};
nixpkgs.overlays = [ inputs.some-overlay.overlays.default ];
}
];
# Host-specific config only
networking.hostName = "laptop";
}
```
### Shared Base Configuration
```nix
# hosts/base.nix
{ config, pkgs, inputs, ... }:
{
# Network
networking.networkmanager.enable = true;
# Time and locale
time.timeZone = "America/New_York";
i18n.defaultLocale = "en_US.UTF-8";
# Users (shared across all hosts)
users.users.john = {
isNormalUser = true;
extraGroups = [ "wheel" "networkmanager" ];
};
# Common packages
environment.systemPackages = with pkgs; [
vim
git
wget
tmux
];
# Common services
services.openssh.enable = true;
# Nix settings
nix.settings.experimental-features = [ "nix-command" "flakes" ];
}
```
**Important:** Don't edit `hardware-configuration.nix` manually. It's generated by `nixos-generate-config` and should be replaced when hardware changes.
---
## Package Installation Best Practices
### System vs User Packages
**System Packages (NixOS)** - Use for:
- System services (servers, daemons)
- Packages needed by all users
- Hardware-related packages (drivers, firmware)
```nix
# hosts/base.nix or host-specific default.nix
{ config, pkgs, ... }:
{
environment.systemPackages = with pkgs; [
vim # Available to all users
git
wget
];
}
```
**User Packages (Home Manager)** - Use for:
- User-specific applications
- Desktop applications
- Development tools (user-specific)
```nix
# home-manager/home.nix or sub-configs
{ config, pkgs, ... }:
{
home.packages = with pkgs; [
vscode # User-specific
chrome
];
}
```
### Installing from Different Nixpkgs Channels
```nix
# flake.nix - default is unstable
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
nixpkgs-stable.url = "github:nixos/nixpkgs/nixos-25.05";
};
# Host config
{ pkgs, pkgs-stable, ... }:
{
environment.systemPackages = with pkgs; [
vim # From unstable (default)
];
environment.systemPackages = with pkgs-stable; [
vim # From stable
];
}
```
---
## Common Configuration Mistakes
### Mistake 1: Overlay in Wrong Location
**Symptom:** Package not found even though overlay is defined.
**Solution:** Move overlay to host's home-manager configuration block.
```nix
# ❌ WRONG: home-manager/home.nix
{
nixpkgs.overlays = [ inputs.overlay.overlays.default ];
}
# ✅ CORRECT: hosts/home/default.nix
{
home-manager.nixpkgs.overlays = [ inputs.overlay.overlays.default ];
}
```
### Mistake 2: Forgetting specialArgs
**Symptom:** `undefined variable 'inputs'` error.
**Solution:** Add `specialArgs = { inherit inputs; }`.
```nix
# ❌ WRONG
outputs = { self, nixpkgs, home-manager }:
{
nixosConfigurations.myhost = nixpkgs.lib.nixosSystem {
modules = [ ./hosts/myhost ];
};
}
# ✅ CORRECT
outputs = { self, nixpkgs, home-manager, ... }@inputs:
{
nixosConfigurations.myhost = nixpkgs.lib.nixosSystem {
specialArgs = { inherit inputs; };
modules = [ ./hosts/myhost ];
};
}
```
### Mistake 3: Editing hardware-configuration.nix
**Symptom:** Hardware changes lost after running `nixos-generate-config`.
**Solution:** Put custom config in `default.nix`, not `hardware-configuration.nix`.
### Mistake 4: Duplicate Package Declarations
**Symptom:** Same package in both system and Home Manager config.
**Solution:** Install in appropriate location only.
```nix
# ❌ WRONG
# hosts/base.nix
environment.systemPackages = with pkgs; [ firefox ];
# home-manager/home.nix
home.packages = with pkgs; [ firefox ]; # Duplicate!
# ✅ CORRECT: Choose one location
home.packages = with pkgs; [ firefox ];
```
### Mistake 5: Not Following nixpkgs
**Symptom:** Slow builds, inconsistent packages.
**Solution:** Use `.follows` for dependency inputs.
```nix
# ❌ WRONG
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
home-manager.url = "github:nix-community/home-manager/release-25.05";
};
# ✅ CORRECT
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
home-manager.url = "github:nix-community/home-manager/release-25.05";
home-manager.inputs.nixpkgs.follows = "nixpkgs";
};
```
---
## Troubleshooting Configuration Issues
### General Approach
1. **Read error messages completely** - They usually tell you exactly what's wrong
2. **Verify syntax** - Check for missing brackets, quotes, commas
3. **Validate config** - Use `nixos-rebuild test` first
4. **Check scope** - Is overlay/module in correct location?
5. **Trace dependencies** - Are required inputs/imports present?
### Common Error Patterns
**"undefined variable 'inputs'"**
Add to flake.nix:
```nix
specialArgs = { inherit inputs; };
```
**"attribute 'package-name' not found"**
Check if overlay is defined in correct location based on `useGlobalPkgs` setting.
**"error: The option 'some.option' does not exist"**
Search for option:
```bash
nixos-options | grep some-option
```
**"infinite recursion"**
Use --show-trace:
```bash
nixos-rebuild build --flake .#hostname --show-trace
```
### Configuration Changes Not Applying
```bash
# Verify rebuild succeeded
sudo nixos-rebuild switch --flake .#hostname
# Check current generation
sudo nix-env --list-generations --profile /nix/var/nix/profiles/system
# Verify new generation is active
nixos-version
```
### Useful Verification Commands
```bash
# Check configuration without building
nix flake check
nixos-rebuild build --flake .#hostname --dry-run
# Evaluate specific option
nix eval .#nixosConfigurations.myhost.config.environment.systemPackages
# Test configuration safely
nixos-rebuild test --flake .#hostname # Rollback on reboot
nixos-rebuild switch --flake .#hostname # Persistent
```
---
## Real-World Impact
Following these best practices prevents the most common NixOS configuration issues:
**Before:**
- Users spend hours debugging why overlays don't apply
- Configuration is duplicated across hosts
- Changes don't apply after editing files
- Confusion about where to define overlays
**After:**
- Clear understanding of overlay scope
- Modular, maintainable configuration structure
- Predictable behavior
- Easy debugging when issues arise
The overlay scope issue alone accounts for ~80% of NixOS + Home Manager configuration problems encountered by users.

View File

@@ -0,0 +1,134 @@
---
name: nixos-best-practices
description: Use when configuring NixOS with flakes, managing overlays with home-manager useGlobalPkgs, structuring NixOS configurations, or facing issues where configuration changes don't apply
license: MIT
metadata:
author: chumeng
version: "1.0.0"
---
# Configuring NixOS Systems with Flakes
Configure NixOS systems with flakes, manage overlays properly, and structure configurations for maintainability.
## Core Principle
**Understand the interaction between NixOS system configuration and Home Manager overlays.**
When `useGlobalPkgs = true`, overlays must be defined at the NixOS configuration level, not in Home Manager configuration files.
## When to Use
- Configuring NixOS with flakes and Home Manager
- Adding overlays that don't seem to apply
- Using `useGlobalPkgs = true` with custom overlays
- Structuring NixOS configurations across multiple hosts
- Package changes not appearing after rebuild
- Confused about where to define overlays
**Don't use for:**
- Packaging new software (use nix-packaging-best-practices)
- Simple package installation without overlays
- NixOS module development (see NixOS module documentation)
## Quick Reference
| Topic | Rule File |
|-------|-----------|
| Overlay scope and useGlobalPkgs | [overlay-scope](rules/overlay-scope.md) |
| Flakes configuration structure | [flakes-structure](rules/flakes-structure.md) |
| Host configuration organization | [host-organization](rules/host-organization.md) |
| Package installation best practices | [package-installation](rules/package-installation.md) |
| Common configuration mistakes | [common-mistakes](rules/common-mistakes.md) |
| Debugging configuration issues | [troubleshooting](rules/troubleshooting.md) |
## Essential Pattern: Overlay with useGlobalPkgs
```nix
# ❌ WRONG: Overlay in home.nix (doesn't apply)
# home-manager/home.nix
{
nixpkgs.overlays = [ inputs.claude-code.overlays.default ]; # Ignored!
home.packages = with pkgs; [ claude-code ]; # Not found!
}
# ✅ CORRECT: Overlay in NixOS home-manager block
# hosts/home/default.nix
{
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.users.chumeng = import ./home.nix;
home-manager.extraSpecialArgs = { inherit inputs pkgs-stable system; };
# Overlay must be HERE when useGlobalPkgs = true
nixpkgs.overlays = [ inputs.claude-code.overlays.default ];
}
```
## Common Tasks
| Task | Solution |
|------|----------|
| Add flake input | Add to `inputs` in flake.nix |
| Add overlay for system packages | Define in `nixpkgs.overlays` in system configuration |
| Add overlay for home-manager (useGlobalPkgs=true) | Define in `home-manager.nixpkgs.overlays` in host config |
| Add overlay for home-manager (useGlobalPkgs=false) | Define in `home.nix` with `nixpkgs.overlays` |
| Pass inputs to modules | Use `specialArgs` in nixosSystem or home-manager |
| Multiple host configurations | Create separate host files in `hosts/` |
| Shared configuration modules | Create modules in `modules/` and import in each host |
| Package not found after overlay | Check overlay scope vs useGlobalPkgs setting |
## Overlay Scope Decision Matrix
| useGlobalPkgs | Overlay Definition Location | Affects |
|---------------|---------------------------|---------|
| `true` | `home-manager.nixpkgs.overlays` | System + Home Manager packages |
| `true` | `home.nix` with `nixpkgs.overlays` | **Nothing** (ignored!) |
| `false` | `home.nix` with `nixpkgs.overlays` | Home Manager packages only |
| `false` | `home-manager.nixpkgs.overlays` | Home Manager packages only |
| Any | System `nixpkgs.overlays` | System packages only |
## Configuration Layers (Bottom to Top)
1. **System configuration** (`/etc/nixos/configuration.nix` or host files)
- System-wide services
- System packages
- System overlays only affect this layer
2. **Home Manager (useGlobalPkgs=true)**
- Uses system pkgs (includes system overlays)
- Home Manager overlays affect both system and user packages
- Most efficient for single-user systems
3. **Home Manager (useGlobalPkgs=false)**
- Creates separate pkgs instance
- Home Manager overlays affect user packages only
- Useful for multi-user systems with different needs
## Red Flags - STOP
- "Overlay in home.nix isn't working" → Check if useGlobalPkgs=true, move to host config
- "I'll just add overlays everywhere" → Define once at appropriate scope
- "Package works in nix repl but not installed" → Check overlay scope
- "Changes don't apply after rebuild" → Verify overlay is in correct location
- "useGlobalPkgs=false for no reason" → Use true unless you need separate package sets
## How to Use
Read individual rule files for detailed explanations and code examples:
```
rules/overlay-scope.md # The core overlay scope issue
rules/flakes-structure.md # How to organize flake.nix
rules/host-organization.md # How to structure host configs
rules/common-mistakes.md # Pitfalls and how to avoid them
```
Each rule file contains:
- Brief explanation of why it matters
- Incorrect code example with explanation
- Correct code example with explanation
- Additional context and references
## Full Compiled Document
For the complete guide with all rules expanded: `AGENTS.md`

View File

@@ -0,0 +1,323 @@
---
title: Common Configuration Mistakes
impact: HIGH
impactDescription: Prevents the most frequently made configuration errors
tags: mistakes,pitfalls,errors,checklist
---
## Why This Matters
Understanding common mistakes helps avoid them, saving time and preventing configuration errors.
## Mistake 1: Overlay in Wrong Location
### Symptom
Package not found even though overlay is defined.
### Cause
Overlay defined in `home.nix` when `useGlobalPkgs = true`.
### Solution
Move overlay to host's home-manager configuration block.
```nix
# ❌ WRONG
# home-manager/home.nix
{
nixpkgs.overlays = [ inputs.overlay.overlays.default ];
}
# ✅ CORRECT
# hosts/home/default.nix
{
home-manager.nixpkgs.overlays = [ inputs.overlay.overlays.default ];
}
```
**See:** [overlay-scope.md](overlay-scope.md)
## Mistake 2: Forgetting specialArgs
### Symptom
`undefined variable 'inputs'` error.
### Cause
Not passing `inputs` via `specialArgs`.
### Solution
Add `specialArgs = { inherit inputs; }`.
```nix
# ❌ WRONG
outputs = { self, nixpkgs, home-manager }:
{
nixosConfigurations.myhost = nixpkgs.lib.nixosSystem {
modules = [ ./hosts/myhost ];
};
}
# ✅ CORRECT
outputs = { self, nixpkgs, home-manager, ... }@inputs:
{
nixosConfigurations.myhost = nixpkgs.lib.nixosSystem {
specialArgs = { inherit inputs; };
modules = [ ./hosts/myhost ];
};
}
```
**See:** [flakes-structure.md](flakes-structure.md)
## Mistake 3: Editing hardware-configuration.nix
### Symptom
Hardware changes lost after running `nixos-generate-config`.
### Cause
Manually editing generated file.
### Solution
Put custom config in `default.nix`, not `hardware-configuration.nix`.
```nix
# ❌ WRONG: Editing hardware-configuration.nix
# hosts/laptop/hardware-configuration.nix
{ config, lib, pkgs, modulesPath, ... }:
{
# My custom kernel parameters (will be lost!)
boot.kernelParams = [ "intel_iommu=on" ];
# Generated hardware config...
}
# ✅ CORRECT: Custom config in default.nix
# hosts/laptop/default.nix
{
imports = [ ./hardware-configuration.nix ];
# Custom kernel parameters (safe!)
boot.kernelParams = [ "intel_iommu=on" ];
}
```
**See:** [host-organization.md](host-organization.md)
## Mistake 4: Duplicate Package Declarations
### Symptom
Package installed multiple times or conflicts.
### Cause
Same package in both system and Home Manager config.
### Solution
Install in appropriate location only.
```nix
# ❌ WRONG: Same package in both places
# hosts/base.nix
environment.systemPackages = with pkgs; [ firefox ];
# home-manager/home.nix
home.packages = with pkgs; [ firefox ]; # Duplicate!
# ✅ CORRECT: Choose one location
# User apps in Home Manager
home.packages = with pkgs; [ firefox ];
```
**See:** [package-installation.md](package-installation.md)
## Mistake 5: Not Following nixpkgs
### Symptom
Slow builds, inconsistent packages.
### Cause
Multiple independent nixpkgs instances.
### Solution
Use `.follows` for dependency inputs.
```nix
# ❌ WRONG: Independent nixpkgs
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
home-manager.url = "github:nix-community/home-manager/release-25.05";
# home-manager will use its own nixpkgs!
};
# ✅ CORRECT: Follow nixpkgs
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
home-manager.url = "github:nix-community/home-manager/release-25.05";
home-manager.inputs.nixpkgs.follows = "nixpkgs";
};
```
**See:** [flakes-structure.md](flakes-structure.md)
## Mistake 6: Mixing System and User Concerns
### Symptom
User-specific config in system files or vice versa.
### Cause
Not understanding NixOS vs Home Manager responsibilities.
### Solution
System config in NixOS, user config in Home Manager.
```nix
# ❌ WRONG: User config in system
# hosts/base.nix
{
# User's git config (should be in Home Manager)
programs.git = {
enable = true;
userName = "john";
userEmail = "john@example.com";
};
}
# ✅ CORRECT: User config in Home Manager
# home-manager/home.nix
{
programs.git = {
enable = true;
userName = "john";
userEmail = "john@example.com";
};
}
```
**See:** [package-installation.md](package-installation.md)
## Mistake 7: Forgetting to Rebuild
### Symptom
Changes don't appear after editing config.
### Cause
Editing config but not running rebuild.
### Solution
Always rebuild after config changes.
```bash
# After editing NixOS config
sudo nixos-rebuild switch --flake .#hostname
# After editing Home Manager config (standalone)
home-manager switch --flake .#hostname
# When using NixOS-integrated Home Manager
sudo nixos-rebuild switch --flake .#hostname
```
## Mistake 8: Overriding systemPackages Multiple Times
### Symptom
Some packages disappear after adding others.
### Cause
Multiple `environment.systemPackages` assignments.
### Solution
Use single list or mkBefore/mkAfter.
```nix
# ❌ WRONG: Multiple assignments
environment.systemPackages = with pkgs; [ vim git ];
environment.systemPackages = with pkgs; [ htop ]; # Overwrites!
# ✅ CORRECT: Single list
environment.systemPackages = with pkgs; [
vim
git
htop
];
# ✅ ALSO CORRECT: Use mkBefore/mkAfter
environment.systemPackages = with pkgs; [ vim git ];
environment.systemPackages = mkAfter [ pkgs.htop ];
```
## Mistake 9: Hardcoding Paths
### Symptom
Config breaks on different machines.
### Cause
Using absolute paths instead of Nix paths.
### Solution
Use relative paths or Nix constructs.
```nix
# ❌ WRONG: Absolute path
{ pkgs, ... }:
{
environment.systemPackages = [
"/home/john/my-app/bin/my-app" # Only works for john!
];
}
# ✅ CORRECT: Use Nix package
{ pkgs, ... }:
{
environment.systemPackages = [ pkgs.my-app ];
}
# ✅ OR: Use path from flake
{ ... }:
{
environment.systemPackages = [
(pkgs.callPackage ./local-packages/my-app { })
];
}
```
## Mistake 10: Not Using Flake References
### Symptom
Can't use packages from flake inputs.
### Cause
Not passing inputs or using wrong reference.
### Solution
Use `inputs.*` syntax.
```nix
# ❌ WRONG: Trying to use input package
{ pkgs, ... }:
{
environment.systemPackages = [
unfire-overlay # Where does this come from?
];
}
# ✅ CORRECT: Use input reference
{ pkgs, inputs, ... }:
{
environment.systemPackages = [
inputs.unfire-overlay.packages.${pkgs.system}.default
];
}
```
## Quick Checklist
Before committing config changes:
- [ ] Overlay in correct location for useGlobalPkgs setting
- [ ] inputs passed via specialArgs if needed
- [ ] Not editing hardware-configuration.nix
- [ ] No duplicate package declarations
- [ ] Following nixpkgs for dependency inputs
- [ ] System config separate from user config
- [ ] Tested with rebuild
- [ ] Using Nix paths, not absolute paths
- [ ] Correct input references for flake packages

View File

@@ -0,0 +1,188 @@
---
title: Flakes Configuration Structure
impact: CRITICAL
impactDescription: Foundation of flake-based NixOS configurations
tags: flakes,special-args,inputs,multiple-hosts
---
## Why This Matters
A well-structured flake.nix makes it easy to manage multiple hosts, share common configurations, and maintain the codebase. Poor structure leads to duplication and confusion.
## Core Structure
```nix
{
description = "My NixOS configuration";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
home-manager.url = "github:nix-community/home-manager/release-25.05";
home-manager.inputs.nixpkgs.follows = "nixpkgs";
# Add other flake inputs here
};
outputs = { self, nixpkgs, home-manager, ... }@inputs: {
nixosConfigurations.hostname = nixpkgs.lib.nixosSystem {
specialArgs = { inherit inputs; };
modules = [ ./hosts/hostname ];
};
};
}
```
## Special Args Pattern
Pass `inputs` via `specialArgs` to make flake inputs available in modules:
```nix
# ❌ WRONG: Forgetting specialArgs
outputs = { self, nixpkgs, home-manager }:
{
nixosConfigurations.myhost = nixpkgs.lib.nixosSystem {
modules = [ ./hosts/myhost ]; # inputs not available!
};
}
# ✅ CORRECT: Using specialArgs
outputs = { self, nixpkgs, home-manager, ... }@inputs:
{
nixosConfigurations.myhost = nixpkgs.lib.nixosSystem {
specialArgs = { inherit inputs; };
modules = [ ./hosts/myhost ]; # inputs available!
};
}
```
Then use in modules:
```nix
# hosts/myhost/default.nix
{ inputs, pkgs, ... }:
{
# Can now use inputs.*
imports = [
inputs.home-manager.nixosModules.home-manager
];
}
```
## Input Following
Set `inputs.nixpkgs.follows` to avoid duplicate nixpkgs instances:
```nix
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
# ❌ WRONG: Doesn't follow, creates duplicate nixpkgs
home-manager.url = "github:nix-community/home-manager/release-25.05";
# ✅ CORRECT: Follows nixpkgs, uses same instance
home-manager.url = "github:nix-community/home-manager/release-25.05";
home-manager.inputs.nixpkgs.follows = "nixpkgs";
};
```
## Multiple Hosts Pattern
```nix
outputs = { self, nixpkgs, home-manager, ... }@inputs: {
# Define multiple hosts
nixosConfigurations.laptop = nixpkgs.lib.nixosSystem {
specialArgs = { inherit inputs; };
modules = [ ./hosts/laptop ];
};
nixosConfigurations.desktop = nixpkgs.lib.nixosSystem {
specialArgs = { inherit inputs; };
modules = [ ./hosts/desktop ];
};
nixosConfigurations.server = nixpkgs.lib.nixosSystem {
specialArgs = { inherit inputs; };
modules = [ ./hosts/server ];
};
};
```
## System-Specific Packages
Pass system-specific args like `pkgs-stable`:
```nix
outputs = { self, nixpkgs, nixpkgs-stable, home-manager, ... }@inputs:
let
system = "x86_64-linux";
in
{
nixosConfigurations.myhost = nixpkgs.lib.nixosSystem {
specialArgs = {
inherit inputs system;
pkgs-stable = import inputs.nixpkgs-stable {
inherit system;
config.allowUnfree = true;
};
};
modules = [ ./hosts/myhost ];
};
};
```
Usage in host config:
```nix
# hosts/myhost/default.nix
{ inputs, pkgs, pkgs-stable, system, ... }:
{
environment.systemPackages = with pkgs; [
unstable-package # From nixos-unstable
];
# Or use stable version
environment.systemPackages = with pkgs-stable; [
stable-package
];
}
```
## Common Mistakes
1. **Not using @inputs pattern**: Forgetting to capture all inputs in a set makes it impossible to reference new inputs without updating the function signature.
2. **Missing specialArgs**: Inputs won't be available in modules without `specialArgs = { inherit inputs; }`.
3. **Hardcoded system**: Avoid hardcoding `x86_64-linux` multiple times. Define once and reuse.
4. **Not following nixpkgs**: Leads to multiple nixpkgs evaluations, slower builds, and potential inconsistencies.
## Quick Template
```nix
{
description = "NixOS configuration";
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
nixpkgs-stable.url = "github:nixos/nixpkgs/nixos-25.05";
home-manager.url = "github:nix-community/home-manager/release-25.05";
home-manager.inputs.nixpkgs.follows = "nixpkgs";
# Add more inputs here
};
outputs = { self, nixpkgs, home-manager, ... }@inputs: {
nixosConfigurations.myhost = nixpkgs.lib.nixosSystem {
specialArgs = {
inherit inputs;
system = "x86_64-linux";
pkgs-stable = import inputs.nixpkgs-stable {
inherit system;
config.allowUnfree = true;
};
};
modules = [ ./hosts/myhost ];
};
};
}
```

View File

@@ -0,0 +1,296 @@
---
title: Host Configuration Organization
impact: HIGH
impactDescription: Prevents configuration chaos across multiple hosts
tags: hosts,modules,base-config,directory-structure
---
## Why This Matters
Proper host configuration organization prevents duplication, makes maintenance easier, and ensures consistency across multiple machines.
## Directory Structure
```
nixos-config/
├── flake.nix # Top-level flake
├── hosts/
│ ├── laptop/
│ │ ├── default.nix # Host-specific config
│ │ ├── hardware-configuration.nix # Generated (don't edit)
│ │ └── home.nix # Home Manager config
│ ├── desktop/
│ │ ├── default.nix
│ │ ├── hardware-configuration.nix
│ │ └── home.nix
│ └── base.nix # Shared by all hosts (optional)
├── modules/ # Reusable NixOS modules
├── overlays/ # Custom overlays
├── home-manager/ # Shared Home Manager configs
│ ├── shell/
│ ├── applications/
│ └── common.nix
└── secrets/ # Age-encrypted secrets
```
## Host Configuration Pattern
### Incorrect: Everything in one file
```nix
# hosts/laptop/default.nix
{ config, pkgs, ... }:
{
# Hardware config (copied from hardware-configuration.nix)
boot.initrd.availableKernelModules = [ "xhci_pci" "nvme" "usb_storage" ];
# ... 50 lines of hardware config ...
# Network config
networking.hostName = "laptop";
networking.networkmanager.enable = true;
# User config
users.users.john = {
isNormalUser = true;
extraGroups = [ "wheel" "networkmanager" ];
};
# Packages
environment.systemPackages = with pkgs; [ vim git wget ];
# Services
services.openssh.enable = true;
# Home Manager
imports = [
./home.nix # Or inline the entire home config
];
}
```
**Problems:**
- Hardware config duplicated (should import hardware-configuration.nix)
- User config duplicated across hosts
- No shared configuration
- Hard to maintain
### Correct: Modular structure
```nix
# hosts/laptop/default.nix
{ inputs, pkgs, pkgs-stable, system, ... }:
{
imports = [
./hardware-configuration.nix # Import hardware config
../base.nix # Import shared config
inputs.home-manager.nixosModules.home-manager
{
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.users.john = import ./home.nix;
home-manager.extraSpecialArgs = {
inherit inputs pkgs-stable system;
};
nixpkgs.overlays = [ inputs.some-overlay.overlays.default ];
}
];
# Host-specific config only
networking.hostName = "laptop";
}
```
## Shared Base Configuration
```nix
# hosts/base.nix
{ config, pkgs, inputs, ... }:
{
# Network
networking.networkmanager.enable = true;
# Time and locale
time.timeZone = "America/New_York";
i18n.defaultLocale = "en_US.UTF-8";
# Users (shared across all hosts)
users.users.john = {
isNormalUser = true;
extraGroups = [ "wheel" "networkmanager" ];
};
# Common packages
environment.systemPackages = with pkgs; [
vim
git
wget
tmux
];
# Common services
services.openssh.enable = true;
# Nix settings
nix.settings.experimental-features = [ "nix-command" "flakes" ];
}
```
## Hardware Configuration
```nix
# hosts/laptop/default.nix
{ ... }:
{
imports = [
./hardware-configuration.nix # Generated by nixos-generate-config
../base.nix
# ...
];
networking.hostName = "laptop";
}
```
**Important:** Don't edit `hardware-configuration.nix` manually. It's generated by `nixos-generate-config` and should be replaced when hardware changes.
## Home Manager Configuration
### Host-specific home.nix
```nix
# hosts/laptop/home.nix
{ config, pkgs, inputs, ... }:
{
imports = [
../../home-manager/shell
../../home-manager/applications
../../home-manager/common.nix
];
# Host-specific user config
home.packages = with pkgs; [
laptop-specific-package
];
}
```
### Shared Home Manager configs
```nix
# home-manager/shell/default.nix
{ config, pkgs, ... }:
{
imports = [
./fish
./neovim
./git
];
}
# home-manager/common.nix
{ config, pkgs, ... }:
{
home.packages = with pkgs; [
jq
ripgrep
fzf
];
programs.git.enable = true;
programs.git.userName = "John Doe";
programs.git.userEmail = "john@example.com";
}
```
## Multiple Hosts Example
```nix
# flake.nix
outputs = { self, nixpkgs, home-manager, ... }@inputs: {
nixosConfigurations.laptop = nixpkgs.lib.nixosSystem {
specialArgs = { inherit inputs; };
modules = [ ./hosts/laptop ];
};
nixosConfigurations.desktop = nixpkgs.lib.nixosSystem {
specialArgs = { inherit inputs; };
modules = [ ./hosts/desktop ];
};
nixosConfigurations.server = nixpkgs.lib.nixosSystem {
specialArgs = { inherit inputs; };
modules = [ ./hosts/server ];
};
};
```
Each host uses the same `base.nix` but can override settings:
```nix
# hosts/server/default.nix
{ ... }:
{
imports = [ ../base.nix ./hardware-configuration.nix ];
# Override time zone for server
time.timeZone = "UTC";
# Add server-specific packages
environment.systemPackages = with pkgs; [
htop
iotop
];
}
```
## Module Pattern
For reusable functionality, create modules:
```nix
# modules/docker.nix
{ config, pkgs, ... }:
{
virtualisation.docker = {
enable = true;
enableOnBoot = true;
};
users.users.john.extraGroups = [ "docker" ];
}
```
Use in host config:
```nix
# hosts/laptop/default.nix
{ ... }:
{
imports = [
../base.nix
../../modules/docker # Import module
./hardware-configuration.nix
];
}
```
## Common Mistakes
1. **Editing hardware-configuration.nix**: Changes are lost when regenerating. Put host-specific config in `default.nix` instead.
2. **Duplicating config across hosts**: Use `base.nix` or modules for shared configuration.
3. **Not separating host-specific and user-specific**: Keep host config in `hosts/*/default.nix`, user config in `home.nix` or `home-manager/`.
4. **Mixing concerns**: Don't put shell config in system packages. Use Home Manager for user-level packages.
## Quick Checklist
- [ ] Each host imports hardware-configuration.nix
- [ ] Shared config in base.nix or modules
- [ ] Home Manager configured in host file
- [ ] Host-specific settings only in host's default.nix
- [ ] User config in home.nix or home-manager/
- [ ] No duplication of hardware config
- [ ] No duplication of user config

View File

@@ -0,0 +1,132 @@
---
title: Overlay Scope and useGlobalPkgs
impact: CRITICAL
impactDescription: The most common issue: overlays don't apply with useGlobalPkgs=true
tags: overlay,useglobalpkgs,home-manager,scope
---
## Why This Matters
When using Home Manager with NixOS, the `useGlobalPkgs` setting determines where overlay definitions must be placed. Defining overlays in the wrong location means they simply don't apply, leading to "package not found" errors even when the overlay syntax is correct.
## The Problem
When `useGlobalPkgs = true`, Home Manager uses NixOS's global `pkgs` instance. Overlays defined in `home.nix` are ignored because Home Manager isn't creating its own `pkgs` - it's using the system one.
## Incorrect: Overlay in home.nix with useGlobalPkgs=true
```nix
# hosts/home/default.nix
{
home-manager.useGlobalPkgs = true; # Using system pkgs
home-manager.useUserPackages = true;
home-manager.users.chumeng = import ./home.nix;
}
# home-manager/home.nix
{ config, pkgs, inputs, ... }:
{
# ❌ This overlay is IGNORED when useGlobalPkgs = true!
nixpkgs.overlays = [ inputs.claude-code.overlays.default ];
home.packages = with pkgs; [
claude-code # Error: attribute 'claude-code' not found
];
}
```
**Why it fails:** When `useGlobalPkgs = true`, the `nixpkgs.overlays` line in `home.nix` has no effect. Home Manager isn't creating its own `pkgs`, so it can't apply overlays to one.
## Correct: Overlay in host home-manager block
```nix
# hosts/home/default.nix
{
home-manager.useGlobalPkgs = true;
home-manager.useUserPackages = true;
home-manager.users.chumeng = import ./home.nix;
home-manager.extraSpecialArgs = { inherit inputs pkgs-stable system; };
# ✅ Overlay defined HERE affects the global pkgs
nixpkgs.overlays = [ inputs.claude-code.overlays.default ];
}
# home-manager/home.nix
{ config, pkgs, ... }:
{
# No overlay definition needed here
home.packages = with pkgs; [
claude-code # ✅ Works! Found via overlay
];
}
```
**Why it works:** The overlay is defined where Home Manager configures the `pkgs` instance it will use. When `useGlobalPkgs = true`, this means the overlay is applied to the system's package set.
## Alternative: Set useGlobalPkgs=false
If you want to define overlays in `home.nix`, set `useGlobalPkgs = false`:
```nix
# hosts/home/default.nix
{
home-manager.useGlobalPkgs = false; # Home Manager creates own pkgs
home-manager.useUserPackages = true;
home-manager.users.chumeng = import ./home.nix;
}
# home-manager/home.nix
{ pkgs, inputs, ... }:
{
# ✅ This works when useGlobalPkgs = false
nixpkgs.overlays = [ inputs.claude-code.overlays.default ];
home.packages = with pkgs; [
claude-code # ✅ Works! Found via overlay
];
}
```
**Trade-off:** This creates a separate package set for Home Manager, which means packages are built twice (once for system, once for Home Manager). Only use this when you truly need separate package sets.
## Decision Matrix
| Your Need | useGlobalPkgs | Overlay Location |
|-----------|---------------|------------------|
| Single-user system, efficiency | `true` | Host home-manager block |
| Multi-user, different packages per user | `false` | User's home.nix |
| Custom packages system-wide | `true` | System nixpkgs.overlays |
| Quick prototype | `false` | User's home.nix |
## Verification
After adding an overlay, verify it works:
```bash
# Build the configuration
nixos-rebuild build --flake .#hostname
# Check if package is available
./result/sw/bin/package-name --version
# Or use nix repl to verify
nix repl
nix-repl> :l flake.nix
nix-repl> homeConfigs.hostname.config.home-manager.users.username.pkgs.package-name
```
## Common Mistakes
1. **Adding overlay both places**: Don't define the same overlay in both host config AND home.nix. It will apply twice and may cause conflicts.
2. **Forgetting to pass inputs**: If your overlay needs `inputs.*`, ensure `inputs` is in `extraSpecialArgs`:
```nix
home-manager.extraSpecialArgs = { inherit inputs; };
```
3. **Not rebuilding system**: Overlays defined in host config require full system rebuild, not just `home-manager switch`.
## References
- [Home Manager Manual - useGlobalPkgs](https://nix-community.github.io/home-manager/options.html#opt-home-manager.useGlobalPkgs)
- [NixOS Manual - Overlays](https://nixos.org/manual/nixos/stable/options#opt-nixpkgs.overlays)

View File

@@ -0,0 +1,264 @@
---
title: Package Installation Best Practices
impact: HIGH
impactDescription: Avoids conflicts and confusion about where to install packages
tags: packages,system,user,home-manager
---
## Why This Matters
Knowing where and how to install packages prevents conflicts, ensures proper updates, and maintains separation between system and user packages.
## System vs User Packages
### System Packages (NixOS)
Use for:
- System services (servers, daemons)
- Packages needed by all users
- Hardware-related packages (drivers, firmware)
- System-wide utilities
```nix
# hosts/base.nix or host-specific default.nix
{ config, pkgs, ... }:
{
environment.systemPackages = with pkgs; [
vim # Available to all users
git
wget
tmux
];
}
```
### User Packages (Home Manager)
Use for:
- User-specific applications
- Desktop applications
- Development tools (user-specific)
- Shell configurations
```nix
# home-manager/home.nix or sub-configs
{ config, pkgs, ... }:
{
home.packages = with pkgs; [
vscode # User-specific
chrome
slack
];
}
```
## Installing from Different Nixpkgs Channels
### Using unstable packages
```nix
# flake.nix - default is unstable
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
nixpkgs-stable.url = "github:nixos/nixpkgs/nixos-25.05";
};
# Host config
{ pkgs, pkgs-stable, ... }:
{
environment.systemPackages = with pkgs; [
vim # From unstable (default)
];
environment.systemPackages = with pkgs-stable; [
vim # From stable
];
}
```
### Using overlays for custom packages
```nix
# hosts/home/default.nix
{
nixpkgs.overlays = [
inputs.custom-overlay.overlays.default
];
}
# Now packages from overlay are available
{ pkgs, ... }:
{
home.packages = with pkgs; [
custom-package # From overlay
];
}
```
## Conditional Package Installation
### Based on host
```nix
# hosts/laptop/default.nix
{ config, pkgs, ... }:
{
environment.systemPackages = with pkgs; [
powertop # Laptop-specific
];
}
```
### Based on GUI environment
```nix
# hosts/base.nix
{ config, pkgs, ... }:
{
environment.systemPackages = with pkgs;
(if config.services.xserver.enable then [
firefox
dmenu
] else [
tmux
htop
]);
}
```
### Based on architecture
```nix
{ config, pkgs, ... }:
{
environment.systemPackages = with pkgs;
(if pkgs.system == "x86_64-linux" then [
docker-compose
] else [
podman
]);
}
```
## Wrapper Scripts
Modify package behavior with wrappers:
```nix
{ pkgs, ... }:
{
environment.systemPackages = with pkgs; [
(symlinkJoin {
name = "google-chrome-with-flags";
paths = [ google-chrome ];
buildInputs = [ makeWrapper ];
postBuild = ''
wrapProgram $out/bin/google-chrome-stable \
--add-flags "--disable-gpu" \
--add-flags "--disable-features=UseChromeOSDirectVideoDecoder"
'';
})
];
}
```
## Common Mistakes
### Installing user packages system-wide
```nix
# ❌ WRONG: User-specific package in system config
environment.systemPackages = with pkgs; [
vscode # Should be in Home Manager
slack # Should be in Home Manager
];
# ✅ CORRECT: User packages in Home Manager
# home-manager/home.nix
home.packages = with pkgs; [
vscode
slack
];
```
### Installing packages in wrong location
```nix
# ❌ WRONG: System package in Home Manager
# home-manager/home.nix
home.packages = with pkgs; [
docker # Should be system package (needs service)
];
# ✅ CORRECT: System package in system config
# hosts/base.nix
environment.systemPackages = with pkgs; [
docker
];
virtualisation.docker.enable = true;
```
### Not using lists for multiple packages
```nix
# ❌ WRONG: Individual statements
environment.systemPackages = [ pkgs.vim ];
environment.systemPackages = [ pkgs.git ]; # Overwrites previous!
# ✅ CORRECT: Single list
environment.systemPackages = with pkgs; [
vim
git
];
```
## Package Updates
### Update all packages
```bash
nix flake update
nixos-rebuild switch --flake .#hostname
```
### Update specific input
```bash
nix flake lock update-input nixpkgs
nixos-rebuild switch --flake .#hostname
```
### Pin to specific version
```nix
# flake.nix
inputs = {
nixpkgs.url = "github:nixos/nixpkgs/nixos-25.05"; # Pinned to release
# Or specific commit:
# nixpkgs.url = "github:nixos/nixpkgs/a1b2c3d...";
};
```
## Finding Packages
```bash
# Search for package
nix search nixpkgs package-name
# Get package info
nix eval nixpkgs#legacyPackages.x86_64-linux.package-name.meta.description
# Check what package provides a file
nix-locate bin/vim
```
## Quick Reference
| Package Type | Location | Example |
|-------------|----------|---------|
| System service | system config | `virtualisation.docker.enable = true` |
| System utility | system config | `environment.systemPackages = [ vim ]` |
| User app | Home Manager | `home.packages = [ vscode ]` |
| Development tool | Either (user usually) | `home.packages = [ nodejs ]` |
| Driver/firmware | system config | `hardware.graphics.enable = true` |

View File

@@ -0,0 +1,326 @@
---
title: Troubleshooting Configuration Issues
impact: MEDIUM
impactDescription: Systematic debugging approach for configuration issues
tags: debugging,errors,troubleshooting,verification
---
## Why This Matters
Knowing how to systematically debug NixOS configurations saves hours of frustration and prevents making random changes hoping something works.
## General Approach
Follow this order when debugging:
1. **Read error messages completely** - They usually tell you exactly what's wrong
2. **Verify syntax** - Check for missing brackets, quotes, commas
3. **Validate config** - Use `nixos-rebuild test` first
4. **Check scope** - Is overlay/module in correct location?
5. **Trace dependencies** - Are required inputs/imports present?
## Common Error Patterns
### "undefined variable 'inputs'"
**Cause:** `inputs` not passed via `specialArgs`.
**Fix:**
```nix
# flake.nix
outputs = { self, nixpkgs, ... }@inputs:
{
nixosConfigurations.myhost = nixpkgs.lib.nixosSystem {
specialArgs = { inherit inputs; }; # Add this
modules = [ ./hosts/myhost ];
};
};
```
### "attribute 'package-name' not found"
**Cause:** Package doesn't exist, or overlay not applied.
**Debug:**
```bash
# Check if package exists in nixpkgs
nix search nixpkgs package-name
# Check if overlay is defined
nix eval .#nixosConfigurations.myhost.config.nixpkgs.overlays
# Verify package in your config's pkgs
nix repl
nix-repl> :l flake.nix
nix-repl> myhost.config.environment.systemPackages
```
**Fix:**
- If overlay issue: Move to correct location (see [overlay-scope.md](overlay-scope.md))
- If missing package: Use correct package name or add overlay
### "error: The option 'some.option' does not exist"
**Cause:** Typo in option name, or option not available in your nixpkgs version.
**Debug:**
```bash
# Search for option
nixos-options | grep some-option
# Check option in current config
nix eval .#nixosConfigurations.myhost.config.some.option
```
**Fix:**
- Check option name spelling
- Verify nixpkgs version has this option
- Read option documentation for correct usage
### "infinite recursion"
**Cause:** Circular dependency in config.
**Debug:**
```bash
# Use --show-trace to see where
nixos-rebuild build --flake .#hostname --show-trace
```
**Fix:**
- Look for mutual dependencies
- Use `mkBefore`/`mkAfter` for ordering
- Break circular reference
### "hash mismatch" in flake.lock
**Cause:** Local changes or outdated lock file.
**Fix:**
```bash
# Update flake lock
nix flake update
# Or update specific input
nix flake lock update-input nixpkgs
```
## Overlay Not Applied
**Symptom:** Package from overlay not found.
**Debug steps:**
1. Check overlay definition:
```bash
nix eval .#nixosConfigurations.myhost.config.nixpkgs.overlays
```
2. Check overlay location:
```bash
# If useGlobalPkgs = true, overlay should be here:
grep -r "nixpkgs.overlays" hosts/myhost/default.nix
# NOT here:
grep -r "nixpkgs.overlays" home-manager/home.nix
```
3. Verify overlay input:
```bash
nix flake metadata
# Look for your overlay input
```
**Fix:** See [overlay-scope.md](overlay-scope.md)
## Configuration Changes Not Applying
**Symptom:** Edit config, rebuild, but nothing changes.
**Debug steps:**
1. Verify rebuild ran successfully:
```bash
sudo nixos-rebuild switch --flake .#hostname
# Look for "success" message
```
2. Check current generation:
```bash
sudo nix-env --list-generations --profile /nix/var/nix/profiles/system
```
3. Verify new generation is active:
```bash
sudo nixos-version
# Should show timestamp of recent rebuild
```
4. Check if option actually changed:
```bash
nix eval .#nixosConfigurations.myhost.config.some.option
```
**Fix:**
- Ensure rebuild succeeded
- Check if service needs restart: `systemctl restart service-name`
- For Home Manager: `home-manager switch` (or `sudo nixos-rebuild switch` if integrated)
## Build Fails with "store collision"
**Symptom:** Multiple packages trying to write to same path.
**Cause:** Usually duplicate package declarations or conflicting modules.
**Fix:**
- Remove duplicate package declarations
- Check for conflicting modules
- Use `--show-trace` to identify conflicting packages
## Verification Commands
### Check configuration without building
```bash
# Check syntax
nix flake check
# Dry run build
nixos-rebuild build --flake .#hostname --dry-run
# Evaluate specific option
nix eval .#nixosConfigurations.myhost.config.environment.systemPackages
```
### Test configuration safely
```bash
# Build without activating
nixos-rebuild build --flake .#hostname
# Test configuration (rollback on reboot)
nixos-rebuild test --flake .#hostname
# Switch (persistent)
nixos-rebuild switch --flake .#hostname
```
### Compare generations
```bash
# List system generations
sudo nix-env --list-generations --profile /nix/var/nix/profiles/system
# List Home Manager generations
home-manager generations
# Compare configurations
sudo nix diff-closures /nix/var/nix/profiles/system-*-link
```
## Useful Tools
### nix repl
```bash
nix repl
nix-repl> :l flake.nix # Load flake
nix-repl> myhost.config.environment.systemPackages # Access config
nix-repl> :b myhost.config.system.build.toplevel # Build
```
### nixos-version
```bash
# Check current system version
nixos-version
# Should show something like:
# 25.05.20250123.abc1234
```
### journalctl
```bash
# Check service logs for failures
sudo journalctl -xe
# Check NixOS rebuild logs
sudo journalctl -u nixos-rebuild
```
## Getting Help
When asking for help, provide:
1. **Full error message** (not just "it doesn't work")
2. **Minimal reproducible example**
3. **NixOS version**: `nixos-version`
4. **Relevant config files**
5. **What you've tried**
6. **Expected vs actual behavior**
Useful commands:
```bash
# Show system info
nixos-version
uname -a
# Show flake info
nix flake metadata
# Export config for sharing
nixos-rebuild build --flake .#hostname
nix-store -qR result > system-closure
```
## Common Debugging Workflows
### Package not found
```bash
# 1. Search for package
nix search nixpkgs package-name
# 2. Check if it's available for your system
nix eval nixpkgs#legacyPackages.x86_64-linux.package-name
# 3. Check your overlays
nix eval .#nixosConfigurations.myhost.config.nixpkgs.overlays
# 4. Check if overlay provides it
nix eval .#packages.x86_64-linux.package-name
```
### Overlay not applying
```bash
# 1. Verify overlay is defined
grep -r "overlays" hosts/myhost/
# 2. Check useGlobalPkgs setting
grep "useGlobalPkgs" hosts/myhost/default.nix
# 3. Evaluate overlay
nix eval .#nixosConfigurations.myhost.config.nixpkgs.overlays
# 4. Test package directly
nix build .#packages.x86_64-linux.package-name
```
### Service not starting
```bash
# 1. Check service status
systemctl status service-name
# 2. View service logs
journalctl -xeu service-name
# 3. Check service config
nixos-rebuild build --flake .#hostname --show-trace
# 4. Test service manually
/path/to/service-binary --verbose
```

1
.roo/skills/find-skills Symbolic link
View File

@@ -0,0 +1 @@
../../.agents/skills/find-skills

View File

@@ -0,0 +1 @@
../../.agents/skills/nix-best-practices

View File

@@ -0,0 +1 @@
../../.agents/skills/nixos-best-practices