ev - progressive zsh command suggestions

August 5, 2026 · View on GitHub

GitHub Release Tests License: MIT

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 zshSuggests matching tools from your PATH cache
Git / GitHub CLI help while typingggit, git sstatus, gh repo llist
Flag discovery without memorizing --helpSuggests next tokens / flags from curated chains + help cache
A list you can navigate↑/↓ select · Tab accept · Enter runs (or accepts after ↑/↓)
No lag while typingPrefix 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 --help calls during cache build

Installation

Latest release: v1.0.0

Oh My Zsh

  1. 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/ev
    

    Or from a local checkout of this repo:

    ./install.sh
    

    ./install.sh symlinks the plugin, updates plugins=(...), adds late keybinds, and builds the cache once.

  2. 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
    )
    
  3. 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.

  1. ggit
  2. git sstatus
  3. git status-v, --short, …
  4. gh repo llist

Press Tab to accept the highlighted suggestion (e.g. ggit ). 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

KeyWidget / action
↑ / ↓Previous / next suggestion (history when the list is hidden)
TabAccept highlighted suggestion
EnterRun the line; after ↑/↓, accept the selected suggestion instead
Shift-Tab / Ctrl+PPrevious suggestion
Ctrl+NNext suggestion
Alt+SpaceAccept highlighted suggestion
Ctrl+GHide suggestion list

Widgets you can rebind with bindkey after the plugin loads:

  • ev-tab / ev-enter
  • ev-up / ev-down
  • ev-prev / ev-next
  • ev-hide
  • ev-accept-widget

Example:

bindkey '^ ' ev-accept-widget

Configuration

Override these variables in ~/.zshrc before the plugin is loaded (or export them in the environment).

VariableDefaultDescription
EV_ENABLED1Set to 0 to disable the suggestion UI
EV_MAX10Maximum rows shown in the list
EV_TMP${XDG_CACHE_HOME:-~/.cache}/evCache directory (persists across reboots; overrides XDG default)
EV_HELP_TIMEOUT1Seconds per --help / -h call during ev-rebuild-cache
EV_HELP_MAX_DEPTH2Nested help discovery depth (root = 0)
EV_HELP_MAX_CALLS60Max 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.zsh if it exists; does not scan PATH or run --help
  • While typing - prefix map lookups only
  • Rebuild - only when you run ev-rebuild-cache (or when ./install.sh builds 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

FilePurpose
ev.plugin.zshMain plugin entry (Oh My Zsh / Antigen / Zinit load this)
chains.zshCurated next-token catalogs
discover.zsh--help / -h discovery (used only during rebuild)
build-cache.zshBuilds $EV_TMP/index.zsh (invoked by ev-rebuild-cache)
stamp.zshCache fingerprint helpers for build-cache.zsh
install.shOptional 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 - Run ev-rebuild-cache once, then keep using the shell as usual.
  • No list appears - Confirm ev is in plugins=(...) (or sourced), then exec zsh. Check EV_ENABLED is not 0. Confirm $EV_TMP/index.zsh exists.
  • 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 on PATH; add a node in chains.zsh if needed.
  • ↑/↓ don't move the list - Re-run ./install.sh so late keybindings are applied after history-substring-search.
  • Slow ev-rebuild-cache - Lower EV_HELP_MAX_CALLS or EV_HELP_MAX_DEPTH in ~/.zshrc before rebuilding.
ls -la "${EV_TMP:-${XDG_CACHE_HOME:-$HOME/.cache}/ev}/"

Uninstallation

  1. Remove ev from the plugins=(...) list in ~/.zshrc (or remove the source …/ev.plugin.zsh line).

  2. Remove the keybind block between # >>> ev plugin keys >>> and # <<< ev plugin keys <<< if present.

  3. 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
    
  4. Restart the shell: exec zsh.

License

MIT - see LICENSE.