Custom command-line tooling is one of the most effective ways to improve your workflow. Whether you’re automating repetitive tasks, organizing project scripts, or creating a small internal CLI, adding autocomplete makes your tool feel polished, fast, and user-friendly.
In this tutorial, we’ll walk step-by-step through how to build a custom Zsh autocomplete function, using a simple file-lookup command as the foundation. While the example maps logical keys to file paths, the technique is fully generic and can be applied to anything—API commands, Kubernetes actions, internal scripts, or even entire CLI frameworks.

⁉️Why Create a Custom Autocomplete?
Autocomplete dramatically improves usability:
- Reduces typing effort
- Avoids memorizing long or cryptic options
- Prevents mistakes (typos, invalid arguments)
- Makes simple shell functions feel like full CLI tools
With a small amount of Zsh scripting, you can provide intelligent suggestions for your custom commands.
1. The Base Command
Let’s start with a simple shell function that accepts a keyword as argument and performs an action. In our example, each keyword corresponds to a file path stored in an associative array.
mytool() {
local -A FILES=(
[config]="/path/to/project/config.yaml"
[build]="/path/to/scripts/build.sh"
[deploy]="/path/to/scripts/deploy.sh"
[test]="/path/to/scripts/test-suite.sh"
)
if [[ -z "$1" ]]; then
echo "❗ You must specify a parameter. Available keys:"
for key in "${(@k)FILES}"; do
echo " - $key → ${FILES[$key]}"
done
return 1
fi
local KEY="$1"
if [[ -z "${FILES[$KEY]}" ]]; then
echo "❗ Unknown parameter: $KEY"
return 1
fi
local FILE="${FILES[$KEY]}"
if [[ ! -f "$FILE" ]]; then
echo "❗ The file '${FILE}' does not exist!"
return 1
fi
pbcopy < "$FILE"
echo "✅ Success!"
}What this function does:
- Defines a mapping of keys → paths
- Validates the user input
- Performs a final action (
pbcopyis just an example)
The missing piece is autocomplete.
2. Creating the Autocomplete Function
To enable autocomplete, Zsh expects a helper function following a specific naming pattern:
_<commandname>()
So if your command is mytool, the autocomplete handler should be:
_mytool() {
local -a keys
keys=(config build deploy test)
_arguments -C '1:select an action:('"${keys[*]}"')'
}Key parts explained:
local -a keys
Declares an array of valid suggestions.
keys=(...)
Populates the array with valid autocomplete values.
These must match the keys defined inside mytool().
_arguments -C '1:...:()'
Tells Zsh that:
- This autocomplete applies to the first argument (
1:) - The description text appears in tab-completion menus
- The list inside parentheses defines the allowed values
3. Registering the Autocomplete
Finally, tell Zsh that autocomplete for mytool should be handled by _mytool:
compdef _mytool mytool
Once this line is sourced, pressing TAB after typing:
mytool <TAB>
will display the list of keys.
4. Installing the Script
Save the entire script in a file, for example:
~/.zsh/mytool-autocomplete.zsh
Then source it from your .zshrc:
source ~/.zsh/mytool-autocomplete.zsh
Refresh your shell:
source ~/.zshrc
🎉 Now your autocomplete is live!
5. Making It Generic
This autocomplete pattern can be adapted to any workflow:
✅ Script runners
Map keywords to CI scripts, build scripts, or test scripts.
✅ Kubernetes helpers
Autocomplete namespace names, deployments, or contexts.
✅ API clients
Offer subcommands like list, create, update, etc.
✅ File shortcuts
Provide quick access to templates, configuration files, or documentation.
You can even generate the list dynamically—reading from directories, Git branches, or JSON files.
6. Tips for Improving Your CLI
Here are some enhancements you might want to add:
- Dynamic key generation using filesystem scanning
- Multi-argument autocomplete
- Option flags (
--force,--verbose, …) - Command help using
--help - Colorized output for clarity
- Logging for debugging
Zsh’s completion system is extremely powerful, and this tutorial only scratches the surface.
Conclusion
By combining a simple shell function with a custom Zsh completion handler, you can create lightweight but highly ergonomic CLI utilities. These tools help streamline your workflow, reduce errors, and feel much more professional.
Adding autocomplete is not only easy—it’s one of the highest-impact improvements you can make for any internal script or tooling.
If you’re building your own developer utilities, this is a great feature to start with.