Use when configuring, troubleshooting, or optimizing zsh: shell options, completion system, prompt customization, parameter expansion, glob qualifiers, .zshrc/.zprofile structure, and plugin management. Do not use for bash-only scripts, non-shell configuration, or writing new scripts from scratch.
.zshrc / .zprofile / .zshenv / .zlogin for correctness and fast startup.compinit, writing custom completers, debugging completion behavior.PROMPT/RPROMPT with escape sequences, vcs_info, prompt_subst.zprof, lazy loading, deferred init).Do NOT use for bash-only scripting that doesn't involve zsh, writing new scripts from scratch, non-shell configuration files, or agent/skill authoring.
.zshrc or related file, or "starting fresh"Zsh loads files in this order — the correct file depends on what's being configured:
| File | When loaded | Use for |
|---|---|---|
.zshenv | Always (every zsh invocation, including scripts) | Environment variables (PATH, EDITOR), no interactive config |
.zprofile | Login shells only | One-time setup (Homebrew shellenv, SSH agent) |
.zshrc | Interactive shells only | Aliases, functions, completions, prompt, plugins, key bindings |
.zlogin | Login shells, after .zshrc | Rarely used; login messages |
.zlogout | Login shell exit | Cleanup tasks |
Common mistakes to check:
.zshrc instead of .zshenv (not available in non-interactive scripts)compinit called in .zshenv (too early, loads for non-interactive shells)eval "$(brew shellenv)" in .zshrc instead of .zprofile (runs on every shell, not just login)Based on the user's goal, follow the appropriate path:
Completion system setup:
# Basic completion init (place in .zshrc)
autoload -Uz compinit
compinit
# Enable menu-driven completion
zstyle ':completion:*' menu select
# Case-insensitive completion
zstyle ':completion:*' matcher-list 'm:{a-zA-Z}={A-Za-z}'
# Cache completions for speed
zstyle ':completion:*' use-cache on
zstyle ':completion:*' cache-path "${XDG_CACHE_HOME:-$HOME/.cache}/zsh/zcompcache"
Startup profiling:
# Add to top of .zshrc
zmodload zsh/zprof
# Add to bottom of .zshrc
zprof
# Then open a new shell and review the output
# Look for plugins/functions taking >50ms
Key zsh-specific syntax reference:
# Glob qualifiers — filter by file attributes
ls *(.) # regular files only
ls *(/) # directories only
ls *(.om[1,5]) # 5 most recently modified files
ls **/*.md(D) # include dotfiles in recursive glob
# Parameter expansion flags
echo ${(U)var} # uppercase
echo ${(L)var} # lowercase
echo ${(s:/:)PATH} # split on /
echo ${#array} # array length (1-indexed in zsh!)
# Array indexing (zsh arrays are 1-indexed!)
arr=(a b c)
echo $arr[1] # "a" (not "b" like bash)
echo $arr[-1] # "c" (negative indexing works)
When modifying zsh configuration files:
After making changes:
# Syntax check
zsh -n ~/.zshrc
# Test in a subshell (won't affect current session)
zsh -i -c 'echo "Config loaded OK"'
# If completion was changed, verify
zsh -i -c 'which compinit && echo "compinit available"'
# If startup perf was the goal, measure
time zsh -i -c exit
Confirm:
.zshenv / .zprofile / .zshrc)zsh -n)