A working macOS terminal setup, managed with chezmoi. Lean, fast, cohesive β built deliberately rather than accumulated. Gruvbox throughout, JetBrains Mono everywhere.
| Layer | Tool | Why |
|---|---|---|
| Terminal | Ghostty | GPU-accelerated, native macOS, auto light/dark |
| Shell | fish | Sensible defaults, no config gymnastics |
| Prompt | Starship | Fast, declarative, themeable |
| Plugins | Fisher | fish plugin manager |
| Multiplexer | tmux | Sessions, splits, persistence |
| Editor | Neovim | Hand-rolled lean config |
| Dev tools | mise | One tool to version Node, Python, Go, Rust, β¦ |
| History | Atuin | Searchable, syncable shell history |
Modern CLI replacements wired in via fish + Fisher: eza, zoxide, fzf,
bat, ripgrep, fd, git-delta.
Prerequisites:
- macOS
- Xcode Command Line Tools β
xcode-select --install - Homebrew β
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
Then one command does the rest:
sh -c "$(curl -fsLS get.chezmoi.io/lb)" -- init --apply cgatnoThat single line:
- Clones this repo into
~/.local/share/chezmoi - Runs
brew bundleβ installs everything inBrewfile - Applies the configs to your home directory
- Bootstraps Fisher and syncs
fish_plugins - Clones TPM and installs the tmux plugins from
.tmux.conf
Steps 2, 4, and 5 are handled by chezmoi
run_onchange_
scripts in .chezmoiscripts/ β each is hashed
against the file it depends on, so they re-run only when something
genuinely changes (e.g., a new package added to Brewfile, a new
plugin added to fish_plugins).
After applying, set fish as your login shell:
echo /opt/homebrew/bin/fish | sudo tee -a /etc/shells
chsh -s /opt/homebrew/bin/fishIf you'll be committing to this repo, enable the gitleaks pre-commit hook:
cd ~/.local/share/chezmoi && pre-commit installIf you'd rather install only some pieces, skip the chezmoi one-liner and install dependencies Γ la carte:
# Core
brew install fish starship tmux neovim mise atuin chezmoi
# Modern CLI replacements
brew install eza zoxide fzf bat ripgrep fd git-delta
# Pre-commit secret scanning
brew install gitleaks pre-commit
# Terminal & font
brew install --cask ghostty font-jetbrains-mono-nerd-fontNative macOS app, GPU-rendered, fast. The config auto-switches between
Gruvbox Light and Dark based on system appearance, and forwards
ssh-terminfo / ssh-env so remote sessions render correctly without
manually installing terminfo on every host.
Fish provides autosuggestions, syntax highlighting, and abbreviations as
built-in features. Fisher manages the plugins that extend it:
fzf.fish for fuzzy keybindings, autopair.fish for bracket pairing,
plugin-git for git abbreviations, and bass for sourcing bash scripts
when needed.
A custom multi-segment prompt with the Gruvbox palette: OS icon β username β directory β git branch & status β language version β docker context β time. One config file, no shell coupling.
Ctrl+Space as prefix (closer to home row than the default Ctrl+b),
intuitive | and - splits that inherit cwd, 50k-line scrollback,
auto-restore via tmux-resurrect + tmux-continuum, and seamless
nvim β tmux pane navigation via vim-tmux-navigator.
Hand-rolled config, bootstrapped with lazy.nvim. One file per plugin
under lua/plugins/ so changes are surgical.
- Treesitter for syntax (Lua, Python, fish, bash, markdown, json, yaml, toml, vim, gitcommit, gitignore, β¦)
- Copilot for inline ghost-text suggestions (Tab to accept)
- fzf-lua for files, grep, buffers, keymaps
- Oil for buffer-as-file-explorer (
-to ascend a directory) - Gitsigns for hunks in the sign column + actions
- Lualine for the status line, Gruvbox for the colors
One tool, one TOML file, every language runtime. Replaces nvm,
pyenv, rbenv, goenv, rustup, etc. Per-project versions when
needed; sane global defaults via mise/config.toml.
Searchable shell history with vim-mode keybindings, compact UI, and sync v2 enabled (encrypted, end-to-end). Built-in secrets filter catches AWS keys, GitHub PATs, Slack tokens, and Stripe keys before they hit the database.
- No LSP / autocomplete plugins in Neovim. Treesitter and Copilot
cover the editing this config is meant for. Adding
mason+lspconfig+ a completion engine would roughly double the plugin count for marginal value at this scale; reach for a heavier editor when deeper static analysis is genuinely needed. - No AI in nvim beyond Copilot inline. No Avante, no CodeCompanion, no ChatGPT plugins. Conversational AI lives in a dedicated tool, not the editor.
- No tmux auto-launch from fish. I want explicit control over when a tmux session starts.
- No shell framework (oh-my-zsh, prezto, etc.). Not running zsh, and frameworks add startup latency and indirection that the small number of plugins here doesn't justify.
Measured on a MacBook Pro (M2 Pro, 16 GB, macOS 26.4.1) using
hyperfine --warmup 3 --runs 50 <cmd>:
| Mean Β± Ο | Range | |
|---|---|---|
fish -i -c exit |
65.9 ms Β± 1.6 ms | 63.2 β 71.2 ms |
nvim --headless +q (no buffer) |
26.6 ms Β± 1.3 ms | 24.2 β 30.2 ms |
nvim --headless <file> +q (Treesitter active) |
46.7 ms Β± 1.1 ms | 44.1 β 49.8 ms |
Larger files (a few thousand lines, more Treesitter and gitsigns work)
push the upper bound higher; the numbers above are for opening
lua/plugins/treesitter.lua (~50 lines) inside this repo.
.
βββ .chezmoiignore # what chezmoi shouldn't apply
βββ .chezmoiscripts/ # run_onchange_ bootstrap scripts
β βββ run_onchange_before_install-brewfile.sh.tmpl
β βββ run_onchange_after_install-fish-plugins.sh.tmpl
β βββ run_onchange_after_install-tmux-plugins.sh.tmpl
βββ .gitignore # repo-level secret-shaped patterns
βββ .pre-commit-config.yaml # gitleaks hook
βββ Brewfile # Homebrew dependencies
βββ dot_gitconfig # β ~/.gitconfig
βββ dot_tmux.conf # β ~/.tmux.conf
βββ private_dot_config/ # β ~/.config/ (chmod 700)
βββ ghostty/config
βββ mise/config.toml
βββ nvim/
β βββ init.lua
β βββ lua/
β βββ config/ # options, keymaps, lazy bootstrap
β βββ plugins/ # one file per plugin
βββ private_atuin/ # β ~/.config/atuin/ (chmod 700)
βββ private_fish/ # β ~/.config/fish/ (chmod 700)
β βββ config.fish
β βββ fish_plugins
β βββ functions/devupdate.fish
βββ starship.toml
The dot_ and private_ prefixes are
chezmoi attributes
β dot_ becomes a leading ., private_ enforces chmod 0700/0600.
