A tiny Neovim plugin that asks the local pi CLI to rewrite the current
visual selection or copy a compact file reference for another agent.
The goal is small, localized edits with little context and easy-to-read code. The plugin sends Pi only:
- your instruction;
- the selected text;
- the buffer file name;
- the filetype;
- the selected line range.
It also runs Pi with no tools, no session, and no context files.
- Neovim 0.9 or newer.
- The Pi coding agent CLI available as
pi.
Install Pi and authenticate it first:
npm install -g @mariozechner/pi-coding-agent
piInside Pi, run:
/login
Choose your provider. OpenAI ChatGPT or an OpenAI API key both work through Pi. If you prefer an API key, set it before starting Neovim:
export OPENAI_API_KEY=sk-...Create a plugin spec such as
~/.config/nvim/lua/plugins/min-pi-agent.lua:
return {
{
"surfdude75/nvim-min-pi-agent",
main = "min_pi_agent",
opts = {
default_model = "openai-codex/gpt-5.5",
default_thinking = "medium",
},
keys = {
{
"<leader>as",
":<C-u>MinPiAgentEditSelection<CR>",
mode = "x",
desc = "Pi edit selection",
},
{
"<leader>ar",
":<C-u>MinPiAgentCopySelectionReference<CR>",
mode = "x",
desc = "Pi copy selection reference",
},
},
},
}- Select text in visual mode.
- Press
<leader>as. - In the popup, describe the edit.
- Press
<C-s>to submit.
In the popup:
- type the requested change in the body;
- press
<C-l>to select a model frompi --list-models gpt; - press
<C-t>to select the thinking level; - press normal mode
<CR>to submit; - press normal mode
qor<Esc>to cancel.
If <C-s> is captured by your terminal, use normal mode <CR> instead.
The success or failure notification includes the elapsed Pi request time.
The plugin remembers the last model and thinking value only in the current Neovim process. Restarting Neovim resets them to the configured defaults.
If the original buffer changes while Pi is working, the replacement is cancelled. This avoids applying stale output over text that you already edited.
To copy a reference for another agent instead of editing:
- Select text in visual mode.
- Press
<leader>ar.
The plugin copies text such as file lua/min_pi_agent/init.lua#125-185.
The file path is relative to the highest parent directory that contains
AGENTS.md.
By default, the plugin copies the reference to the unnamed register and, when
available, the system clipboard. You can also use
:MinPiAgentCopySelectionReference a to target a specific register.
:MinPiAgentEditSelectionedits the current visual selection.:MinPiAgentCopySelectionReference [register]copies afile path#linesreference for the current visual selection.:MinPiAgentCheckchecks that thepicommand is available.:MinPiAgentLoginopens Pi in a terminal split so you can run/login.:MinPiAgentLogCommand onlogs the exact Pi command before each request.:MinPiAgentShowLastCommandprints the last Pi command again.
Default options:
require("min_pi_agent").setup({
default_model = "openai-codex/gpt-5.5",
default_thinking = "medium",
pi_cmd = "pi",
extra_args = {},
keymap = nil,
reference_keymap = "<leader>ar",
model_list_search = "gpt",
strip_trailing_newline = true,
log_cmd = false,
})Set model_list_search = "" if you want <C-l> to list all Pi models.
Optional prompt customization: agent_prompt replaces the default instruction
lines sent before the request and selected text. Do not add it unless you want
to customize the agent behavior.
require("min_pi_agent").setup({
agent_prompt = {
"Rewrite only the selected text.",
"Return replacement text only.",
"Do not include Markdown fences or explanations.",
},
})The user request, file metadata, and selected text are still appended after these lines.
The provider prefix matters. A bare model such as gpt-5.5 can resolve to a
provider you have not authenticated, such as Azure OpenAI. If Pi lists your
desired model with a provider prefix, use that exact value. For example:
require("min_pi_agent").setup({
default_model = "openai-codex/gpt-5.5",
})You can also set the visual keymaps from setup:
require("min_pi_agent").setup({
keymap = "<leader>as",
reference_keymap = "<leader>ar",
})Set reference_keymap = nil to disable the built-in reference mapping.
LazyVim users usually prefer the keys section in the plugin spec.
For every request, the plugin runs a command similar to:
pi \
--print \
--no-session \
--no-tools \
--no-context-files \
--no-extensions \
--no-skills \
--no-prompt-templates \
--model openai-codex/gpt-5.5 \
--thinking mediumThe prompt is passed on standard input. Pi then sends the prompt to the selected model provider.
To compare the command used by the default model and the model picker, run:
:MinPiAgentLogCommand onThen try both flows and inspect :messages. You can also rerun:
:MinPiAgentShowLastCommand- Visual block selections are not supported.
- There is no diff preview yet.
- The plugin expects Pi to return replacement text only.
- Authentication is handled by Pi, not by this plugin.