3.9 KiB
CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
What This Is
A NixOS flake managing multiple machines. All machines import /common for shared config, and each machine has its own directory under /machines/<hostname>/ with a default.nix (machine-specific config), hardware-configuration.nix, and properties.nix (metadata: hostnames, arch, roles, SSH keys).
Common Commands
# Build a machine config (check for errors without deploying)
nix build .#nixosConfigurations.<hostname>.config.system.build.toplevel --no-link
# Deploy to local machine (user must run this themselves - requires privileges)
doas nixos-rebuild switch --flake .
# Deploy to a remote machine (boot-only, no activate)
deploy --remote-build --boot --debug-logs --skip-checks .#<hostname>
# Deploy to a remote machine (activate immediately)
deploy --remote-build --debug-logs --skip-checks .#<hostname>
# Update flake lockfile
make update-lockfile
# Update a single flake input
make update-input <input-name>
# Edit an agenix secret
make edit-secret <secret-filename>
# Rekey all secrets (after adding/removing machine host keys)
make rekey-secrets
Architecture
Machine Discovery (Auto-Registration)
Machines are not listed in flake.nix. Instead, common/machine-info/default.nix recursively scans /machines/ for any properties.nix file and auto-registers that directory as a machine. To add a machine, create machines/<name>/properties.nix and machines/<name>/default.nix.
properties.nix returns a plain attrset (no NixOS module args) with: hostNames, arch, systemRoles, hostKey, and optionally userKeys, deployKeys, remoteUnlock.
Role System
Each machine declares systemRoles in its properties.nix (e.g., ["personal" "dns-challenge"]). Roles drive conditional config:
config.thisMachine.hasRole.<role>- boolean, used to conditionally enable features (e.g.,de.enableforpersonalrole)config.machines.withRole.<role>- list of hostnames with that role- Roles also determine which machines can decrypt which agenix secrets (see
secrets/secrets.nix)
Secrets (agenix)
Secrets in /secrets/ are encrypted .age files. secrets.nix maps each secret to the SSH host keys (by role) that can decrypt it. After changing which machines have access, run make rekey-secrets.
Sandboxed Workspaces
common/sandboxed-workspace/ provides isolated dev environments. Three backends: vm (microvm/cloud-hypervisor), container (systemd-nspawn), incus. Workspaces are defined in machine default.nix files and their per-workspace config goes in machines/<hostname>/workspaces/<name>.nix. The base config (base.nix) handles networking, SSH, user setup, and Claude Code pre-configuration.
IP allocation convention: VMs .10-.49, containers .50-.89, incus .90-.129 in 192.168.83.0/24.
Backups
common/backups.nix defines a backup.group option. Machines declare backup groups with paths; restic handles daily backups to Backblaze B2 with automatic ZFS/btrfs snapshot support. Each group gets a restic_<group> CLI wrapper for manual operations.
Nixpkgs Patching
flake.nix applies patches from /patches/ to nixpkgs before building (workaround for nix#3920).
Key Conventions
- Uses
doasinstead ofsudoeverywhere - Fish shell is the default user shell
- Home Manager is used for user-level config (
home/googlebot.nix) lib/default.nixextends nixpkgs lib with custom utility functions (extends vianixpkgs.lib.extend)- Overlays are in
/overlays/and applied globally viaflake.nix - The Nix formatter for this project is
nixpkgs-fmt - Do not add "Co-Authored-By" lines to commit messages
- Always use
--no-linkwhen runningnix build - Don't use
nix build --dry-rununless you only need evaluation — it skips the actual build - Avoid
2>&1on nix commands — it can cause error output to be missed