ZSH + Oh My Zsh
Overview
ZSH is a powerful Unix shell with superior tab-completion, globbing, and plugin support. Combined with Oh My Zsh, it becomes a fully customized development environment — themeable, extensible, and configured through a clean $ZSH_CUSTOM/ directory structure. This reference documents a production-ready setup tuned for daily development across Java, Python, Node, Rust, Go, and Kubernetes workflows.
The config files live in an Oh My Zsh custom/ directory ($ZSH_CUSTOM) and are loaded automatically. Files in custom/ are sourced after Oh My Zsh core and before plugins, making them the ideal place for overrides.
$ZSH_CUSTOM/
├── alias.zsh # User-defined aliases
├── config.zsh # PATH, SDK roots, toolchain init
├── environment.zsh # Editor, JAVA_HOME, GOPATH
├── keyboard.zsh # Custom keybindings
├── kube.zsh # kubectl completion + shorthand
├── plugin.zsh # Plugin declarations
├── theme.zsh # Agnoster theme overrides
└── themes/ # Custom theme files
Aliases (alias.zsh)
alias.zsh centralizes every shell shortcut — Git operations, Python virtualenvs, infrastructure tools, and browser profiles — so daily commands are just a few keystrokes. Oh My Zsh sources it automatically on startup.
# ── Oh My Zsh quick-open ──
alias zshconfig="code ~/.zshrc"
alias ohmyzsh="code ~/.oh-my-zsh"
# ── Git shortcuts ──
alias gc='git commit -m'
alias gp='git push'
alias gm='git merge'
alias gs='git switch'
alias ga='git add'
# ── Python ──
alias py='python3'
alias act='source .venv/bin/activate'
alias dact='deactivate'
# ── Development tools ──
alias ls='ls -la'
alias c='code'
alias cf='copyfile'
# ── Colored ls ──
alias ls='ls --color=auto'
alias ll='ls -alF --color=auto'
alias la='ls -A --color=auto'
alias l='ls -CF --color=auto'
# ── Infrastructure ──
alias tf='terraform'
# ── Browser profiles ──
alias unsafe-chrome='google-chrome --disable-web-security --user-data-dir="/tmp/chrome-dev"'
Environment Variables (environment.zsh)
environment.zsh exports the variables every toolchain and editor relies on: the default Git editor, the Java home, the Android SDK root, and extra PATH entries that make nvim and Go binaries globally available.
# ── Default editor ──
export GIT_EDITOR=vim
# ── Java ──
export JAVA_HOME="/usr/lib/jvm/java-21-openjdk-amd64"
# ── Android SDK ──
export ANDROID_SDK_ROOT="$HOME/Android/Sdk"
export ANDROID_HOME="$HOME/Android/Sdk"
# ── Python virtualenv ──
export VIRTUAL_ENV_DISABLE_PROMPT=1
# ── Additional PATHs ──
export PATH="/opt/nvim-linux-x86_64/bin:$PATH"
export PATH="$HOME/go/bin:$PATH"
Toolchain Configuration (config.zsh)
Key sections for initializing toolchain runtime managers. Each block can be commented in/out as needed.
# ── PyEnv ──
export PYENV_ROOT="$HOME/.pyenv"
export PATH="$PYENV_ROOT/bin:$PATH"
eval "$(pyenv init --path)"
eval "$(pyenv init -)"
eval "$(pyenv virtualenv-init -)"
# ── Rust / Cargo ──
export PATH="$HOME/.cargo/bin:$PATH"
# ── SBIN ──
export PATH="/sbin:$PATH"
# ── Custom User Binaries ──
export PATH="$HOME/bin:$PATH"
export PATH="/usr/local/go/bin:$PATH"
# ── NVM (Node Version Manager) ──
. /usr/share/nvm/nvm.sh
. /usr/share/nvm/bash_completion
# ── File descriptor limit ──
ulimit -SHn 2000
# ── Colors ──
eval $(dircolors -b ~/.dir_colors)
Platform SDK paths
| Variable | Typical location | Toolchain |
|---|---|---|
ANDROID_HOME | ~/Android/Sdk | Android SDK / adb |
JAVA_HOME | /usr/lib/jvm/java-21-openjdk-amd64 | Java 21 |
GOPATH | ~/go | Go modules |
PYENV_ROOT | ~/.pyenv | Python version manager |
CARGO_HOME | ~/.cargo | Rust toolchain |
Keyboard Bindings (keyboard.zsh)
ZLE (Zsh Line Editor) supports both bindkey for readline-style controls:
# ── Word navigation ──
bindkey "^[[1;5D" backward-word # Ctrl+Left
bindkey "^[[1;5C" forward-word # Ctrl+Right
Common escape sequences
| Shortcut | Escape sequence | ZLE widget |
|---|---|---|
Ctrl+Left | ^[[1;5D | backward-word |
Ctrl+Right | ^[[1;5C | forward-word |
Ctrl+A | ^A | beginning-of-line |
Ctrl+E | ^E | end-of-line |
Ctrl+U | ^U | backward-kill-line |
Ctrl+K | ^K | kill-line |
Ctrl+W | ^W | backward-kill-word |
:::tip Finding an escape sequence
Run cat -v then press the key combination. The terminal will print the raw escape sequence, e.g., ^[[1;5D.
:::
Kubernetes Integration (kube.zsh)
Load kubectl completion and set up the k shorthand with full autocomplete:
source <(kubectl completion zsh)
alias k=kubectl
compdef __start_kubectl k
This provides tab-completion on pods, namespaces, contexts, and all kubectl subcommands under both kubectl and k.
Plugin System (plugin.zsh)
Plugins are declared as a ZSH array. They load from $ZSH/plugins/ (built-ins) or $ZSH_CUSTOM/plugins/ (custom):
plugins=(
git
zsh-syntax-highlighting
zsh-autosuggestions
sudo
web-search
copyfile
macos
dirhistory
copybuffer
)
| Plugin | Purpose |
|---|---|
git | Git aliases and branch status in prompt |
zsh-syntax-highlighting | Real-time command syntax coloring |
zsh-autosuggestions | Fish-style gray autosuggestions |
sudo | Press Esc twice to prepend sudo |
web-search | google, stackoverflow commands |
copyfile | Copies file contents to clipboard |
dirhistory | Alt+Left/Right to navigate directory history |
copybuffer | Ctrl+O copies current command to clipboard |
Custom plugins
Place third-party plugins in $ZSH_CUSTOM/plugins/<name>/:
# Clone directly into the custom plugins directory
git clone https://github.com/zsh-users/zsh-autosuggestions \
$ZSH_CUSTOM/plugins/zsh-autosuggestions
git clone https://github.com/zsh-users/zsh-syntax-highlighting \
$ZSH_CUSTOM/plugins/zsh-syntax-highlighting
Theme Customization (theme.zsh)
This setup uses the agnoster theme with overrides for git colors, virtualenv display, and a curated set of prompt emoji:
# ── Color palette ──
BLACK='#2b2b2b'
# ── Git state colors (agnoster) ──
ZSH_THEME_GIT_PROMPT_CLEAN_COLOR=green
ZSH_THEME_GIT_PROMPT_CLEAN_BG=$BLACK
ZSH_THEME_GIT_PROMPT_DIRTY_COLOR=008000
ZSH_THEME_GIT_PROMPT_DIRTY_BG=$BLACK
# ── Disable default status indicator ──
prompt_status() {}
# ── Virtualenv indicator (🐍 + name on blue background) ──
prompt_virtualenv() {
local venv=""
if [ -n "$VIRTUAL_ENV" ] && [ -n "${VIRTUAL_ENV##*disable*}" ]; then
venv="$(basename "$VIRTUAL_ENV")"
prompt_segment blue $BLACK "🐍 $venv"
fi
}
# ── Random emoji context (space/tech/hacker themes) ──
emoji=(
"👾" "👽" "🛸" "🪐" "🚀" "💻" "🖥️" "⌨️"
"🔮" "⚡" "🧪" "🧬" "🤖" "📡" "🔧" "✨"
)
prompt_context() {
local emoji_choice="${emoji[$(( $RANDOM % ${#emoji[@]} + 1 ))]}"
prompt_segment black default "%{%F{$BLACK}%}$emoji_choice%{%f%}"
}
# ── Directory display (current folder only) ──
prompt_dir() {
prompt_segment blue $BLACK '%c'
}
# ── Disable syntax-highlighting path underline ──
ZSH_HIGHLIGHT_STYLES[path]=none
ZSH_HIGHLIGHT_STYLES[path_prefix]=none
Agnoster prompt anatomy
Here is how the segments of the agnoster prompt fit together — each labeled part maps to one of the prompt_* functions defined in theme.zsh above:
👾 ~/projects/stack-garden master ● 10:42:42
│ │ │ │ │
│ └─ prompt_dir │ │ └─ right prompt (time)
└─ prompt_context │ └─ prompt_git (branch + dirty)
└─ prompt_end (arrow indicator)
Each segment is a prompt_segment bg_color fg_color "text" call. Override any segment by redefining its function in theme.zsh.
Key Plugins in Detail
zsh-autosuggestions
Fish-style autosuggestions appear as ghosted gray text as you type. Press Right arrow or End to accept.
| Configuration variable | Default | Description |
|---|---|---|
ZSH_AUTOSUGGEST_HIGHLIGHT_STYLE | fg=8 | Suggestion appearance |
ZSH_AUTOSUGGEST_STRATEGY | (history) | Strategies: history, completion, match_prev_cmd |
ZSH_AUTOSUGGEST_BUFFER_MAX_SIZE | — | Disable suggestions for large buffers (recommended: 20) |
Key bindings:
| Widget | Key (default) | Action |
|---|---|---|
autosuggest-accept | Right / End | Accept entire suggestion |
autosuggest-execute | — | Accept and execute immediately |
autosuggest-clear | — | Dismiss current suggestion |
autosuggest-fetch | Ctrl+Space | Manually trigger suggestion |
autosuggest-disable | — | Turn off autosuggestions |
autosuggest-enable | — | Turn on autosuggestions |
autosuggest-toggle | — | Toggle on/off |
# Example: accept suggestion with Ctrl+F
bindkey '^F' autosuggest-accept
# Example: use history + match_prev_cmd strategies
ZSH_AUTOSUGGEST_STRATEGY=(history match_prev_cmd)
zsh-syntax-highlighting
Real-time syntax coloring while you type — commands turn green, invalid paths turn red, quotes and expansions get distinct colors. No configuration required; it works immediately after sourcing.
| Config variable | Effect |
|---|---|
ZSH_HIGHLIGHT_HIGHLIGHTERS | Array of active highlighters (default: main) |
ZSH_HIGHLIGHT_MAXLENGTH | Buffer length at which highlighting turns off |
ZSH_HIGHLIGHT_STYLES[path]=none | Disable path underlining |
ZSH_HIGHLIGHT_PATTERNS | Custom glob pattern → style mappings |
ZSH_HIGHLIGHT_REGEXP | Custom regex → style mappings |
# Enable brackets + pattern highlighters in addition to main
ZSH_HIGHLIGHT_HIGHLIGHTERS=(main brackets pattern)
# Highlight \`rm -rf\` in red
ZSH_HIGHLIGHT_PATTERNS+=('rm -rf *' 'fg=white,bold,bg=red')
# Highlight \`TODO\` in comments
ZSH_HIGHLIGHT_PATTERNS+=(' *TODO*' 'fg=yellow,bold')
Syntax highlighting must be sourced at the very end of .zshrc, after all other plugins and config, because it wraps ZLE widgets.
See also
- VS Code — Editor configuration and extensions
- Vim — Terminal-based editing workflows
- Bash — Shell scripting reference
- Kubernetes — kubectl, manifests, and cluster operations