This guide covers day-to-day operations with your Nix-powered dev-config environment. After initial setup, these are the tasks you'll perform regularly.
When you cd into dev-config, direnv automatically activates the Nix environment:
cd ~/Projects/dev-config
# 🔐 Loading AI credentials from 1Password...
# ✓ Loaded: ANTHROPIC_API_KEY
# ✓ Loaded: OPENAI_API_KEY
# ✓ Loaded: GOOGLE_AI_API_KEY
# ✅ AI credentials loaded from 1PasswordWhat happened:
- direnv detected
.envrc - Loaded
nix develop(all packages available) - Sourced
scripts/load-ai-credentials.sh - Exported AI credentials from 1Password
Verify environment:
which nvim # Should show /nix/store/.../bin/nvim
which claude # Should show Claude Code CLI location
echo $ANTHROPIC_API_KEY # Should show your API keyIf direnv is not set up:
cd ~/Projects/dev-config
nix developTo load credentials manually:
source scripts/load-ai-credentials.shUpdate all packages to latest versions:
cd ~/Projects/dev-config
nix flake updateThis updates flake.lock with latest package versions from nixpkgs.
View what changed:
git diff flake.lockTest updated environment:
nix develop
nvim --version # Check Neovim version
tmux -V # Check tmux versionCommit updated lock file:
git add flake.lock
git commit -m "chore: update Nix flake inputs"
git push origin mainEdit flake.nix:
nvim flake.nixNote: Packages are centrally managed in pkgs/default.nix (single source of truth).
Add package to appropriate category in pkgs/default.nix:
# pkgs/default.nix
{pkgs}: {
# ... existing categories ...
# Add to relevant category
data = [
pkgs.jq
pkgs.yq-go
pkgs.postgresql # NEW: Add PostgreSQL client
];
# ... rest of file ...
}Rebuild environment:
nix flake check # Validate syntax
nix develop # Enter new environmentVerify package installed:
which psql # Should show /nix/store/.../bin/psqlCommit changes:
git add pkgs/default.nix
git commit -m "feat: add PostgreSQL client to data tools"
git push origin mainEdit pkgs/default.nix:
# pkgs/default.nix
{pkgs}: {
# ... existing categories ...
core = [
pkgs.git
pkgs.zsh
# Removed: pkgs.docker (if you no longer need it)
pkgs.neovim
pkgs.tmux
];
# ... rest of file ...
}Rebuild and test:
nix develop
which docker # Should return "not found"Example: Modify Neovim config
nvim ~/Projects/dev-config/nvim/init.lua
# Make changes...Apply changes:
# No rebuild needed! Configs are symlinked.
# Just restart Neovim to see changes.
nvimCommit changes:
git add nvim/init.lua
git commit -m "feat(nvim): add new keybinding"
git push origin mainWhen to rerun:
- Added new dotfiles to flake.nix
- Changed symlink structure
- Need to reinstall Oh My Zsh or TPM
Rerun activation:
nix run .#activateThis recreates symlinks and reinstalls plugins without breaking existing setup.
If update broke something:
# View generation history
nix profile history
# Output:
# Version 42 (current) - 2025-01-18
# Version 41 - 2025-01-15
# Version 40 - 2025-01-10
# Rollback to previous generation
nix profile rollback
# Or rollback to specific generation
nix profile switch-generation 40Rollback flake.lock:
git log --oneline flake.lock # Find commit hash before update
git checkout <commit-hash> flake.lock
nix develop # Uses older package versionsStart your development day:
cd ~/Projects/dev-config # Auto-activates Nix + credentials
tmux new -s dev # Start tmux session
nvim # Open editor (LSP auto-starts)
claude # Start Claude Code sessionSafe workflow for experimentation:
cd ~/Projects/dev-config
# Create feature branch
git checkout -b feat/new-config
# Edit config
nvim nvim/init.lua
# Test changes (no rebuild needed for config files!)
nvim test-file.txt
# If satisfied, commit
git add nvim/init.lua
git commit -m "feat(nvim): add new feature"
git push origin feat/new-config
# Create PR for team review
gh pr create --title "New Neovim feature"On your updated workstation:
cd ~/Projects/dev-config
git push origin mainOn target machine:
cd ~/Projects/dev-config
git pull origin main
# If flake.lock changed, rebuild environment
nix develop
# If config files changed, restart affected tools
tmux source-file ~/.tmux.conf # Reload tmux
source ~/.zshrc # Reload zsh
# Restart Neovim (no command, just exit and reopen)Sunday evening checklist:
cd ~/Projects/dev-config
# Update packages
nix flake update
git add flake.lock
git commit -m "chore: weekly flake update"
# Rebuild and test
nix develop
nvim --version
tmux -V
# Run health checks
nvim +checkhealth +qall # Neovim health check
bash scripts/validate.sh # Repo validation
# Push updates
git push origin mainUsing Claude Code via LiteLLM homelab gateway:
cd ~/Projects/dev-config # direnv loads Claude env vars automatically
# Ask for code review
claude ask "Review nvim/init.lua for improvements"
# Generate new config
claude ask "Create a tmux keybinding for splitting panes"
# Debug issues
claude ask "Why is my LSP not attaching? Here's my :LspInfo output: ..."LiteLLM credentials and headers auto-load via direnv + 1Password integration.
1. You: cd ~/Projects/dev-config
2. direnv: Detects .envrc file
3. direnv: Runs `use flake`
4. Nix: Loads all packages from flake.nix
5. direnv: Sources scripts/load-ai-credentials.sh
6. 1Password CLI: Fetches API keys from "Dev" vault
7. You: All tools + credentials available!
First time in directory:
cd ~/Projects/dev-config
# direnv: error .envrc is blocked. Run `direnv allow` to approve its content.
direnv allow # Approve .envrc
# 🔐 Loading AI credentials...Block a directory:
direnv blockRe-allow:
direnv allowEnvironment not loading:
direnv status # Check direnv state
# Should show:
# Found RC allowed true
# Found RC path /Users/you/Projects/dev-config/.envrcManual reload:
direnv reloadCheck hook installation:
cat ~/.zshrc | grep direnv
# Should show: eval "$(direnv hook zsh)"Ask a question:
claude ask "How do I configure Neovim LSP for Python?"Review code:
claude ask "Review nvim/init.lua and suggest improvements"Generate code:
claude ask "Create a shell function to quickly switch tmux sessions"Debug:
claude ask "Debug: Neovim LSP not working. :LspInfo shows: ..."Automatic credential injection:
cd ~/Projects/dev-config # direnv loads ANTHROPIC_BASE_URL + headers
claude ask "..." # Uses LiteLLM proxy + secret headersExplicit op run (optional hardening):
op run -- claude ask "Explain this codebase"
# Injects headers just for the duration of this commandVerify environment variables:
env | grep ANTHROPIC_
# Should show ANTHROPIC_BASE_URL=https://litellm.infra.samuelho.space
# and ANTHROPIC_CUSTOM_HEADERS with x-litellm-api-keyDefault model (Anthropic Sonnet via Max subscription):
claude --model claude-3-5-sonnet-20241022 ask "..."Use another routed model:
claude --model claude-3-5-haiku-20241022 ask "..." # Haiku
claude --model minimax/MiniMax-M2.1 ask "..." # MiniMax M2
claude --model gemini-3.0-flash-exp ask "..." # Gemini via LiteLLMThe LiteLLM dashboard controls which providers/models are available. Enable new models in the UI, then call them directly via claude --model <name>.
Push changes:
cd ~/Projects/dev-config
git add .
git commit -m "feat: add new tmux plugin"
git push origin mainTeam members pull:
cd ~/Projects/dev-config
git pull origin main
nix develop # Automatically rebuilds if flake.lock changedNo manual "install updated packages" step! Nix handles it automatically.
For team vaults:
- Create shared "Dev" vault in 1Password
- Add team members to vault
- Create "ai" item with team credentials
- Each team member runs
op signin - Credentials auto-load for all team members
Result: Everyone uses same API keys, no manual distribution.
First build (no cache):
- Time: 5-10 minutes (building packages from source)
Subsequent builds (with Cachix):
- Time: 10-30 seconds (downloading pre-built binaries)
- 20x faster!
How it works:
- First team member builds environment
- Cachix uploads build artifacts
- Other team members download instead of rebuilding
No setup needed - configured in flake.nix.
Verify everything is working:
cd ~/Projects/dev-config
nix develop --command bash -c "
nvim --version &&
tmux -V &&
op account get &&
echo '✅ All tools operational'
"Need a tool just once?
nix shell nixpkgs#htop # Temporarily add htop
htop # Use it
exit # Tool removed when shell exitsDon't pollute flake.nix with temporary tools.
Find package name:
nix search nixpkgs postgresql
# Returns: legacyPackages.x86_64-darwin.postgresql
# Use: pkgs.postgresql in flake.nixWeb search: https://search.nixos.org/packages
Nix store grows over time. Clean up old generations:
# Remove old generations (keep last 10)
nix-collect-garbage --delete-older-than 30d
# Aggressive cleanup (keep only current generation)
nix-collect-garbage -dCaution: This removes ability to rollback to old generations.
Nix works offline if packages are cached:
# Build all dependencies while online
nix build .#devShells.x86_64-darwin.default
# Later, offline:
cd ~/Projects/dev-config
nix develop # Uses cached packagesUse project-specific flake.nix:
# Project A: Uses Python 3.9
cd ~/Projects/project-a
nix develop # Loads Python 3.9
# Project B: Uses Python 3.11
cd ~/Projects/project-b
nix develop # Loads Python 3.11
# No conflicts! Isolated environments.Add to ~/.zshrc.local:
# Auto-activate Nix in dev-config
cd() {
builtin cd "$@"
if [[ $(pwd) == "$HOME/Projects/dev-config"* ]]; then
echo "🔧 Nix environment active"
fi
}
# Quick rebuild alias
alias nix-rebuild="cd ~/Projects/dev-config && nix develop && cd -"Verify Cachix is working:
nix build .#devShells.x86_64-darwin.default --print-build-logs
# Look for: "copying path ... from 'https://dev-config.cachix.org'"If builds are slow:
- Check internet connection
- Verify Cachix cache name in flake.nix
- Check GitHub Actions pushed to cache
Create personal cache for fast rebuilds:
# Build once
nix build .#devShells.x86_64-darwin.default
# Subsequent builds use local cache
nix develop # Nearly instant!Speed up flake evaluation:
nix develop --eval-cache # Experimental featureA: Update specific input:
nix flake lock --update-input nixpkgsOr pin to specific version in flake.nix:
inputs.nixpkgs.url = "github:nixos/nixpkgs/nixpkgs-unstable?rev=abc123";A: Yes! They coexist peacefully:
- Nix packages:
/nix/store/ - Homebrew:
/opt/homebrew/(Apple Silicon) or/usr/local/(Intel)
Use Nix for development tools, Homebrew for GUI apps.
A: Nothing, unless that directory has a flake.nix. Nix only activates when:
- You run
nix developin directory with flake.nix - direnv detects .envrc with
use flake
A: GitHub Actions example:
- uses: DeterminateSystems/nix-installer-action@main
- uses: DeterminateSystems/magic-nix-cache-action@main
- uses: cachix/cachix-action@v14
with:
name: dev-config
authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}'
- run: nix develop --command make testCI builds use same flake.lock → identical environment.
A: Yes, using overlays in flake.nix:
nixpkgs.overlays = [
(final: prev: {
neovim = prev.neovim.overrideAttrs (old: {
version = "0.10.0"; # Pin specific version
});
})
];- Troubleshooting: Common Issues
- Advanced Customization: Advanced Guide
- Nix Concepts: Understanding Nix
- Quick Reference: Quick Start
# Daily Commands
cd ~/Projects/dev-config # Auto-activate environment
nix flake update # Update all packages
nix develop # Enter dev environment
nix run .#activate # Rerun activation script
nix profile rollback # Undo last change
# Package Management
nix search nixpkgs <name> # Find package
nix shell nixpkgs#<pkg> # Temporary package
nix-collect-garbage -d # Clean up old builds
# Environment
direnv allow # Approve .envrc
direnv reload # Reload environment
op signin # Authenticate 1Password
# Claude Code
claude ask "..." # Ask AI assistant through LiteLLM
claude --model minimax/MiniMax-M2.1 ask "..." # Use alternate model
# Validation
nix flake check # Validate flake.nix
bash scripts/validate.sh # Validate setup
nvim +checkhealth +qall # Neovim health check
# Git
git add flake.lock # Commit package updates
git push origin main # Share with team