Files
nixos-config/AGENTS.md

16 KiB

Agent Instructions

This project uses bd (beads) for issue tracking. Run bd prime for full workflow context.

Quick Reference

bd ready              # Find available work
bd show <id>          # View issue details
bd update <id> --claim  # Claim work atomically
bd close <id>         # Complete work
bd dolt push          # Push beads data to remote

Non-Interactive Shell Commands

ALWAYS use non-interactive flags with file operations to avoid hanging on confirmation prompts.

Shell commands like cp, mv, and rm may be aliased to include -i (interactive) mode on some systems, causing the agent to hang indefinitely waiting for y/n input.

Use these forms instead:

# Force overwrite without prompting
cp -f source dest           # NOT: cp source dest
mv -f source dest           # NOT: mv source dest
rm -f file                  # NOT: rm file

# For recursive operations
rm -rf directory            # NOT: rm -r directory
cp -rf source dest          # NOT: cp -r source dest

Other commands that may prompt:

  • scp - use -o BatchMode=yes for non-interactive
  • ssh - use -o BatchMode=yes to fail instead of prompting
  • apt-get - use -y flag
  • brew - use HOMEBREW_NO_AUTO_UPDATE=1 env var

Beads Issue Tracker

This project uses bd (beads) for persistent task tracking. Run bd prime for full workflow context.

Why Beads?

  • Prefer Beads over ad-hoc markdown TODO lists — Beads provides structured, queryable, shareable issue tracking with dependency management
  • Never use bd edit — it opens an interactive editor which blocks agent workflows
  • Use flags and stdin insteadbd update <id> --claim, bd create --title "..." --estimate 2

Slash Commands (Agent Workflow)

Command Purpose
/beads:ready Find unblocked issues
/beads:create Create a new issue
/beads:update Update an issue (claim, status)
/beads:close Close completed work
/beads:stats Project-level snapshot

Core Workflow (6 Steps)

1. Find Unblocked Work

bd ready --json

Lists issues with no blocking dependencies that are ready to work on.

2. Claim Work

bd update <id> --claim

Atomically assigns the issue to you (sets status to "in-progress").

3. Inspect Details

bd show <id>

View full issue details including:

  • Description and acceptance criteria
  • Blocking/blocked-by dependencies
  • Time estimates
  • Status history

4. Create Newly Discovered Work

# Create a new issue
bd create \
  --title "Fix audio on m3-helios" \
  --estimate 2 \
  --priority high \
  --labels nixos,audio

# Link dependencies
bd dep <id> --blocks <blocked-id>      # This issue blocks another
bd dep <id> --after <after-id>         # This issue after another completes
bd dep <id> --requires <requires-id>  # This issue requires another

5. Complete Work

bd close <id> --reason "Added PulseAudio fallback to configuration.nix"

Provide a concise summary of what was done. The --reason is mandatory.

6. Project Snapshot

bd status --json    # Current state of all issues
bd stats            # Metrics: velocity, cycle time, bottlenecks

Example Complete Workflow

# Start session - find work
bd ready --json

# Claim available issue
bd update 42 --claim

# Do the work...

# Discover something else needed
bd create --title "Document hermes-agent setup" --estimate 1
# Link as related
bd dep 43 --after 42

# Complete original
bd close 42 --reason "Added Hyprland idle timeout config"

# Close related
bd close 43 --reason "Added setup docs to AGENTS.md"

# Push state to remote
bd dolt push

Rules

  • Use bd for ALL task tracking — do NOT use TodoWrite, TaskCreate, or markdown TODO lists
  • Run bd prime for detailed command reference and session close protocol
  • Use bd remember for persistent knowledge — do NOT use MEMORY.md files

Session Completion

When ending a work session, you MUST complete ALL steps below. Work is NOT complete until git push succeeds.

MANDATORY WORKFLOW:

  1. File issues for remaining work - Create issues for anything that needs follow-up
  2. Run quality gates (if code changed) - Tests, linters, builds
  3. Update issue status - Close finished work, update in-progress items
  4. PUSH TO REMOTE - This is MANDATORY:
    git pull --rebase
    bd dolt push
    git push
    git status  # MUST show "up to date with origin"
    
  5. Clean up - Clear stashes, prune remote branches
  6. Verify - All changes committed AND pushed
  7. Hand off - Provide context for next session

CRITICAL RULES:

  • Work is NOT complete until git push succeeds
  • NEVER stop before pushing - that leaves work stranded locally
  • NEVER say "ready to push when you are" - YOU must push
  • If push fails, resolve and retry until it succeeds

Project Agent

Workspace Path: /home/m3tam3re/p/NIX/nixos-config (Note to Pi: Your file write/edit tools run in a different directory by default. You MUST use absolute paths starting with the Workspace Path above for ALL file operations!)

