ev - progressive zsh command suggestions
August 5, 2026 · View on GitHub
ev is a Zsh / Oh My Zsh plugin for progressive command autocomplete: a selectable suggestion list under your prompt that deepens as you type - commands → subcommands → flags.
Use it as a zsh-autosuggestions alternative when you want a navigable list (not only ghost text), including git, gh, docker, and other CLI subcommands.
Repository: https://github.com/emhat098/ev
Shows a ranked list below the line and continues into subcommands and flags:
❯ git st
▸ status
stash
switch
❯ git status -
▸ -v
--verbose
-sb
Works in Linux terminals and iTerm2 (macOS). Install with Oh My Zsh, Zinit, Antigen, Zplug, or a plain source.
What it's for
| If you want… | ev does this |
|---|---|
| Faster CLI typing in zsh | Suggests matching tools from your PATH cache |
| Git / GitHub CLI help while typing | g → git, git s → status, gh repo l → list |
Flag discovery without memorizing --help | Suggests next tokens / flags from curated chains + help cache |
| A list you can navigate | ↑/↓ select · Tab accept · Enter runs (or accepts after ↑/↓) |
| No lag while typing | Prefix lookup only; rebuild with ev-rebuild-cache when tools change |
Suggestions come from a local cache (PATH tools + curated chains + optional --help discovery). Typing only does prefix lookups - the cache is never rebuilt on shell start or while you type. Refresh it yourself with ev-rebuild-cache when tools or chains change.
Requirements
- Zsh 5.9+ (
add-zle-hook-widget) - Optional: Oh My Zsh (recommended)
- Optional:
timeout(coreutils) to cap slow--helpcalls during cache build
Installation
Latest release: v1.0.0
Oh My Zsh
-
Clone this repository into oh-my-zsh's custom plugins directory:
# HTTPS git clone https://github.com/emhat098/ev.git \ ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/ev # or SSH git clone git@github.com:emhat098/ev.git \ ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/ev # or GitHub CLI gh repo clone emhat098/ev ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/evOr from a local checkout of this repo:
./install.sh./install.shsymlinks the plugin, updatesplugins=(...), adds late keybinds, and builds the cache once. -
If you cloned manually (skipped
./install.sh), add the plugin in~/.zshrc:plugins=( # ... other plugins ev zsh-syntax-highlighting # keep near the end if you use it zsh-history-substring-search ) -
Restart the shell, then build the cache if you have not already (required after a plain clone):
exec zsh ev-rebuild-cache
Note: If you use
zsh-history-substring-search, run./install.sh(or append the keybind block from that script) so ↑/↓ still navigate ev's list when it is visible. The installer adds bindings after other plugins load.
Antigen
antigen bundle emhat098/ev
antigen apply
Then restart and build the cache:
exec zsh
ev-rebuild-cache
Zinit
zinit light emhat098/ev
exec zsh
ev-rebuild-cache
Zplug
zplug "emhat098/ev", as:plugin
exec zsh
ev-rebuild-cache
Manual (no framework)
git clone https://github.com/emhat098/ev.git ~/.zsh/ev
# or: gh repo clone emhat098/ev ~/.zsh/ev
echo 'source ~/.zsh/ev/ev.plugin.zsh' >> ~/.zshrc
exec zsh
ev-rebuild-cache
Usage
Type normally at your prompt. While you are completing a known command chain, suggestions appear under the line.
g→gitgit s→statusgit status→-v,--short, …gh repo l→list
Press Tab to accept the highlighted suggestion (e.g. g → git ). Use ↑/↓ to move in the list, then Enter to accept that selection. Plain Enter (without ↑/↓) runs the line as typed.
After you install or remove CLIs, or edit chains.zsh, run ev-rebuild-cache so the list picks up the changes.
Key bindings
| Key | Widget / action |
|---|---|
| ↑ / ↓ | Previous / next suggestion (history when the list is hidden) |
| Tab | Accept highlighted suggestion |
| Enter | Run the line; after ↑/↓, accept the selected suggestion instead |
| Shift-Tab / Ctrl+P | Previous suggestion |
| Ctrl+N | Next suggestion |
| Alt+Space | Accept highlighted suggestion |
| Ctrl+G | Hide suggestion list |
Widgets you can rebind with bindkey after the plugin loads:
ev-tab/ev-enterev-up/ev-downev-prev/ev-nextev-hideev-accept-widget
Example:
bindkey '^ ' ev-accept-widget
Configuration
Override these variables in ~/.zshrc before the plugin is loaded (or export them in the environment).
| Variable | Default | Description |
|---|---|---|
EV_ENABLED | 1 | Set to 0 to disable the suggestion UI |
EV_MAX | 10 | Maximum rows shown in the list |
EV_TMP | ${XDG_CACHE_HOME:-~/.cache}/ev | Cache directory (persists across reboots; overrides XDG default) |
EV_HELP_TIMEOUT | 1 | Seconds per --help / -h call during ev-rebuild-cache |
EV_HELP_MAX_DEPTH | 2 | Nested help discovery depth (root = 0) |
EV_HELP_MAX_CALLS | 60 | Max help invocations per cache build |
EV_MAX=12
EV_HELP_MAX_CALLS=80
Cache
The index under $EV_TMP is load-only at runtime:
- Shell start - loads
$EV_TMP/index.zshif it exists; does not scanPATHor run--help - While typing - prefix map lookups only
- Rebuild - only when you run
ev-rebuild-cache(or when./install.shbuilds once during setup)
ev-rebuild-cache
If no cache exists yet, startup prints:
ev: no suggestion cache yet - run: ev-rebuild-cache
Rebuild after:
- Installing, upgrading, or removing CLI tools
- Editing
chains.zsh - Changing help-discovery limits and wanting a fuller index
Cache files: index.zsh, stamp, commands.txt, chains/ under $EV_TMP (default ${XDG_CACHE_HOME:-~/.cache}/ev/). A one-time migrate copies an older /tmp/ev-$UID cache if present.
Customizing chains
Edit chains.zsh. Keys are colon-separated command paths; values are next tokens (earlier = higher rank for short prefixes):
_EV_CHAINS[mycli]="init build deploy status"
_EV_CHAINS[mycli:deploy]="--env --dry-run --force"
Then run ev-rebuild-cache.
At build time, discover.zsh also runs CMD --help / -h / help and merges discovered subcommands and flags (cobra, gh, click, argparse styles; with depth and call limits). Nested help is skipped for tools that tend to block (for example docker <subcommand> --help).
File layout
| File | Purpose |
|---|---|
ev.plugin.zsh | Main plugin entry (Oh My Zsh / Antigen / Zinit load this) |
chains.zsh | Curated next-token catalogs |
discover.zsh | --help / -h discovery (used only during rebuild) |
build-cache.zsh | Builds $EV_TMP/index.zsh (invoked by ev-rebuild-cache) |
stamp.zsh | Cache fingerprint helpers for build-cache.zsh |
install.sh | Optional Oh My Zsh helper (symlink, keys, one-time cache build) |
tests/ | Unit tests (zsh tests/run.zsh) |
Testing
zsh tests/run.zsh
Covers stamp fingerprints, help parsing, curated chains, cache build, progressive context parsing, command/next-token filtering, accept/nav widgets, and manual-only cache loading (no auto-rebuild on init).
Troubleshooting
- Message:
no suggestion cache yet- Runev-rebuild-cacheonce, then keep using the shell as usual. - No list appears - Confirm
evis inplugins=(...)(or sourced), thenexec zsh. CheckEV_ENABLEDis not0. Confirm$EV_TMP/index.zshexists. - Missing / stale commands - Installs do not refresh the index automatically. Run
ev-rebuild-cache. - Missing nested tokens (e.g.
gh repo list) - Rebuild cache; ensure the CLI is onPATH; add a node inchains.zshif needed. - ↑/↓ don't move the list - Re-run
./install.shso late keybindings are applied after history-substring-search. - Slow
ev-rebuild-cache- LowerEV_HELP_MAX_CALLSorEV_HELP_MAX_DEPTHin~/.zshrcbefore rebuilding.
ls -la "${EV_TMP:-${XDG_CACHE_HOME:-$HOME/.cache}/ev}/"
Uninstallation
-
Remove
evfrom theplugins=(...)list in~/.zshrc(or remove thesource …/ev.plugin.zshline). -
Remove the keybind block between
# >>> ev plugin keys >>>and# <<< ev plugin keys <<<if present. -
Delete the plugin and cache:
rm -rf ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/ev rm -rf "${EV_TMP:-${XDG_CACHE_HOME:-$HOME/.cache}/ev}" # or: rm -rf ~/.zsh/ev # manual install -
Restart the shell:
exec zsh.
Links
- Source: https://github.com/emhat098/ev
- Releases: https://github.com/emhat098/ev/releases
- Issues: https://github.com/emhat098/ev/issues
- Owner: @emhat098
License
MIT - see LICENSE.