A comprehensive collection of configuration files for a modern developer environment. This repository contains configurations for terminal, shell, editor, and development tools.
This configuration setup is designed for macOS/Linux systems with a focus on minimal, fast, and remote-friendly tooling. Each configuration is self-contained and can be used independently.
This repository is ~/.config, so most tools (Neovim, Ghostty, Alacritty, tmux)
already find their config at the XDG path with no setup. Only the few files that
have to live outside ~/.config need linking.
make install deliberately reports missing tools rather than installing
them, so adopting this on a new machine is five steps, not one:
# 1. Homebrew — nothing here installs it for you
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
# 2. Clone. The path matters — see "Cloning somewhere else" below.
git clone https://github.com/codephilip/dotfiles.git ~/.config
# 3. Tools. `make tools` prints these from bootstrap's own list, so it is
# never out of date — pipe it to a shell, or paste it:
# cd ~/.config && make tools
brew install bat delta eza fd fzf gh k9s lazydocker lazygit neovim ripgrep starship \
tmux zoxide zsh-autosuggestions zsh-syntax-highlighting
brew install --cask ghostty alacritty font-jetbrains-mono-nerd-font
# 4. Symlinks + generated theme files
cd ~/.config
make verify # dry run — show what would change
make install
# 5. Pick up the new shell, then let the editor bootstrap itself
exec zsh
nvim # lazy.nvim self-installs; then :Mason for the language serversmake install is idempotent and never overwrites a real file — if ~/.zshrc
already exists as a regular file, it says so and leaves it alone. It links
~/.zshrc, ~/.tmux.conf and ~/.gitconfig, lists any missing formulae and
casks as copy-pasteable brew install lines, then runs theme regen to write
the generated colour fragments (a fresh clone has none — they are gitignored)
and fetch the bat theme Tokyo Night needs.
These are per-machine or secret, so they are not in the repo and nothing checks for them:
| What | Command | Needed for |
|---|---|---|
| SSH config | restore ssh/config from your password manager |
the github, prox-*, macmini* and Hetzner hosts |
| GitHub auth | gh auth login |
gh; the token lives in the keychain, not here |
| Secrets | create ~/.zshrc.local with export ANTHROPIC_API_KEY=… |
CodeCompanion in Neovim (inert without it) |
| Key repeat | see below — make install reports these |
holding j/k in Neovim without it crawling |
| Docs toolchain | brew install mkdocs-material (or pip install) |
make serve / make docs only |
ssh/config is gitignored — it used to be an Ansible Vault blob in the repo,
but it is local-only now, so a rebuild needs it from elsewhere. bootstrap
reports not in repo, nothing to link and carries on.
Key repeat is the one that makes a new Mac feel broken in Neovim. These are
per-user macOS defaults rather than files, so they cannot live in this repo and
make install can only report them. All three steps are needed, in order:
- System Settings → Keyboard — Key Repeat Rate to the fastest notch, Delay Until Repeat to the shortest. Do this first; writing the prefs without the pane having set them does not take.
- Then run:
defaults write -g KeyRepeat -int 1 # below the slider's floor of 2 defaults write -g InitialKeyRepeat -int 15 # delay before repeating defaults write -g ApplePressAndHoldEnabled -bool false # not in System Settings at all
- Log out and back in. A terminal relaunch is not enough — macOS latches the rate for the login session.
Step 2 is not redundant with step 1: KeyRepeat = 1 is faster than the slider
can express, and ApplePressAndHoldEnabled has no GUI control. While that one
is on, holding a key opens the accent-character picker instead of repeating at
all, so j advances one line per press however fast the rate is set.
Note that defaults read — and therefore make verify — reports the stored
value, which looks correct immediately while the session still uses the old one.
The only real test is holding j after a logout. Full detail, including the
case-sensitivity trap, is in
docs/troubleshooting.md.
A few things the config uses can arrive by several routes — a native installer,
npm, pip, uv, cargo, a direct download — so there is no brew install line that
fixes them and no brew upgrade that keeps them current. make verify gives
them their own section:
External tools
not from this homebrew — compare versions across machines
✓ Claude Code 2.1.220
/usr/local/bin/claude — direct install or Intel brew
✓ mkdocs 1.6.1
/opt/homebrew/bin/mkdocs — homebrew
The route is inferred from the path, because nothing records how a binary
actually got there. This matters because the failure mode is quiet: a missing
tool announces itself, whereas the same tool installed three different ways on
three machines just runs three different versions. Claude Code has already done
this here — the native installer puts it in ~/.local/bin, npm in the brew
prefix, and a direct install in /usr/local/bin. Run make verify on each
machine and compare the versions; nothing can do that comparison for you.
git clone … ~/.config fails if ~/.config already exists with content,
which is common on a machine that has been used. Adopt the directory in place
instead:
git init ~/.config && cd ~/.config
git remote add origin https://github.com/codephilip/dotfiles.git
git fetch origin && git checkout -f mainCloning to a path other than ~/.config only half-works: bootstrap and
scripts/theme both resolve the repo from their own location, so linking and
theme generation are correct — but every tool that reads an XDG path (Neovim,
Ghostty, Alacritty, starship) still looks in ~/.config and will not see the
clone. Symlink ~/.config at it, or clone there in the first place.
Per-tool details and manual steps are in the sections below.
- Git - Version control (required for Neovim plugins, git aliases, and various integrations)
- Neovim (0.11+) - Required, not just recommended: the LSP config uses the
native
vim.lsp.config/vim.lsp.enableAPI added in 0.11 - tmux - Terminal multiplexer
- Zsh - Shell (uses built-in features, no Oh My Zsh required)
- ripgrep (rg) - Fast text search (required for Neovim
:Rgcommand) - bat - Syntax-highlighted pager (required for zsh pager and cheatsheet viewing)
- fzf - Fuzzy finder (required for Neovim file navigation)
- Docker - Container platform (for docker aliases)
- kubectl - Kubernetes CLI (for k8s aliases)
- lsof - List open files (for
ports()andkillport()functions)
One palette drives the terminal, prompt, fzf, Neovim, bat and delta.
Three are available; switch with a single command:
theme list # all themes, active one marked
theme solarized-osaka # switch
theme next # cycle
theme show # swatches for the active palette| Theme | Look |
|---|---|
tokyonight |
cool blue-violet on near-black (default) |
solarized-osaka |
deep teal-black, Solarized accents |
catppuccin-mocha |
warm, soft, low-contrast |
theme/palettes/<name>.sh is the single source of truth. The per-tool
fragments (ghostty/theme.conf, alacritty/theme-current.toml,
git/theme.gitconfig) are generated from it and gitignored — don't
hand-edit them, and don't put colours in ghostty/config or
alacritty.toml. Full detail: docs/theming.md.
Ghostty is the daily driver because it can use the macOS 26 glass
material (via the per-machine local.conf), and it has splits, tabs and
shell integration. Alacritty is styled to match it everywhere else.
Key Features:
background-opacity = 0.86+background-blur = 20;macos-glass-regularinlocal.confon macOS 26+- Window padding: 14pt horizontal, 12pt vertical; titlebar hidden
JetBrainsMono Nerd Fontat 13.5pt,adjust-cell-height = 8%- Beam cursor with blinking;
copy-on-select - Shift+Enter sends ESC CR (needed by Claude Code and most REPLs)
Reload config with ⌘⇧, — Ghostty has no CLI reload.
Kept because it works everywhere, including over X forwarding and on Linux. Styled to match Ghostty: same palette, opacity, blur, padding, font and cursor, so switching between the two is not a visual jump.
Font Requirements:
- JetBrains Mono Nerd Font must be installed
- Regular style
- Bold style
- Italic style
- Font size: 13.5pt with y-offset of 1
Color Scheme:
- Generated — imports
alacritty/theme-current.toml, written bytheme
Key Features:
- Window padding: 14px horizontal, 12px vertical
- Opacity 0.86 with
blur = true, the same glass as Ghostty's shared setting - Left Option is Alt (
option_as_alt = "OnlyLeft"), as in Ghostty - Mouse cursor hides while typing
live_config_reload, so a theme switch applies without a restart- Scrollback history: 100,000 lines (Alacritty's maximum)
- Selection automatically copied to clipboard
- Beam cursor with blinking enabled
Installation:
- On macOS: Install JetBrains Mono via Homebrew (
brew install font-jetbrains-mono) or download from JetBrains - On Linux: Install via package manager or download from JetBrains website
Plugin Manager:
- lazy.nvim - Automatically bootstrapped on first run
Core Dependencies:
- fzf - Must be installed and built (
fzfbinary in PATH) - ripgrep - Required for
:Rgsearch command (rgbinary in PATH) - git - Required for git integration (gitsigns, fzf git commands)
LSP Servers (installed via Mason.nvim):
lua_ls- Lua Language Serverts_ls- TypeScript/JavaScript Language Serverpyright- Python Language Servergopls- Go Language Serverrust_analyzer- Rust Language Serverbashls- Bash Language Serveryamlls- YAML Language Serverjsonls- JSON Language Server
Treesitter Parsers (auto-installed):
- lua, vim, bash, json, yaml, javascript, typescript, html, css, python
Keybindings:
<Space>- Leader key<leader>e- Toggle file tree (nvim-tree)<leader>ff- Find files (fzf)<leader>fg- Find git files<leader>fb- Find buffers<leader>fw- Search with ripgrep<leader>f- Format code (LSP)gd- Go to definition (LSP)gr- Go to references (LSP)K- Hover documentation (LSP)<leader>rn- Rename symbol (LSP)<C-h/j/k/l>- Navigate windows (works with tmux via vim-tmux-navigator)
Plugins:
- nvim-tree.lua - File tree
- fzf.vim - Fuzzy finder
- nvim-treesitter - Syntax highlighting
- gitsigns.nvim - Git signs in gutter
- nvim-cmp + sources - Autocompletion
- nvim-lspconfig - LSP client
- mason.nvim - LSP server installer
- vim-tmux-navigator - Seamless tmux/neovim navigation
- bufdelete.nvim - Safe buffer deletion
- LuaSnip - Snippet engine (for LSP snippets)
Installation:
- Ensure Neovim 0.9+ is installed
- Install fzf:
brew install fzf(macOS) or via package manager - Install ripgrep:
brew install ripgrep(macOS) or via package manager - Link config:
ln -s ~/.config/nvim ~/.config/nvim(if needed) - Launch Neovim - plugins will auto-install via lazy.nvim
- LSP servers will be installed automatically via Mason when you open files
Terminal Requirements:
- tmux-256color terminal capability - Your terminal must support 256-color mode
- On macOS, this is typically enabled by default in modern terminals
- On Linux, you may need to ensure
TERM=tmux-256coloris set
Keybindings:
- Prefix:
Ctrl-a(changed from the defaultCtrl-b) - Every other binding is stock tmux:
%and"split, arrows move between panes,ddetaches. On a server's stock tmux, useCtrl-band the rest is the same. Ctrl-a Ctrl-asends a literalCtrl-a(go to line start in the shell)Ctrl-a Rreloads the config- Full reference:
tmux-commands, or the tmux page in the docs
Features:
- Mouse support enabled
- History limit: 50,000 lines
- Vim-style copy mode
- Window/pane indexing starts at 1
- Status bar shows session name and hostname (when SSH'd)
Plugin Directories (Optional):
The plugins/ directory contains plugin folders, but no TPM configuration is present. These plugins are not automatically loaded unless TPM is configured separately:
- nord-tmux (theme)
- tmux-prefix-highlight
- tmux-sensible
- tmux-sessionx
- tmux-yank
- vim-tmux-navigator (also in Neovim)
Installation:
- Install tmux:
brew install tmux(macOS) or via package manager - Link config:
ln -s ~/.config/tmux/tmux.conf ~/.tmux.conf - Ensure your terminal supports 256-color mode
Dependencies:
- bat - Required for pager (
LESSOPEN) and cheatsheet commands - git - Required for git aliases and prompt integration
- Docker (optional) - For docker aliases
- kubectl (optional) - For k8s aliases
- lsof - Required for
ports()andkillport()functions (usually pre-installed on macOS)
Features:
- starship prompt — bracketed segments with Nerd Font icons, themed from
the shared palette.
starship.tomlis generated byscripts/gen-starship.py;zsh/prompt.zshis the faster pure-zsh fallback. Seedocs/shell/index.md - No framework — no oh-my-zsh, prezto, zinit or antigen
- 50,000 line history with sharing across sessions
- Case-insensitive globbing
- Autocompletion with menu selection
Aliases:
- Git aliases: sourced from
~/.config/git/aliases.sh - Docker aliases: sourced from
~/.config/docker/aliases.sh - Kubernetes aliases: sourced from
~/.config/k8s/aliases.sh - Cheatsheet commands:
git-commands,k8s-commands,docker-commands,tmux-commands,zsh-commands,nvim-commands
Functions:
mkcd <dir>- Create directory and cd into itcdr- Jump to git repository rootports- Show active listening portskillport <port>- Kill process on specified portdkclean- Docker system prunekctxp- Show current kubectl context
Auto-tmux:
- Automatically attaches/creates tmux session when SSH'ing into a server
macOS-specific:
- Disables press-and-hold character accent menu
Installation:
- Ensure zsh is your default shell (usually default on macOS)
- Install bat:
brew install bat(macOS) or via package manager - Link config:
ln -s ~/.config/zsh/.zshrc ~/.zshrc - Source it:
source ~/.zshrcor restart terminal
Configuration:
- User name:
codephil - User email:
philip@meiers.in
Aliases (git/aliases.sh):
Extensive git aliases for common operations:
- Status:
gs,gss - Logs:
gl,glg,gla - Branches:
gb,gbv,gbd - Checkout/Switch:
gco,gcob,gsw,gswc - Add/Commit:
ga,gaa,gc,gcm,gca,gcan - Fetch/Pull/Push:
gf,gfa,gp,gpo,gpm - Rebase:
grb,grbi,grbc,grba - Diff:
gd,gds - Stash:
gsh,gshp,gshl
Installation:
- Git aliases are automatically sourced by zsh config if
~/.config/git/aliases.shexists - Git config can be linked:
ln -s ~/.config/git/gitconfig ~/.gitconfig
Aliases (docker/aliases.sh):
- Base:
d,dc - Containers:
dps,dpa,dst - Images:
di - Logs/Exec:
dl,dlf,dex - Build/Run:
db,dr,drm,drmi - Compose:
dcu,dcud,dcd,dcb,dcl,dclf - Cleanup:
dclean,dcleanf
Installation:
- Aliases are automatically sourced by zsh config if
~/.config/docker/aliases.shexists - Requires Docker to be installed
Docker TUI — lazydocker, or ld. The Docker counterpart to k9s: every
container, image, volume and Compose service in one screen, with live logs and
stats. Start it inside a Compose project and a Services panel appears too.
Same XDG problem as k9s, different fix. lazydocker defaults to
~/Library/Application Support/lazydocker on macOS. Its override is an env
var called plain CONFIG_DIR, which is too generic to export into every
process, so docker/aliases.sh wraps lazydocker in a function that sets it
for that one command. Check with type lazydocker; it should say "shell
function".
docker/lazydocker/config.yml changes one thing: logs show the last 500 lines
rather than the last 60 minutes. The default leaves the log pane empty for any
container that crashed more than an hour ago. There is no generated skin: its
colours are ANSI names, so they already follow the terminal's theme.
Aliases (k8s/aliases.sh):
- Base:
k - Get:
kgp,kgs,kgd,kgn,kgi,kgcm,kgsec - Describe:
kdp,kdd,kds - Logs:
kl,klf,klp - Exec:
kex,ksh,kbash - Apply/Delete:
ka,kdel - Context/Namespace:
kctx,kctxs,kns,knsa - Rollout:
kro,kru - Metrics:
ktp,ktn
Installation:
- Aliases are automatically sourced by zsh config if
~/.config/k8s/aliases.shexists - Requires kubectl to be installed
Cluster TUI — k9s. Use it instead of chaining the kg* aliases when you are
exploring rather than scripting: live-updating resource lists, l for logs,
s to shell into a pod, d to describe, and : to jump to any resource type
by name.
This one needs an env var to work at all. k9s ignores XDG on macOS and
defaults to ~/Library/Application Support/k9s, which would put its config
outside this repo — unversioned and unthemed. .zshrc exports
K9S_CONFIG_DIR=~/.config/k8s/k9s to pull it back in. Confirm which paths it
actually resolved with:
k9s info # Config: and Skins: should both be under ~/.config/k8s/k9sk8s/k9s/config.yaml is tracked and deliberately minimal — k9s merges it over its
own defaults, so a short file stays correct across upgrades. Colours come from
k8s/k9s/skins/theme-current.yaml, generated by scripts/theme and gitignored
like the other theme fragments; restart k9s after theme <name>.
Gotcha worth knowing: k9s 0.51 validates config.yaml against a schema and
rejects the whole file on a single misplaced key, falling back to its
defaults with only a warning in its log — nothing on screen. If your settings
seem to be ignored, check:
grep -i 'not allowed\|load failed' "$(k9s info | awk '/Logs:/{print $2}')"Backgrounds are default rather than a palette colour throughout the skin, so
k9s inherits the terminal background instead of painting its own — the same
reason tmux uses bg=default and the Neovim themes are transparent. Ghostty's
blur stays visible behind it.
ssh/ is gitignored. The config was previously committed as an Ansible Vault
blob, but the repo is public and the decrypted file contains host names and
addresses, so it is local-only now. Keep a copy in your password manager.
On a new machine:
# restore ssh/config from your password manager, then:
chmod 600 ~/.config/ssh/config
make install # links it to ~/.ssh/configmake install links ~/.ssh/config when the file is present and reports
not in repo, nothing to link when it isn't — it is never an error.
Markdown cheatsheets for:
- docker.md
- git.md
- k8s.md
- nvim.md
- tmux.md
- zsh.md
Viewing:
- Use aliases:
git-commands,k8s-commands,docker-commands,tmux-commands,zsh-commands,nvim-commands - These use
batfor syntax highlighting
Symlinking is handled by make install (see Quick Start) —
these are just the packages. make install also reports which of them are
missing, so you can run it first and paste the command it gives you.
Don't trust this copy — it has drifted before. make tools prints the lines
straight from BREW_FORMULAE and BREW_CASKS in bootstrap, which is the
only place the list actually lives:
cd ~/.config && make tools # paste the output
cd ~/.config && make tools | sh # or just run itFor reference, at the time of writing:
brew install bat delta eza fd fzf gh k9s lazydocker lazygit neovim ripgrep starship \
tmux zoxide zsh-autosuggestions zsh-syntax-highlighting
brew install --cask ghostty alacritty font-jetbrains-mono-nerd-fontThe font must be the Nerd Font build — plain JetBrains Mono has no glyphs for the icons in the Neovim statusline, file tree or prompt.
# Debian/Ubuntu — note bat is `batcat` and fd is `fdfind` on apt
sudo apt install neovim tmux fzf ripgrep bat fd-find git zsh
# Not in apt; install via Homebrew on Linux, cargo, or the release pages:
# delta eza lazygit starship zoxideJetBrains Mono Nerd Font: download the patched build from https://github.com/ryanoasis/nerd-fonts/releases — the upstream JetBrains release is unpatched and will render icons as tofu.
Separate from make install, which is macOS/Linux only and refuses to run
on Windows. From Git Bash, with scoop installed:
cd ~/.config && make windowsThis installs the CLI tools, Alacritty and the Nerd Font with scoop. zsh and real tmux come from MSYS2, and Alacritty is set to open zsh. It's safe to re-run. How it works and why: docs/windows.md.
- The
vim-tmux-navigatorplugin enables seamless navigation between Neovim windows and tmux panes usingCtrl-h/j/k/l - Works automatically when both are configured
EDITORandVISUALenvironment variables are set tonvim- Git commits and other editor operations will use Neovim
batis used as the pager forless(viaLESSOPEN)- Cheatsheet commands use
batfor syntax highlighting
- tmux's status line is two greys on
bg=default, so it inherits the terminal's background and palette rather than defining its own. That is what keeps Ghostty's blur visible behind the status line, and it means tmux needs no per-theme config at all terminal-overridesmust namexterm-ghosttyexplicitly — Ghostty's$TERMmatches neither*256col*noralacritty, and without it every colour inside tmux silently drops to 256
- This configuration does not use Oh My Zsh - it relies on built-in zsh features
- Neovim plugins are managed via
lazy.nvimand auto-install on first run - LSP servers are installed via
mason.nvimwhen needed - tmux plugins in the
plugins/directory are not automatically loaded (no TPM config) - SSH config is encrypted with Ansible Vault for security
- All aliases are modular and can be sourced independently