Skip to main content
Navigation
HomeTechnical ReferenceJournalGitHubGitHub
Sidebar — toggle document categories via the logo
Categories

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

VariableTypical locationToolchain
ANDROID_HOME~/Android/SdkAndroid SDK / adb
JAVA_HOME/usr/lib/jvm/java-21-openjdk-amd64Java 21
GOPATH~/goGo modules
PYENV_ROOT~/.pyenvPython version manager
CARGO_HOME~/.cargoRust 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

ShortcutEscape sequenceZLE widget
Ctrl+Left^[[1;5Dbackward-word
Ctrl+Right^[[1;5Cforward-word
Ctrl+A^Abeginning-of-line
Ctrl+E^Eend-of-line
Ctrl+U^Ubackward-kill-line
Ctrl+K^Kkill-line
Ctrl+W^Wbackward-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
)
PluginPurpose
gitGit aliases and branch status in prompt
zsh-syntax-highlightingReal-time command syntax coloring
zsh-autosuggestionsFish-style gray autosuggestions
sudoPress Esc twice to prepend sudo
web-searchgoogle, stackoverflow commands
copyfileCopies file contents to clipboard
dirhistoryAlt+Left/Right to navigate directory history
copybufferCtrl+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 variableDefaultDescription
ZSH_AUTOSUGGEST_HIGHLIGHT_STYLEfg=8Suggestion appearance
ZSH_AUTOSUGGEST_STRATEGY(history)Strategies: history, completion, match_prev_cmd
ZSH_AUTOSUGGEST_BUFFER_MAX_SIZEDisable suggestions for large buffers (recommended: 20)

Key bindings:

WidgetKey (default)Action
autosuggest-acceptRight / EndAccept entire suggestion
autosuggest-executeAccept and execute immediately
autosuggest-clearDismiss current suggestion
autosuggest-fetchCtrl+SpaceManually trigger suggestion
autosuggest-disableTurn off autosuggestions
autosuggest-enableTurn on autosuggestions
autosuggest-toggleToggle 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 variableEffect
ZSH_HIGHLIGHT_HIGHLIGHTERSArray of active highlighters (default: main)
ZSH_HIGHLIGHT_MAXLENGTHBuffer length at which highlighting turns off
ZSH_HIGHLIGHT_STYLES[path]=noneDisable path underlining
ZSH_HIGHLIGHT_PATTERNSCustom glob pattern → style mappings
ZSH_HIGHLIGHT_REGEXPCustom 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')
caution

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