One repo to carry an entire development environment between machines. Everything that can be automated is automated — packages are installed, configs are templated per machine type, and a post-apply checklist catches anything that needs manual attention (SSH keys, GPG keys, fonts). Machine-specific secrets like signing keys are prompted at init time, never hardcoded, and SSH host config stays local-only.
xcode-select --install
sh -c "$(curl -fsLS get.chezmoi.io)" -- init --apply Braden1996First apply can take a few minutes on a fresh machine because it may install Homebrew, Brew packages, and mise runtimes.
- Fast shell startup — cache generated init for
starship,fzf, andzoxide, prefermiseshims over full shell hooks, and keep shell config modular. - Portable between laptops — detect Homebrew prefix dynamically, template only the parts that actually vary by machine, and route work Git identity by remote org instead of hardcoded checkout paths.
- Keep local state local — SSH host config, auth state, generated keys, and other machine-bound setup stay outside the tracked repo.
xcode-select --installIf chezmoi is not yet installed (fresh machine):
sh -c "$(curl -fsLS get.chezmoi.io)" -- init --apply Braden1996Or if chezmoi is already installed:
chezmoi init --apply Braden1996You'll be prompted for these values (stored locally, never committed):
| Variable | Description | Example |
|---|---|---|
machineType |
personal or work |
work |
gitName |
Git author name | Braden Marshall |
personalEmail |
Personal email for git | me@bradenm.co.uk |
workEmail |
Work email (work machines only) | braden@attio.com |
workGitHubOrg |
GitHub org for work repos (optional, work machines only) | Attio |
onePasswordAccount |
1Password account domain | my.1password.com |
gpgKeyPersonalEmail |
GPG signing key ID for your personal email | 38D2DE75C7CD663D |
gpgKeyWorkEmail |
GPG signing key ID for your work email (work only) | 9BD932BC6F57FB4E |
Tip: If you haven't generated your GPG keys yet, leave the signing key fields blank. Generate them in the next step and then re-run
chezmoi initto fill them in.
- Homebrew is installed if missing (with Apple Silicon detection)
- Packages are installed via Brewfile — shell tools, editors,
mise,biome,jq, 1Password CLI, Ghostty - Runtimes and global tools are installed via
miseusing the global Node/Python/Biome defaults - Configs are templated and written to
~— git, zsh, fish, starship, editors, terminal, tmux - TPM (tmux plugin manager) is cloned if not present
- Post-setup checklist runs and flags anything that still needs manual attention
The setup checklist will tell you what's missing, but here's the full list:
Generate an SSH key and add it to GitHub:
ssh-keygen -t ed25519 -C "your-email@example.com"
eval "$(ssh-agent -s)"
ssh-add ~/.ssh/id_ed25519
pbcopy < ~/.ssh/id_ed25519.pub
# Add at: https://github.com/settings/ssh/newGenerate a GPG key and add it to GitHub:
gpg --full-generate-key # choose Ed25519, use your git email
gpg --list-secret-keys --keyid-format=long # note the key ID
gpg --armor --export YOUR_KEY_ID | pbcopy
# Add at: https://github.com/settings/gpg/newThen re-run chezmoi init to set the key ID in your config.
Other manual steps:
- 1Password — sign in with
op signin - Nerd Font — install FiraCode Nerd Font (used by editors, starship, terminal)
- Tmux plugins — open tmux and press
prefix + I - Neovim plugins — open nvim and run
:PlugInstall - SSH config — keep
~/.ssh/configlocal-only and unmanaged by chezmoi
- SSH host config —
~/.ssh/configis intentionally unmanaged so work- and machine-specific hosts do not leak into the repo - Auth state —
op signin, SSH agent state, and GPG agent state remain local to the machine - Secrets and keys — private keys are never stored in the repo; only public identifiers like GPG key IDs are prompted into local chezmoi data
- Fonts and app state — fonts, editor extensions, and login sessions still need a one-time local install/sign-in
ssh -T git@github.com # SSH works
echo "test" | gpg --clearsign # GPG signing works
zsh-check-deps # all tools installed
fish-check-deps # fish prompt/tooling dependencies installed
chezmoi verify # applied files match the target state| Shell | zsh, fish, antidote, starship prompt, fzf, zoxide, bat, eza, yazi |
| Editor | Cursor (primary), neovim, zed |
| Terminal | ghostty, alacritty, iterm2 |
| Git | gpg signing, graphite, conditional work includes, aliases |
| Tmux | tmux + TPM, dracula theme |
| Files | yazi (Ctrl+y picker), ranger |
| Languages | mise (Node/Python/Biome with legacy version-file support), optional bun shims if installed separately |
| Security | 1Password CLI (op:// URIs), GPG commit signing |
| Theme | Catppuccin Macchiato (ghostty, zed, starship, fzf, fsh) / Dracula (alacritty, iterm2, nvim, tmux) |
Mise-managed runtimes
mise manages global Node, Python, and Biome versions from one config while still honoring legacy project files like .nvmrc, .python-version, and .ruby-version.
Work / personal machine branching
Set
machineType at init to toggle work-specific git configs (separate signing key, email, conditional includes for the configured work GitHub org). Architecture-aware paths handle Apple Silicon vs Intel Homebrew locations.
Starship prompt
Full Catppuccin Macchiato palette, rune character (
ᛃ) for success/error/vim mode indicators, git state detection (rebase, cherry-pick, merge, bisect), directory icons via Nerd Font substitutions, and right-aligned command duration + clock.
FZF everywhere
Catppuccin colors, bat-powered preview windows, fzf-tab for completions, Ctrl+R history with a 60% preview panel, and magic-enter integration (Cmd+Enter for git status or directory listing).
Git aliases
shit (amend), fuck (amend + force push), nuke (reset --hard + clean), ignore (append to .gitignore), ls / ll (compact log formats).
Antidote plugin loading
Core: zephyr (prompt, completion). Oh-My-Zsh: git, magic-enter, extract, sudo. Deferred: autosuggestions, autopair, you-should-use, forgit, fast-syntax-highlighting. Atomic bundle regeneration prevents race conditions.
Fish without a plugin manager
Fish uses native
conf.d autoloading plus cached init output for starship, fzf, and zoxide. Custom helpers and Nx completions live in-repo instead of depending on a runtime plugin manager.
1Password integration
op:// URIs in templated configs for secrets, CLI completion hooks in zsh, and GPG signing key storage.
CI pipeline
Template validation via chezmoi, shellcheck linting (SC1090/SC1091 excluded), JSON validation for editor configs, and automatic PR labeling by area (shell, git, editor, terminal, tmux, chezmoi).
Dependency checker
Run
zsh-check-deps or fish-check-deps to verify required tools (starship, fzf, mise) and optional ones (eza, bat, yazi, zoxide) with install hints.
.
├── .chezmoi.toml.tmpl # prompted config (machine type, emails, GPG keys)
├── .chezmoiignore # conditional ignores
├── dot_gitconfig.tmpl # git config (templated signing key)
├── dot_attio.gitconfig.tmpl # work-specific git config (templated)
├── dot_zshrc # main zsh entry
├── dot_zshenv.tmpl # zsh environment
├── dot_zprofile # login shell setup
├── dot_zsh_plugins.txt # antidote plugin list
├── dot_tmux.conf # tmux config
├── dot_bashrc # bash fallback
├── dot_profile # POSIX profile
├── dot_local/bin/ # lightweight wrappers (ghostty-fish, corepack shims)
├── empty_dot_hushlogin # suppress login banner
├── run_once_before_*.sh.tmpl # homebrew + package bootstrap
├── run_once_after_*.sh.tmpl # post-apply setup + checklist
├── dot_config/
│ ├── fish/ # fish conf.d, functions, completions
│ ├── zsh/ # modular zsh configs (00-99)
│ │ ├── 00-path.zsh # PATH management
│ │ ├── 10-options.zsh # shell options & history
│ │ ├── 20-plugins.zsh # antidote + starship init
│ │ ├── 30-completion.zsh # fzf-tab, bookmarks
│ │ ├── 40-tools.zsh # mise shims, fzf, zoxide
│ │ ├── 50-functions.zsh.tmpl # yazi, workspace-aware nx wrapper
│ │ ├── 70-keybindings.zsh # Ctrl+y, arrow keys
│ │ └── 99-local.zsh.tmpl # machine-specific
│ ├── zed/settings.json.tmpl # zed editor (biome, catppuccin)
│ ├── ghostty/config.tmpl # ghostty (catppuccin, blur, wrapper command)
│ ├── alacritty/alacritty.yml # alacritty (dracula)
│ ├── iterm2/Default.json # iterm2 profile
│ ├── starship.toml # prompt (catppuccin palette)
│ ├── nvim/init.vim # neovim (dracula, plug)
│ ├── fsh/ # fast-syntax-highlighting theme
│ ├── ranger/ # file manager + devicons
│ ├── graphite/aliases # git stacking aliases
│ └── private_git/ # private git ignores
├── private_Library/
│ └── .../Cursor/User/ # cursor settings & keybindings
chezmoi update # pull latest changes and apply
chezmoi diff # preview what would change
chezmoi apply # apply without pulling
chezmoi verify # confirm target and destination still match
chezmoi edit ~/.zshrc # edit zsh entrypoint
chezmoi edit ~/.config/fish/config.fish # edit fish entrypoint
chezmoi add ~/.config/foo/bar # start managing a new file
chezmoi cd # cd into the source directory
chezmoi init # re-run prompts (e.g. after generating a GPG key)