This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
This is a dotfiles repository managed by Chezmoi. It contains personal configuration files for a cross-platform development environment (macOS, Linux/WSL) with automated setup via Ansible.
- Chezmoi: Dotfile manager with templating support (.tmpl files)
- Ansible: Automated system setup and package installation
- ZSH: Shell with Zplug for plugin management
- Neovim: Terminal editor using kickstart.nvim (nvim-custom) and LazyVim (nvim-lazyvim)
- Tmux: Terminal multiplexer with TPM for plugins
- Hammerspoon: macOS desktop automation (Lua-based)
@./ansible/README.md
# Apply changes and reload shell
ma
# Edit dotfiles (opens chezmoi source dir in editor)
edit
# Navigate to chezmoi source directory
moicd
# or
cd ~/.local/share/chezmoi
# Run git commands on dotfiles repo from anywhere
gmoi <git-command>
# Add nvim config to chezmoi (removes lazy-lock.json)
moi_add_nvim# Run full ansible playbook to configure system
dotansible
# Interactive tag selection with fzf
dotansible -i
# Run specific ansible tasks by tag
dotansible brew # Install/update Homebrew packages only
dotansible packages # Install all packages (brew or apt)
dotansible zsh # Configure ZSH only
dotansible tmux # Configure tmux only
# List available tags
dotansible tags
# For WSL (prompts for sudo password)
dotansible --ask-become
# First-time setup scripts
./ansible/mac-setup.sh # macOS
./ansible/fedora-setup.sh # Fedora LinuxThe dotansible function automatically uses hostname-specific inventory files when available (e.g., ansible/inventory/GVXPDWWKWG.yml), falling back to main.yml.
# Reload zsh configuration
sz
# View zsh configuration
catrc# Switch between neovim configs interactively
vv
# Current default config (set via NVIM_APPNAME)
nvim-custom # kickstart.nvim based
nvim-lazyvim # LazyVim distribution# Session manager (uses sesh + fzf)
# Bound to Alt+s in tmuxFiles with .tmpl extension are processed as Go templates. Key variables:
{{ .chezmoi.os }}- OS detection ("darwin" or "linux"){{ .chezmoi.hostname }}- Machine hostname for machine-specific configuration- Conditional blocks enable OS-specific and hostname-specific configuration
Example from dot_zshrc.tmpl:
{{ if eq .chezmoi.os "darwin" -}}
# macOS specific configuration
{{ end -}}
{{ if eq .chezmoi.hostname "GVXPDWWKWG" -}}
# Zendesk work machine configuration
{{ end -}}
Main playbook: ansible/main.yml
- Targets: localhost (127.0.0.1)
- Roles: zsh, hammerspoon (macOS only)
- Tasks: apt/homebrew package management, nodenv, tmux, vundle
Inventory files: ansible/inventory/
- Machine-specific configs named by hostname
main.ymlis the default inventory
Tasks: ansible/tasks/
- apt.yml - Debian/Ubuntu packages
- homebrew.yml - macOS packages
- nodenv.yml - Node.js version management
- tmux.yml - Tmux plugin manager setup
- vundle.yml - Vim plugin setup
Roles: ansible/roles/
- zsh/ - ZSH installation and configuration
- hammerspoon/ - macOS window management (macOS only)
- Additional roles: desktop-background, emacs, lastpass, lock-screen, music, pacman
Structure:
.zshenv- Environment variables, sourced first.zprofile- Login shell configuration.zshrc- Interactive shell setup, sources aliases.zshaliases.zsh- All shell aliases and functions
Plugin management: Zplug
- Plugins: vi-mode, agnoster theme, zsh-autosuggestions, zsh-syntax-highlighting
- Custom keybinds:
fdfor vi command mode,lkto accept suggestions
Key integrations:
- fzf - fuzzy finder
- zoxide - smart directory jumping
- sesh - tmux session manager (Alt+s keybind)
nvim-custom: Kickstart.nvim fork
- Single-file init.lua with extensive documentation
- Uses lazy.nvim for plugin management
- Located:
dot_config/nvim-custom/
nvim-lazyvim: LazyVim distribution
- More opinionated, feature-complete setup
- Located:
dot_config/nvim-lazyvim/
Switch between configs using the vv function or by setting NVIM_APPNAME.
- Navigate to chezmoi source:
moicdoredit - Edit files in the source directory
- For templated files, edit the
.tmplversion - Apply changes:
ma(applies and reloads shell) - Commit changes:
gmoi add .andgmoi commit
# Add a file to chezmoi management
chezmoi add ~/.config/newapp/config.yml
# Add with auto-template generation
chezmoi add --autotemplate ~/.gitconfigCreate machine-specific inventory:
cp ansible/inventory/main.yml ansible/inventory/$(hostname).ymlEdit the new inventory file, then run:
ansible-playbook ansible/main.yml -i ansible/inventory/$(hostname).ymlMachine-specific configurations are determined by hostname using chezmoi's built-in {{ .chezmoi.hostname }} variable in templates. No additional configuration files are needed.
Using hostname in templates:
{{ if eq .chezmoi.hostname "GVXPDWWKWG" -}}
# Zendesk work machine configuration (zetup, zendesk tooling, SSH keys, etc.)
{{ end -}}
To add configuration for a new machine:
- Get the hostname:
hostname - Add conditionals to templates based on the hostname
- Use
{{ .chezmoi.os }}for OS-specific configuration (darwin/linux) - Combine conditions as needed for specific machine + OS combinations
This hostname-based approach:
- Requires no manual configuration files
- Makes machine identity explicit in templates
- Works automatically when dotfiles are applied to any machine
- Easy to add new machines by adding hostname checks to templates
macOS:
- Homebrew packages managed via
ansible/tasks/homebrew.yml - Hammerspoon requires manual first-time setup
- rbenv path:
~/.rbenv/versions/3.3.3/bin
Linux/WSL:
- APT packages managed via
ansible/tasks/apt.yml - Alacritty settings in Windows:
C:\Users\Patrick\AppData\Roaming\Alacritty\ - Use
alacritty_settings_updateto sync config to Windows (WSL only) - rbenv path:
~/.rbenv/versions/3.3.4/bin
Chezmoi uses special prefixes in the source directory:
dot_→.at any level (e.g.,dot_zshrc→.zshrc,dot_config/→.config/).tmplsuffix → Go template processingexecutable_→ Make file executableprivate_→ Set file permissions to 0600
Examples of the directory structure mapping:
dot_config/nvim/init.lua→~/.config/nvim/init.luadot_zsh/dot_zprofile.tmpl→~/.zsh/.zprofile(templated)dot_tmux.conf→~/.tmux.conf
The dot_ prefix is used every time a dot is needed in the path, whether for directories or files.
- Chezmoi source:
$HOME/.local/share/chezmoi - Global Claude instructions (tracked in private dotfiles):
~/code/dotfiles-private/dot_claude/CLAUDE.md- this is the primary place for user preferences that apply across all projects - Config files:
~/.config/ - Local binaries:
~/.local/bin - ZSH configs:
$ZDOTDIR(usually~/.zsh/) - Tmux plugins:
~/.tmux/plugins/ - Node versions:
~/.nodenv/versions/ - never use emojis in commit messages, nor co-authoring from claude, nor mentions of it being generated by claude
- always update the links in the readme toc when adding/removing files in docs/
- Ansible should not report tasks as "changed" when they haven't changed the state of the machine.
- NEVER create dotfiles directly on the system (e.g. in
~/.emacs.d.han/,~/.config/, etc.). Always create them in the chezmoi source directory (~/.local/share/chezmoi/) so they are tracked and deployed properly viachezmoi apply.