A vi plugin that lets you query an LLM inline, directly from inside vi.
- Python 3.13 or later
- uv
- An OpenAI compatible endpoint
git clone https://github.com/liupeirong/vimai.git /path/to/vimai
cd /path/to/vimaiuv syncAdd this line to your ~/.vimrc. Use the exact absolute path where you installed vimai:
set runtimepath+=/path/to/vimaivimai needs to know which OpenAI compatible endpoint to call. Set these in your shell before launching Vim:
export OPENAI_BASE_URL="https://<your-resource>.openai.azure.com/openai/v1"
export OPENAI_MODEL="<your-deployment-name>"
export OPENAI_API_KEY="" # optional; omit for Entra ID Auth
export LANGSMITH_API_KEY="" # optional; set if you want to enable tracing
export LANGSMITH_PROJECT="" # optional; default = "vimai"The plugin calls main.py under the hood. After uv sync, vimai automatically
uses the Python executable from the plugin checkout's .venv.
If you need to use a different Python, set one of these before the plugin loads:
" In vimrc
let g:vimai_python="/absolute/path/to/python"az loginOnce Vim is open, run:
:AI What does the % register hold in Vim?The response opens in a vertical split on the right side of your screen as a read-only buffer.
Your cursor returns to your original window automatically. Close the response pane with :q when done.
You can also type :ai in lowercase — it is aliased to :AI:
:ai Explain the difference between :s and :S in a substitution commandFor longer prompts, press <leader>ai to open a scratch prompt buffer, type as many
lines as you need, leave Insert mode with Esc, then press <leader>s from that buffer
to submit. The prompt buffer is wiped after submission, and the response appears in the
same read-only response split.
Agent definitions are plain Markdown system prompts. vimai looks for user-defined
agents in ~/.vimai/agents/<name>.md; a user file overrides a bundled agent with
the same name. The plugin includes a built-in vi.md Vim expert prompt.
mkdir -p ~/.vimai/agents
cat > ~/.vimai/agents/git.md <<'EOF'
You are a Git expert. Give concise, safe commands and explain risky operations.
EOFRoute a prompt to an agent by starting :AI with @<name>:
:AI @vi Explain :global with an example
:AI @git How do I undo the last commit but keep the changes?Agent calls are stateless single-turn requests. They use the selected agent's system prompt and do not read from or write to your current conversation history.
If no prompt file exists for @<name>, vimai can run an external non-interactive
agent wrapper instead. Set VIMAI_EXTERNAL_AGENTS_DIR to a directory containing
one subdirectory per external agent:
VIMAI_EXTERNAL_AGENTS_DIR=/path/to/external-agentsEach external agent must provide a run-agent wrapper. On Windows,
run-agent.bat and run-agent.cmd are also supported:
/path/to/external-agents/
git/
run-agent
run-agent.bat # Windows alternative
vimai invokes the wrapper as:
/path/to/external-agents/git/run-agent --prompt-file <tempfile>The prompt is written to a UTF-8 temporary file, so multiline prompts are safe.
The wrapper should write its final answer to stdout; stdout and stderr are shown
in the existing [AI Response] scratch buffer. Non-zero exits and wrappers that
run longer than 120 seconds are displayed as clear vimai errors. Prompt-only
agents still take priority, so
~/.vimai/agents/git.md or a bundled git.md would be used before the external
git/run-agent wrapper.
vimai automatically maintains conversation history for the current Vim session. Every prompt you send and every response you receive are saved to a temporary JSON file in your system temp directory:
| Environment | Session file location |
|---|---|
| Windows (any shell) | %TEMP%\vimai-session-YYYY-MM-DD-HH-MM-<pid>.tmp |
| Linux / macOS | /tmp/vimai-session-YYYY-MM-DD-HH-MM-<pid>.tmp |
Run :AISession inside Vim to confirm the exact path:
:AISessionHistory is sent to the LLM on every subsequent turn, so you can ask follow-up questions naturally:
:AI What is a Vim macro?
:AI How do I record one?
:AI Can I run it 10 times at once?The session file is written after every turn, so your history is preserved even if Vim exits unexpectedly. A new session file is created each time you open Vim.
Use slash commands to manage your session without making an LLM call:
| Command | What it does |
|---|---|
:AI /clear |
Close the current session and wipe the scratch buffer; session file is kept on disk |
:AI /purge |
Delete all vimai-session-*.tmp files from your temp directory |
:AI /help |
List all available commands |
:AI /clear
" → Session cleared.
:AI /purge
" → Purged 3 session files.
:AI /help
" → vimai commands:
" /clear Close the current session and clear the scratch buffer
" /purge Delete all vimai session files from the system temp directory
" /help Show this help message
" <prompt> Send a prompt to the LLMvimai automatically loads a .env file from your current working directory or
from the plugin checkout root.
- Python 3.13, uv, LangChain, Azure OpenAI
- Tests:
pytest+pytest-mock(no real Azure calls needed for unit tests) - Linting:
ruff
git clone https://github.com/liupeirong/vimai.git
cd vimai
uv sync
# on Windows
uv pip install -e . --no-build-isolation
# on Linux
uv pip install -e .uv run pytestNo Azure credentials are needed — all Azure and LangChain calls are mocked.
The VimScript buffer/window management is tested with vader.vim.
Install vader.vim (once):
git clone https://github.com/junegunn/vader.vim ~/.vim/pack/plugins/start/vader.vimRun the tests (replace ~/vimai with your clone path):
vim -u NONE -N \
+"set runtimepath+=~/.vim/pack/plugins/start/vader.vim,~/vimai" \
+"runtime plugin/vader.vim" \
+"runtime plugin/vimai.vim" \
+"Vader tests/vimai.vader"Or from inside Vim with vader.vim installed:
:Vader tests/vimai.vaderRUN_E2E=1 uv run pytest -m e2euv run ruff format .
uv run ruff check .