Generated: 2026-04-26


Stack

Component Version/Source
Nixpkgs nixos-unstable + 25.05 stable
Home Manager github:nix-community/home-manager
m3ta-home code.m3ta.dev/m3tam3re/m3ta-home
m3ta-nixpkgs code.m3ta.dev/m3tam3re/nixpkgs
Agenix github:ryantm/agenix
Disko github:nix-community/disko
NUR github:nix-community/NUR
Formatter alejandra
Linters statix, deadnix
IDE nixd
Hermes Agent NousResearch/hermes-agent
LLM Agents numtide/llm-agents.nix

Structure

nixos-config/
├── flake.nix                    # Entry point: hosts, overlays, dev shells, m3ta-home input
├── coding-rules.json            # Opencode rules configuration
│
├── hosts/                        # Per-host NixOS configurations
│   ├── common/                   # Shared across all hosts
│   │   ├── users/
│   │   │   └── m3tam3re.nix     # ← Central user + m3ta-home integration
│   │   ├── default.nix          # Shared NixOS settings, overlays, home-manager setup
│   │   ├── ports.nix            # Network ports config
│   │   └── extraServices/       # Common service toggles
│   ├── m3-ares/                  # TUXEDO laptop (desktop)
│   │   └── home.nix             # Hyprland: eDP-1 + HDMI, XDG/MIME
│   ├── m3-kratos/                # AMD desktop (desktop)
│   │   └── home.nix             # Hyprland: dual DP, XDG/MIME
│   ├── m3-daedalus/              # Portable laptop (desktop, no Hyprland)
│   │   └── home.nix             # XDG/MIME only
│   ├── m3-atlas/                 # Primary server (server + coding)
│   ├── m3-helios/                # AdGuard DNS server (minimal server)
│   ├── m3-hermes/                # Secondary server (minimal server)
│   └── m3-aether/                # Cloud VM (minimal server)
│
├── modules/                      # Reusable NixOS modules
│   └── nixos/                    # NixOS-specific modules
│
├── overlays/                    # Package overlays (stable/locked/master/pinned)
│   ├── default.nix
│   └── mods/
│
├── pkgs/                        # Custom packages
│
├── secrets/                     # Encrypted secrets (agenix)
│   └── secrets.nix
│
├── .opencode-rules/             # Opencode AI rules
│   ├── concerns/
│   ├── languages/nix.md
│   └── USAGE.md
│
└── .pi/                         # Agent configuration

Home-Manager Integration

Home-Manager configs are managed centrally in the m3ta-home repository:

  • Repo: code.m3ta.dev/m3tam3re/m3ta-home
  • Docs: See m3ta-home README for full documentation

What lives where:

Concern Location Why
Shell, CLI tools, editors, apps m3ta-home/profiles/ Portable across all hosts
User identity (git, SSH, JJ) m3ta-home/users/ Switchable: private vs work
Feature flags (enable/disable) nixos-config/hosts/common/users/m3tam3re.nix Per-host decisions
Monitor layouts, window rules nixos-config/hosts/<name>/home.nix Hardware-specific
XDG/MIME defaults nixos-config/hosts/<name>/home.nix Host-specific preferences
NixOS overlays nixos-config/overlays/ System-level package management

Host → Profile Mapping

Defined in hosts/common/users/m3tam3re.nix:

hostProfiles = {
  # Desktop hosts
  m3-ares     = { context = "desktop"; sets = ["coding" "gaming" "media"]; };
  m3-kratos   = { context = "desktop"; sets = ["coding" "gaming" "media"]; };
  m3-daedalus = { context = "desktop"; sets = ["coding" "media"]; };
  # Server hosts
  m3-atlas    = { context = "server";  sets = ["coding"]; };
  m3-helios   = { context = "server";  sets = []; };
  m3-hermes   = { context = "server";  sets = []; };
  m3-aether   = { context = "server";  sets = []; };
};

Work Identity Use Case

The same m3ta-home repo supports a work identity for company machines:

# On a work NixOS machine:
(m3ta-lib.mkHome {
  user = "m3tam3re";
  identity = "work";       # ← switches git to sascha.koenig, SSH to AZ hosts
  context = "desktop";
  sets = ["coding"];
})

This provides the familiar shell/editor/CLI setup but with work git credentials and SSH configuration.


Commands

Action Command Notes
Enter dev shell nix develop Includes alejandra, nixd, agenix, statix, deadnix
Build host sudo nixos-rebuild switch --flake .#m3-ares Replace hostname as needed
Dry run build sudo nixos-rebuild dry-run --flake .#m3-ares Validate without applying
List hosts nix flake show Shows all NixOS configurations
Update flake sudo nixos-rebuild switch --flake .#m3-ares --update-input nixpkgs Update specific input
Format code alejandra . Run before committing
Check lint statix check . Run statix for antipatterns
Remove dead code deadnix -w . Clean up unused let bindings
Build ISO nix build .#nixosConfigurations.m3-ares.config.system.build.isoImage Generate install ISO

