Personal macOS dotfiles for zsh, tmux, kitty, Neovim, Claude Code, and Rectangle.
.
├── zsh/
│ ├── .zshrc # symlink target for ~/.zshrc
│ └── .p10k.zsh # symlink target for ~/.p10k.zsh
├── .tmux.conf # symlink target for ~/.tmux.conf
├── kitty/
│ └── kitty.conf # symlink target for ~/.config/kitty/kitty.conf
├── nvim/ # symlink target for ~/.config/nvim
├── claude/ # global Claude Code config -> ~/.claude/
│ ├── settings.json # model, hooks, enabled plugins
│ ├── CLAUDE.md # global instructions (sources RTK.md)
│ ├── RTK.md # rtk command reference
│ ├── hooks/notify.sh # desktop notification hook (Stop/Notification)
│ └── hooks/statusline.sh # status line: dir, git branch, model, ponytail tag
└── RectangleConfig.json # imported via Rectangle's UI
Install these before linking the configs — the shell, tmux, and editor configs reference them directly and will warn or break without them.
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"Everything below (plus the font and optional tools) lives in the Brewfile — install it all at once:
brew bundle # or: make installOr by hand:
brew install zsh tmux neovim kitty lsd git make gnupg ripgrep fd rtk
brew install --cask rectangle| Tool | Used by |
|---|---|
tmux |
.tmux.conf |
neovim |
nvim/ config (with Lazy.nvim) |
kitty |
kitty/kitty.conf |
lsd |
ls alias in .zshrc |
gnupg |
GPG_TTY export for signed commits |
git, make |
telescope-fzf-native build inside Neovim |
ripgrep |
Telescope live_grep / grep_string (no fallback — these break without it) |
fd |
Faster Telescope find_files (optional; has a Lua fallback) |
rtk |
rtk hook claude PreToolUse hook in claude/settings.json |
rectangle |
RectangleConfig.json |
Required by kitty.conf and the Neovim UI icons.
brew install --cask font-jetbrains-mono-nerd-font.zshrc sets export ZSH="$HOME/.oh-my-zsh" and sources $ZSH/oh-my-zsh.sh. Without it, the shell will start but the theme and plugins below won't load.
sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattendedThe plugins=(...) array in .zshrc enables these oh-my-zsh built-ins (no extra install needed): git, node, tmux. They ship with oh-my-zsh itself.
.zshrc sets ZSH_THEME="powerlevel10k/powerlevel10k" and sources ~/.p10k.zsh (which is symlinked from zsh/.p10k.zsh in this repo). The instant-prompt block at the top of .zshrc also depends on it.
git clone --depth=1 https://github.com/romkatv/powerlevel10k.git \
"${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/themes/powerlevel10k"Listed in the plugins=(...) array in .zshrc. Provides fish-style "ghost text" suggestions from history as you type.
git clone https://github.com/zsh-users/zsh-autosuggestions \
"${ZSH_CUSTOM:-$HOME/.oh-my-zsh/custom}/plugins/zsh-autosuggestions".zshrc runs autoload -Uz compinit && compinit -C and adds ~/.zfunc to fpath. compinit is built into zsh — nothing to install — but if you have custom completion functions, drop them in ~/.zfunc.
.tmux.conf ends with run '~/.tmux/plugins/tpm/tpm' and uses tmux-sensible, tmux-yank, tmux-resurrect, and tmux-gruvbox.
git clone https://github.com/tmux-plugins/tpm ~/.tmux/plugins/tpmAfter linking the config, install plugins from inside tmux with prefix + I (prefix is Ctrl-a).
.zshrc sources $HOME/.nvm/nvm.sh.
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.7/install.sh | bashThen install a Node version — nvm by itself puts no node/npm on PATH, and Neovim's Mason needs them to install the npm-based language servers (eslint, pyright, svelte, typescript, css, html), which otherwise fail with "failed to install":
nvm install --lts && nvm alias default 'lts/*'These are referenced in .zshrc only when present — install only what you actually use:
- Go —
brew install go(config exportsGOPATH=$HOME/go) - Rust / cargo —
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh - pnpm —
curl -fsSL https://get.pnpm.io/install.sh | sh - - Headroom —
pipx install --python python3.13 "headroom-ai[all]"(context compressor for AI agents)..zshrcexportsHEADROOM_OUTPUT_SHAPER=1to trim output tokens; run agents withheadroom wrap claude. - uv —
brew install uv(providesuvx, required bymake serenabelow to run the Serena MCP server).
From the repo root, make symlinks everything (existing files are overwritten — back them up first):
make # link all configs + apply macOS tweaks
make zsh # or run one group: zsh / tmux / kitty / nvim / claude / macos / keyswapmake macos sets a fast key repeat (KeyRepeat 2, InitialKeyRepeat 15, and disables press-and-hold accents). Log out and back in for it to take effect.
make keyswap swaps the left Ctrl and Fn keys. It installs a LaunchAgent (macos/keyswap.plist) that reapplies the hidutil mapping at every login, since the mapping is otherwise lost on reboot. Takes effect immediately.
The targets just wrap the ln -sf commands below if you'd rather run them by hand:
# zsh
ln -sf "$PWD/zsh/.zshrc" ~/.zshrc
ln -sf "$PWD/zsh/.p10k.zsh" ~/.p10k.zsh
# tmux
ln -sf "$PWD/.tmux.conf" ~/.tmux.conf
# kitty
mkdir -p ~/.config/kitty
ln -sf "$PWD/kitty/kitty.conf" ~/.config/kitty/kitty.conf
# Neovim
ln -sf "$PWD/nvim" ~/.config/nvim
# Claude Code (global config — link the files, leave runtime state untracked)
mkdir -p ~/.claude/hooks
ln -sf "$PWD/claude/settings.json" ~/.claude/settings.json
ln -sf "$PWD/claude/CLAUDE.md" ~/.claude/CLAUDE.md
ln -sf "$PWD/claude/RTK.md" ~/.claude/RTK.md
ln -sf "$PWD/claude/hooks/notify.sh" ~/.claude/hooks/notify.sh
ln -sf "$PWD/claude/hooks/statusline.sh" ~/.claude/hooks/statusline.shsettings.json references the rtk and ponytail plugins plus the notify hook;
the rest of ~/.claude/ (cache, sessions, history, plugins) is runtime state and
stays out of the repo.
Back up any pre-existing files first if you want to keep them.
Open Rectangle → preferences → Import → select RectangleConfig.json.
Serena is a coding-agent toolkit that gives Claude Code
semantic, LSP-backed code tools (find/edit symbols, references, project memories). It runs as a
user-scope MCP server, so MCP config lives in ~/.claude.json (runtime state, untracked) rather
than in this repo. make serena re-registers it from scratch:
make serena # needs uv (brew install uv); re-runnableThat wraps claude mcp add serena -s user -- uvx --from git+https://github.com/oraios/serena ….
uvx fetches and runs Serena straight from the repo — nothing to install globally. Verify with
claude mcp list.
Linear's hosted MCP server gives Claude Code access to issues, projects, and
comments. It runs over HTTP at https://mcp.linear.app/mcp, so like Serena its config lives in
~/.claude.json rather than in this repo. make linear re-registers it:
make linear # re-runnable; authenticate via OAuth on first useThat wraps claude mcp add --transport http linear-server https://mcp.linear.app/mcp -s user.
Verify with claude mcp list.
- zsh: open a new terminal. Powerlevel10k will start its config wizard on first run; settings are written to
~/.p10k.zsh(already symlinked to this repo, so they'll persist). - tmux: start
tmux, then pressCtrl-athenIto install plugins via TPM. - Neovim: launch
nvim. Lazy.nvim bootstraps itself, then installs all plugins listed undernvim/lua/plugins/. Mason auto-installs the language servers listed innvim/CLAUDE.md. - kitty: quit and relaunch so the font and key bindings take effect.
- The
tmuxandkittyconfigs include a workaround that mapsShift+EntertoESC [13;2uso apps like Claude Code receive a literal newline instead of submitting. kitty.confremapsCtrl+Shift+6toCtrl+^for Neovim alternate-buffer switching on Corne keyboards.- tmux prefix is
Ctrl-a(not the defaultCtrl-b). - Claude Code + tmux scrolling: if
Ctrl-a [won't scroll past Claude Code's output, fullscreen rendering (alternate-screen buffer) is on — it has no scrollback..zshrcexportsCLAUDE_CODE_DISABLE_ALTERNATE_SCREEN=1to force the classic renderer so output flows into tmux scrollback. The toggle persists per machine: if a box still misbehaves, run/tuiinside Claude Code and turn fullscreen off.