Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Package management

Every package layer has a declarative text file and an idempotent install script. All scripts skip already-installed items — safe to re-run at any time.

The layers

LayerFileInstall scriptPlatform
System packagespackages/Brewfileinstall/homebrew.sh / install/linux-packages.shmacOS (bottles) / Linux (manylinux container)
Rust toolspackages/cargo.txtinstall/rust.shAll
Python packagespackages/pip.txtinstall/python.shAll
Global npmpackages/npm.txtinstall/npm.shAll
Claude pluginspackages/claude-plugins.txtinstall/claude.shAll
Claude MCP serverspackages/claude-mcp.txtinstall/claude.shAll

Adding a package — priority order

Choose the first layer that applies:

1. cargo — Rust crates

# packages/cargo.txt
ripgrep
fd-find

Re-run: bash ~/dotfiles/install/rust.sh

2. Homebrew — everything else

# packages/Brewfile
brew "tool-name"

# macOS-only (casks, GUI apps, macOS services)
if OS.mac?
  cask "some-app"
end

Re-run: brew bundle --file=~/dotfiles/packages/Brewfile

3. pip — Python packages

# packages/pip.txt
requests
black

Re-run: bash ~/dotfiles/install/python.sh

4. npm — npm-specific tools

# packages/npm.txt
@scope/package-name

Re-run: bash ~/dotfiles/install/npm.sh

5. Custom install script

Look at an existing install/ script for patterns, follow them, and add an INSTALL_* flag to bootstrap.sh.


Why cargo over Homebrew for some tools

fd, sd, and zoxide are in cargo.txt instead of Brewfile because:

  • $CARGO_HOME/bin is already under $LOCAL_PLAT/ — PLAT isolation is automatic
  • Rust crates compile cleanly from source on any platform
  • The Homebrew formula for these often just calls cargo install anyway

Do not install the same tool in both places. PLAT paths win on PATH — the Homebrew copy would install but never be used.


Why Homebrew for Linux

Homebrew on Linux installs inside a manylinux_2_28 container (AlmaLinux 8, glibc 2.28) so the compiled binaries work on any Linux host since ~2018. Most packages pour as precompiled bottles — no compilation needed. Homebrew bundles its own glibc 2.35, so the binaries are self-contained regardless of the host’s glibc version.

The same Brewfile works on macOS and Linux. if OS.mac? blocks (casks, GUI apps) are silently skipped on Linux.


Updating all packages

# Homebrew (macOS)
brew bundle --file=~/dotfiles/packages/Brewfile

# Homebrew (Linux) — re-run in container
bash ~/dotfiles/install/linux-packages.sh

# Cargo tools
bash ~/dotfiles/install/rust.sh

# Python venv
bash ~/dotfiles/install/python.sh

# Claude plugins + MCP servers
bash ~/dotfiles/install/claude.sh