Conventions

Formatting & Style

  • Formatter: alejandra (mandatory, run before commits)
  • Indentation: 2 spaces (alejandra default)
  • Variables: camelCase (e.g., maxRetryAttempts)
  • Types/Modules: PascalCase (e.g., MyService)
  • Constants: UPPER_SNAKE_CASE (e.g., MAX_RETRIES)
  • Files: hyphen-case (e.g., my-file.nix)

Nix Module Patterns

{ config, lib, pkgs, ... }:
{
  options.myService.enable = lib.mkEnableOption "my service";
  config = lib.mkIf config.myService.enable {
    services.myService.enable = true;
  };
}

Conditionals

config = lib.mkMerge [
  (lib.mkIf cfg.enable { ... })
  (lib.mkIf cfg.extraConfig { ... })
];

Anti-Patterns (AVOID)

  • Never use with pkgs; — always use explicit package references
  • Never use builtins.fetchTarball — use flake inputs instead
  • Never use import <nixpkgs> — always use inputs
  • Never use builtins.getAttr/hasAttr — use lib.attrByPath or lib.optionalAttrs
  • Avoid anonymous functions in config — extract to named lets

Imports

  • Use flake inputs for dependencies (e.g., inputs.home-manager.nixosModules.home-manager)
  • Import relative paths with ./ or ../
  • Never use absolute paths in imports

Secrets

  • Secrets managed via agenix in secrets/ directory
  • Never commit plaintext secrets
  • Use .nix extension for secret files

Flake Input URLs

All code.m3ta.dev inputs use SSH URLs:

url = "git+ssh://gitea@code.m3ta.dev/m3tam3re/<repo>";

Anonymous HTTPS git on Gitea is unreliable and prompts for auth. SSH works with configured keys.


Key Files

File Purpose
flake.nix Central entry point defining all hosts, overlays, packages, dev shells, and nixpkgs config
hosts/common/default.nix Shared Nix settings, nixpkgs overlays, home-manager setup (useGlobalPkgs = true)
hosts/common/users/m3tam3re.nix User definition + m3ta-home mkHome integration + per-host feature flags
hosts/<name>/home.nix Host-specific overrides: monitors, workspaces, window rules, XDG/MIME
overlays/default.nix Package version overrides (stable/locked/master branches)
.opencode-rules/languages/nix.md Nix-specific conventions and patterns

What to Avoid

  1. Don't modify flake.lock directly — use nix flake update
  2. Don't use impure operations — this is a pure flake-based config
  3. Don't commit without formatting — always run alejandra . first
  4. Don't add packages to hosts directly — prefer adding to overlays or using NUR
  5. Don't hardcode paths — use inputs and relative imports
  6. Don't create monolithic modules — keep functions under 20 lines
  7. Don't skip the dry-run — always test with --dry-run before switching
  8. Don't use lib.mkDefault lightly — understand the precedence implications

Notes

Adding a New Host

  1. Add entry to flake.nixnixosConfigurations
  2. Create directory in hosts/ with:
    • default.nix — imports common + specific configs
    • configuration.nix — host-specific system config
    • hardware-configuration.nix — from nixos-generate-config
    • programs.nix, services/, secrets.nix as needed
  3. Add entry to hostProfiles in hosts/common/users/m3tam3re.nix
  4. Add feature flags in the hostFlags section
  5. Create hosts/<name>/home.nix if the host needs monitor/XDG overrides
  6. Run sudo nixos-generate-config --dir ./hosts/new-host first time

Adding a New Package

  1. For simple packages: add to appropriate overlay in overlays/default.nix
  2. For complex packages: create in pkgs/ directory
  3. For upstream packages: use NUR or add as flake input

Adding a New Home-Manager Feature

  1. Create the module in m3ta-home under the appropriate profile directory
  2. Add the import to the parent default.nix in m3ta-home
  3. Enable it per-host via feature flags in hosts/common/users/m3tam3re.nix

Development Workflow

  1. Edit config files
  2. Run alejandra . to format
  3. Run statix check . for linting
  4. Run sudo nixos-rebuild dry-run --flake .#m3-ares
  5. If successful: sudo nixos-rebuild switch --flake .#m3-ares

Remote Building

# Build on remote machine
nix copy --to ssh://user@host .#nixosConfigurations.m3-ares.config.system.build.toplevel
ssh user@host 'sudo nixos-rebuild switch --flake /nix/store/...-closure'