ZSH completion system patterns and conventions. Use when implementing custom completion handling, writing completion files, or working with zsh autocomplete. Do not use when installing packages from homebrew, since that typically installs completions automatically.
Guide for writing and managing custom ZSH completion files in this dotfiles repository.
Do NOT use when installing homebrew packages - they handle completions automatically.
Completion files in this repo use: <topic>/completion.zsh
Example: claude/completion.zsh
From zsh/zshrc:
compinit is called to initialize the completion system*/completion.zsh files are sourcedfpath#!/usr/bin/env zsh
# Define completion function
_toolname() {
local line state
# Define options
local -a options=(
'-h[Display help]'
'--help[Display help]'
)
# Define subcommands
local -a subcommands=(
'command:Description'
)
_arguments -C \
"${options[@]}" \
'1: :->command' \
'*::arg:->args'
case $state in
command)
_describe -t commands 'tool command' subcommands
;;
args)
# Handle subcommand args
;;
esac
}
# Register completion
compdef _toolname toolname
Use compdef at the end of the file:
compdef _toolname toolname
NOT the #compdef directive (that's for files in fpath).
local -a options=(
'-h[Display help]'
'--help[Display help]'
'--flag[Description]'
'--option[Description]:value:'
'--file[Description]:file:_files'
'--dir[Description]:directory:_directories'
)
local -a subcommands=(
'command:Description'
'subcommand:What it does'
)
_describe -t commands 'tool command' subcommands
_arguments -C \
"${options[@]}" \
'1: :->command' \
'*::arg:->args'
case $state in
command)
_describe -t commands 'tool command' subcommands
;;
args)
case ${line[1]} in
subcommand)
_arguments \
'--subcommand-option[Description]' \
'1:arg:'
;;
esac
;;
esac
For tools like git or docker with deep command hierarchies:
_tool_subcommand() {
local line state
local -a sub_subcommands=(
'action:Description'
)
_arguments -C \
'1: :->command' \
'*::arg:->args'
case $state in
command)
_describe -t commands 'tool subcommand command' sub_subcommands
;;
esac
}
Built-in zsh completion functions:
_files - File paths_directories - Directory paths_values - Predefined values_describe - Command descriptions_arguments - Argument parsing'--config[Config file]:file:_files'
'--format[Output format]:format:(json yaml text)'
'--env[Environment variables]:env:' # Free form
'--scope[Scope]:scope:(local user project)' # Fixed choices
After creating/modifying a completion file:
source ~/.zshrctool <TAB>tool subcommand <TAB>tool --<TAB>Steps to create completions for a new tool:
tool --help to see main optionstool subcommand --help for each subcommand<topic>/completion.zsh_toolname() function with all discovered optionscompdef _toolname toolnameThe completion function is being executed instead of sourced. Ensure:
completion.zsh (not completions.zsh)compdef (not #compdef)Using #compdef directive when file is sourced directly. Use compdef registration instead.
*/completion.zshecho $ZSH/**/*.zsh | grep completionzsh -n path/to/completion.zshSee existing completion files:
claude/completion.zsh - Complex multi-level subcommandsgcloud/completions.zsh - Third-party completion sourcingCategory:developer