PATH Ordering Strategy¶
Purpose: Define clear priority order for executable resolution across all platforms
PATH Priority Order¶
Listed from highest to lowest priority. First match wins during command execution.
~/.cargo/bin¶
- Rust tools installed via cargo-binstall (bat, fd, eza, delta, zoxide). Latest versions, takes precedence over everything.
~/.local/bin¶
- User-installed tools and scripts (neovim, lazygit, yq, fzf, yazi, custom scripts, theme, toolbox).
$ZSH_PLUGINS_DIR/forgit/bin¶
- Shell-specific Git utilities (forgit commands).
/usr/local/opt/.../bin¶
- Homebrew formula-specific binaries (postgresql@16, version-specific tools). macOS only.
~/.local/share/npm/bin¶
- npm global packages (TypeScript, ESLint, Prettier, language servers). macOS only.
/snap/bin¶
- Snap-packaged applications. Linux only.
/opt/nvim/bin¶
- Neovim extracted location (symlinked to ~/.local/bin). Linux only.
/usr/local/go/bin¶
- Go toolchain for building fzf (go, gofmt, etc.). Linux only.
~/go/bin¶
- User-compiled Go binaries (sess, toolbox - our Go CLI apps).
/usr/bin¶
- System packages (zsh, tmux, basic utilities). Lowest priority.
/usr/local/bin¶
- Homebrew/manually installed system-wide tools. macOS only.
/usr/local/sbin¶
- Homebrew system daemons and admin tools. macOS only.
Implementation Pattern¶
# add_path PREPENDS, so reverse order (last call = highest priority)
# System (will be lowest priority)
add_path "/usr/bin"
add_path "/usr/local/bin"
add_path "/usr/local/sbin"
# Platform-specific development tools
if [[ "$OSTYPE" == "darwin"* ]]; then
add_path "/usr/local/opt/postgresql@16/bin"
add_path "~/.local/share/npm/bin"
add_path "~/go/bin"
else
# Linux
add_path "/snap/bin"
add_path "/opt/nvim/bin"
add_path "/usr/local/go/bin"
add_path "~/go/bin"
fi
# Common (will be higher priority)
add_path "$ZSH_PLUGINS_DIR/forgit/bin"
add_path "~/.local/bin" # User tools
add_path "~/.cargo/bin" # Rust tools (HIGHEST)
Tool Resolution Examples¶
Example 1: bat command¶
$ which bat
/Users/chris/.cargo/bin/bat # cargo-binstall version (latest)
# Not: /usr/bin/batcat (apt version, older)
Example 2: nvim command¶
$ which nvim
/Users/chris/.local/bin/nvim # Symlink to latest GitHub release
# Not: /usr/bin/nvim (apt version 0.9.5, too old)
Example 3: fd command¶
$ which fd
/Users/chris/.cargo/bin/fd # cargo-binstall version (latest, correct name!)
# Not: /usr/bin/fdfind (apt version, wrong name)
Example 4: go command¶
$ which go
/usr/local/go/bin/go # Latest from go.dev
# Not: /usr/bin/go (apt version 1.22, outdated)
Debugging PATH Issues¶
# Show current PATH in readable format
echo $PATH | tr ':' '\n' | nl
# Find all instances of a command
which -a nvim
# Show what would execute
type bat
# Full PATH info
echo $PATH
Design Principles¶
- User space first:
~/.cargo/binand~/.local/binoverride everything - Language ecosystems: Each package manager has its own bin directory
- System packages last:
/usr/binis lowest priority (stable but outdated) - Platform-aware: macOS and Linux have different requirements
- Explicit over implicit: Clear why each directory is at its priority level
Maintenance¶
When adding new PATH directories:
- Determine priority: Does it need to override system or user tools?
- Add in correct position: Remember add_path prepends
- Document rationale: Update this file with why it's placed there
- Test resolution: Use
which -ato verify correct tool is found first