Idempotent Mac development environment managed with GNU Stow + Homebrew Bundle.
curl -fsSL https://raw.githubusercontent.com/moruklabs/dotfiles/main/bootstrap.sh | bashcd ~/.dotfiles
make install # Full setup (brew + stow + shell + macos defaults)
make update # Pull latest, update packages, re-stow
make brew # Install/update Homebrew packages only
make stow # Re-link config files only (auto-locks after)
make macos # Re-apply macOS defaults only
make protect # Lock config files (prevent installer modifications)
make unprotect # Unlock config files (for manual editing)
make protect-status # Show lock state of managed configsgit, gh, curl, wget, jq, tree, htop, ripgrep, fd, bat, eza, fzf, tmux, zoxide, starship, tldr, stow
- Node.js 24 LTS (via mise)
- Python 3.13 (via uv)
- Go 1.26 (via mise)
- Rust 1.94 (via rustup + mise)
- Bun 1.2 (via mise)
VS Code, Zed, JetBrains Toolbox, Raycast, Rectangle, Slack, Notion, Spotify, Discord, Docker Desktop, Obsidian
JetBrains Mono Nerd Font, Fira Code Nerd Font
~/.dotfiles/
├── Brewfile # Declarative packages, casks, fonts
├── Makefile # Orchestration
├── bootstrap.sh # One-command fresh machine setup
├── scripts/
│ ├── brew.sh # Homebrew install + bundle
│ ├── macos.sh # macOS system defaults
│ ├── shell.sh # Language toolchain setup
│ ├── duti.sh # File association defaults
│ └── protect.sh # Lock/unlock configs (chflags uchg)
├── zsh/
│ ├── .zshrc # Shell config (starship, zoxide, fzf, aliases)
│ └── .zsh/completions/ # Custom zsh completions (claude, etc.)
├── git/.gitconfig # Git settings
├── git/.gitignore_global # Global gitignore
├── tmux/.tmux.conf # tmux config
├── iterm2/ # iTerm2 dynamic profile (keybindings)
├── starship/.config/
│ └── starship.toml # Prompt theme
└── claude/.claude/ # Claude Code config, hooks, scripts
Each top-level directory is a GNU Stow package. Running stow zsh from ~/.dotfiles symlinks zsh/.zshrc to ~/.zshrc.
Add machine-specific config to ~/.zshrc.local (gitignored).
| Doc | Description |
|---|---|
| Architecture Decisions | Why GNU Stow, mise, uv, etc. |
| Post-Install Steps | Manual GUI setup after bootstrap |
| Cheatsheet | All aliases, keybindings, tool tricks |
| Extending | How to add packages, stow modules, languages |
| Tools Guide | Deep usage guide for each CLI tool |
| macOS Defaults | What each system default changes and why |
| Multi-Machine | Managing work vs personal, secrets, conditionals |
| Troubleshooting | Common issues and fixes |
| Python Toolchain (uv) | Why uv over pyenv, full command reference, migration guide |
| Local LLMs with MLX | MLX inference stack, model recommendations, setup guide for M5 Max |
| mise — Version Manager | Universal version manager replacing fnm/pyenv/goenv/SDKMAN |
| Node.js | Node 24 LTS, pnpm vs bun, TypeScript execution, package managers |
| Go | Go 1.26 features, version management, essential tools |
| Rust | Rust 1.94, rustup, editions, cargo tools, cross-compilation |
| Java | JDK 21/25 LTS, Temurin vs GraalVM, SDKMAN vs mise |
| Bun | Runtime + package manager, benchmarks, production readiness |
| Stack Decisions | Definitive versions & package managers for our Next.js/Expo/Firebase/CF Workers stack |