Describe what you want in plain language; ai prints one shell command.
The core rule: ai never runs the command it generates. It writes it to stdout
and nothing else. A shell wrapper puts that command into your editing buffer, so you
read it, edit it if needed, and press Enter yourself.
$ ai find files larger than 100MB in my home directory
$ find ~ -type f -size +100M 2>/dev/null # <- waiting in your prompt, not executedbashjq- The
claudeCLI in yourPATH zshorbashfor the wrapper
curl -fsSL https://raw.githubusercontent.com/horbo/ai/main/install.sh | bashPrefer to read the script first:
curl -fsSL https://raw.githubusercontent.com/horbo/ai/main/install.sh -o install.sh
less install.sh
bash install.shThe installer clones the repository, symlinks ai into your PATH and adds a
wrapper to your shell config. It is idempotent, so running it again just updates
the checkout.
| variable | default | meaning |
|---|---|---|
AI_INSTALL_DIR |
~/.local/share/ai |
where the repository is cloned |
AI_BIN_DIR |
~/.local/bin |
where the ai symlink is created |
AI_RC_FILE |
detected from $SHELL |
shell config to edit |
Flags: --dir, --bin-dir, --no-rc, --help.
The wrapper is added between markers, so it can be updated or removed cleanly:
# >>> ai >>>
eval "$(ai init zsh)"
# <<< ai <<<git clone https://github.com/horbo/ai.git ~/.local/share/ai
ln -s ~/.local/share/ai/ai ~/.local/bin/ai
echo 'eval "$(ai init zsh)"' >> ~/.zshrcrm -rf ~/.local/share/ai ~/.local/bin/ai
# then delete the marked block from your shell configai --updateFast-forwards the checkout, then verifies the symlink and the shell config entry and restores them if either is missing.
ai list processes using the most memory
ai --no-context find large files
ai -e show disk usage # also print a one-line explanation on stderr
ai -m sonnet rewrite this git history interactively
ai # interactive prompt
echo "show disk usage" | ai # request on stdin
ai -- --version # treat the rest as the request, not as flagsai init zsh and ai init bash print the wrapper if you want to wire it up yourself.
Tab completion comes with the wrapper, so there is nothing extra to install:
$ ai --<TAB>
--explain --link --model --no-context
--no-rc --update --help --version
$ ai -m <TAB>
haiku sonnet opus fable
$ ai init <TAB>
zsh bashFree-text requests are left alone — completion only kicks in for flags and for
init.
In zsh the wrapper must be evaluated after compinit, which is where the
installer puts it. If you wire it up by hand and put the eval earlier, the
wrapper still works but completion is skipped.
Only the generated command ever reaches stdout. Explanations, warnings, questions and errors go to stderr, so nothing but a runnable command can end up in your editing buffer.
| exit code | meaning |
|---|---|
0 |
command on stdout |
1 |
usage error or missing dependency |
2 |
the request was too vague; a clarifying question is on stderr |
3 |
the claude CLI failed |
Because the wrapper uses || return, codes 1-3 leave your prompt untouched — you
just see the message.
Without the wrapper ai behaves like an ordinary filter:
ai delete .tmp files older than 7 days | tee /dev/tty | bash # at your own risk| variable | default | meaning |
|---|---|---|
AI_MODEL |
haiku |
model used for generation |
AI_FALLBACK_MODEL |
sonnet |
model used when the primary one is unavailable |
AI_CONTEXT |
os,shell,tools,cwd |
which environment details to send |
AI_MAX_BUDGET_USD |
unset | spending cap for a single call |
Your request, plus an environment block that helps the model produce a command that actually works on your machine:
os— the distribution name from/etc/os-release, so you do not getapton Fedorashell—zshorbash, since their syntax differstools— which offd,rg,jq,gh,docker, … are installedcwd— the current directory path and the names of the files in it
Drop any part you would rather not send:
export AI_CONTEXT=os,shell,tools # no directory listing
export AI_CONTEXT=none # request only
ai --no-context find large files # one-offThe model runs with all tools disabled, without your Claude Code settings, hooks,
MCP servers or CLAUDE.md, and without persisting a session.
Models get things wrong and shell commands can be irreversible. The whole point of
this tool is that you see the command before it runs — read it, especially when it
contains rm, dd, mkfs or a redirect that overwrites a file. ai flags
commands the model considers destructive, but that flag is a hint, not a guarantee.
tests/run.shRuns syntax checks, shellcheck when available, the output-contract assertions
against a stubbed claude, and an end-to-end installer run in a temporary
directory. It makes no API calls.