Personal cross-platform dotfiles managed with GNU Stow and a bootstrap.sh script. Primary target is macOS; Linux/devspaces supported via the same script. Compatible with Coder devspaces dotfiles.
This README is the cheat sheet for what to do when I sit down at a new (or another) machine.
git clone git@github.com:alexciarlillo/dotfiles.git ~/.dotfiles
cd ~/.dotfiles
./bootstrap.sh # installs packages + stows configs (detects macOS/Linux)Per-machine Claude setup: merge the hooks block from universal/.claude/README.md into ~/.claude/settings.json (that file is intentionally not stowed).
Point your devspace dotfiles setting at this repo. Coder clones it to /home/coder/.config/coderv2/dotfiles and runs bootstrap.sh automatically. It backs up the existing ~/.zshrc to ~/.zshrc.bak before stowing.
cd ~/.dotfiles
git pull
./bootstrap.sh # re-stows configs + installs any new packagesTo re-link configs without reinstalling packages:
./bootstrap.sh dots- Edit the file inside
~/.dotfiles/(not the symlink target in~). Most~/.foofiles are already symlinks pointing into this repo, so editing~/.zshrceditsuniversal/.zshrc. That's fine. - Commit and push:
cd ~/.dotfiles && git add -A && git commit -m "describe the change" && git push
- On the other machine:
git pull && ./bootstrap.sh - Note what changed in
CHANGELOG.md.
dotfiles/
bootstrap.sh Entry point — detects OS, installs packages, stows configs
universal/ Cross-platform configs — stowed into ~
osx/ macOS-only (AeroSpace, Hammerspoon, Sublime) — stowed into ~
linux/ Linux-only (i3, polybar, compton) — stowed into ~
extra/ NOT stowed — used by bootstrap.sh
homebrew/ Brewfile
apt/ packages.txt
The directory layout inside universal/ / osx/ / linux/ mirrors $HOME. So universal/.config/nvim/init.lua ends up at ~/.config/nvim/init.lua.
Per-package .stow-local-ignore files keep things like .DS_Store and .local/ out of the symlink pass.
- Zsh (
universal/.zshrc,universal/.config/zsh/) — aliases,twork-*tmux helpers, Vault helpers, worktree helpers - WezTerm (
universal/.wezterm.lua) — primary terminal - Tmux (
universal/.tmux.conf,universal/.config/tmux/tmux.conf.user) — prefixC-Space, vim-style pane nav, bell-based notifications
- Neovim (
universal/.config/nvim/) — LazyVim base with custom plugin configs inlua/plugins/and overrides inlua/config/ - Vim (
universal/.vimrc) — minimal fallback
- Git (
universal/.gitconfig,universal/.gitignore_global) - Ripgrep (
universal/.ripgreprc) - Lazygit (
universal/.config/lazygit/)
- AeroSpace (
osx/.aerospace.toml) — tiling WM with workspace keybindings - Hammerspoon (
osx/.hammerspoon/) — window manipulation and automation
- i3, polybar, compton, dunst — under
linux/.config/
universal/.claude/ — hook scripts that surface Claude state in the tmux window name and ring the terminal bell. See universal/.claude/README.md. ~/.claude/settings.json is per-machine and not stowed.
Paired tmux sessions (edit, agent, adhoc) keyed by window name, defined in universal/.config/zsh/tmux:
| Function | What it does |
|---|---|
twork-init |
Creates all three sessions, wires after-select-window hooks |
twork-new [name] <path> |
Opens a paired window across all three sessions |
twork-close [name] |
Kills the paired windows |
twork-edit / twork-agent / twork-adhoc |
Attach to the named session |
twork-sync |
Sync current pane's cwd to paired windows |
twork-ls |
List active projects |
Claude hooks (universal/.claude/hooks/notify-tmux.sh) annotate window names with ⠋ (working) or ? (needs input) across all three sessions, plus a red bell flag that clears on focus.
- Drop it into
universal/(orosx//linux/) at the path it should have under$HOME. E.g.~/.config/foo/bar.toml→universal/.config/foo/bar.toml. ./bootstrap.sh dots— Stow creates the symlink.- Commit and push.
If an app rewrites its config on launch (clobbers symlinks), put the source of truth in extra/ and add a copy step to bootstrap.sh instead of stowing it.
- macOS: edit
extra/homebrew/Brewfile, then./bootstrap.sh. - Linux: edit
extra/apt/packages.txt, then./bootstrap.sh.
Stow doesn't automatically clean up symlinks for files you deleted from the repo. Unstow manually:
stow --delete --target="$HOME" --dir="$PWD" universal- Cross-platform stuff →
universal/. Platform-specific (WM, GUI app, hardware) →osx/orlinux/. - Per-machine state (
~/.claude/settings.json, shell history, secrets) stays out of the repo. - Changes are tracked in
CHANGELOG.md— just a running log, not formal releases.
| I want to... | Run |
|---|---|
| Set up a brand new machine | ./bootstrap.sh |
| Pull latest changes | git pull && ./bootstrap.sh |
| Re-link configs after editing | ./bootstrap.sh dots |
| Unstow a removed file | stow --delete --target="$HOME" --dir="$PWD" universal |