v1.20Grok Build CLI support →

Shell

agents-cli dispatches every claude, codex, gemini, agy,grok, copilot, opencode, and cursor-agent call through a small shimon your PATH. The shim resolves the right version for the current project and execs the real binary. For this to work, the shim directory has to win the PATH race against every other dir.

How shimming works

Shims live at ~/.agents/.cache/shims/. Each one is a 200-line bash script that reads the per-project agents.yaml (see Pin versions), figures out which version of the agent to run, and execs the matching binary from ~/.agents/.history/versions/<agent>/<version>/. If a project hasn't pinned anything, the shim falls back to your global default (set with agents use <agent> <version>).

That means whoever wins type -p claude decides which Claude you get. If a system binary at /usr/local/bin/claude sits ahead of the shim dir, the shim never runs and per-project pinning silently does nothing. Shims must come first.

What the installer does

On first run, agents-cli detects your shell from $SHELL and appends a marked block to the right rc file:

# agents-cli: version-managed agent CLIs
export PATH="$HOME/.agents/.cache/shims:$PATH"

The block is inserted after any nvm/fnm/pyenv setup the CLI can detect, so node resolves before the shim path is prepended. The marker comment is how the CLI finds and updates the block on later runs — don't change it.

zsh

One canonical block in ~/.zshrc, placed after every version manager and after every other PATH prepend:

# ~/.zshrc
# ... nvm / pyenv / conda / homebrew init goes here ...

# agents-cli: version-managed agent CLIs
export PATH="$HOME/.agents/.cache/shims:$PATH"

typeset -U path at the top of the file is also a good idea — it dedupes PATH entries so repeated rc sources don't balloon it.

bash

Same block, but in ~/.bashrc (Linux) or ~/.bash_profile (macOS login shells):

# ~/.bashrc
# ... nvm / pyenv / homebrew init goes here ...

# agents-cli: version-managed agent CLIs
export PATH="$HOME/.agents/.cache/shims:$PATH"

fish

fish prepends paths with fish_add_path, which writes to $fish_user_paths and persists across sessions automatically:

# ~/.config/fish/config.fish
# ... nvm / pyenv init goes here ...

# agents-cli: version-managed agent CLIs
fish_add_path $HOME/.agents/.cache/shims

Fast-path shells

Some users wrap an early-return block at the top of ~/.zshrc that skips oh-my-zsh, compinit, and plugins when an env var like AGENT_TERMINAL_ID is set. This is great for sub-100ms shell boot in agent terminals, but it bypasses everything below the return — including the PATH block the installer wrote. If you use this pattern, the shim dir has to be inside the fast-path block too:

# ~/.zshrc
if [[ -n "$AGENT_TERMINAL_ID" ]]; then
  # nvm bin (if you need node in agent shells)
  if [[ -s "$HOME/.nvm/alias/default" ]]; then
    _nvm_v=$(<"$HOME/.nvm/alias/default")
    export PATH="$HOME/.nvm/versions/node/v${_nvm_v#v}/bin:$PATH"
    unset _nvm_v
  fi

  # Shims FIRST, then everything else.
  export PATH="$HOME/.agents/.cache/shims:$HOME/.local/bin:$HOME/go/bin:/opt/homebrew/bin:/opt/homebrew/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:$PATH"

  PS1='%1~ %# '
  return
fi

# ... normal interactive setup below ...

When the repair prompt keeps firing

On every agents run <agent> in a TTY, the CLI checks whether its shim is the first match for each agent's command name. If something earlier in PATH shadows it, you get the Repair shim integration now?prompt. Saying yes only rewrites the rc file — it doesn't fix three common shapes:

1. A real binary at ~/.local/bin/<agent>

If you previously installed an agent CLI as a standalone binary (e.g. ~/.local/bin/agy from a downloaded installer), and your rc file puts ~/.local/bin ahead of the shim dir, the standalone wins and the shim is dead weight.

# broken — .local/bin wins, shim ignored
export PATH="$HOME/.local/bin:$HOME/.agents/.cache/shims:$PATH"

# fixed — shim first
export PATH="$HOME/.agents/.cache/shims:$HOME/.local/bin:$PATH"

Either reorder, or delete the standalone binary now that the shim manages it. Verify with which -a claude — the first hit should be under ~/.agents/.cache/shims/.

2. Multiple PATH prepends scattered across the rc file

rc files are sequential: the last export PATH="...:$PATH" wins. If the installer dropped the shim block at line 50 and you have another export PATH="$HOME/.local/bin:$PATH" at line 200, your local bin re-shadows the shims every time you open a shell.

# broken — last prepend wins, shim loses
export PATH="$HOME/.agents/.cache/shims:$PATH"   # line 50
# ... 150 lines ...
export PATH="$HOME/.local/bin:$PATH"              # line 200, overrides above

# fixed — one canonical block, at the bottom, after everything else
# ... all other PATH writes ...
export PATH="$HOME/.agents/.cache/shims:$PATH"   # last write, wins

3. A shell alias that customizes an agent command

An alias like alias codex="codex --sandbox workspace-write" shows up in the repair prompt as codex (alias). This is usually intentional customization, not a shadow — the alias resolves codex via the shim, then adds flags. The CLI short-circuits and skips the prompt as long as no binary is shadowing, so this warning is informational. If you want it gone entirely, move the alias into a file that isn't scanned (~/.zsh_aliases sourced from ~/.zshrc) or rename the alias (cdx instead of codex).

Verifying the setup

# every default agent's command should resolve into ~/.agents/.cache/shims/
for cmd in claude codex gemini agy grok copilot opencode cursor-agent; do
  printf "%-15s -> %s\n" "$cmd" "$(command -v $cmd 2>/dev/null || echo 'not installed')"
done

# or, more direct
agents doctor

Related