Neovim plugin with a bundled Pi extension.
This package works in two modes:
- install it as a Neovim plugin and let it launch Pi with the bundled extension
- install it with
pi install pi:github.com/aliou/nvim-piand use the extension directly in terminal Pi sessions
When Neovim is not running, the extension still loads cleanly and degrades gracefully.
| Tool / Command | Description |
|---|---|
nvim_context |
Query the connected Neovim instance for editor context, splits, diagnostics, or current function |
/neovim:settings |
Configure Neovim integration settings for the Pi extension |
Behavior provided by hooks:
- automatically discovers and connects to a matching Neovim instance on session start
- injects visible split context into the system prompt on each turn
- reloads files in Neovim after successful
writeandedittool calls - sends LSP diagnostics for modified files after the turn ends
- starts a Neovim RPC server and writes lockfiles Pi can discover
- opens Pi in a terminal split or float
- passes through selected Pi CLI flags
- exposes
:PiNvimStatus
Install this repo as a Neovim plugin. The lua/ directory is runtimepath-compatible.
Example with lazy.nvim:
{
dir = "/absolute/path/to/nvim-pi",
config = function()
require("pi-nvim").setup()
end,
}Manual setup:
vim.opt.runtimepath:append(vim.fn.expand("/absolute/path/to/nvim-pi"))
require("pi-nvim").setup()Requirements:
pimust be onPATHnvimmust supportserverstart()and--remote-expr
When you open Pi through pi-nvim, the plugin launches:
pi --extension /absolute/path/to/nvim-piThe extension then injects its Neovim guidance and runtime editor context through hooks.
You can also install it directly in Pi:
pi install pi:github.com/aliou/nvim-piThis is useful if you want the extension available in terminal Pi sessions too. If no Neovim instance is running, the extension still loads and simply reports that no instance was found when needed.
/neovim:settings currently exposes:
| Setting | Default | Description |
|---|---|---|
Connection status messages |
on |
Show nvim: connected / no instance found style messages in the Pi session |
require("pi-nvim").setup({
auto_start = true,
data_dir = nil,
-- Pi CLI flags
models = nil,
provider = nil,
model = nil,
thinking = nil,
extra_args = nil,
-- Window configuration
win = {
layout = "auto",
width_threshold = 150,
width = 80,
height = 20,
focus_source_on_stopinsert = true,
keys = {
close = { "<C-q>", mode = "n", desc = "Close Pi" },
stopinsert = { "<C-q>", mode = "t", desc = "Exit terminal mode" },
suspend = { "<C-z>", mode = "t", desc = "Suspend Neovim" },
picker = { "<C-Space>", mode = "t", desc = "Open context picker" },
},
},
})The plugin does not create global leader mappings by default.
Example mappings:
vim.keymap.set("n", "<leader>po", require("pi-nvim").open, { desc = "Open Pi" })
vim.keymap.set("n", "<leader>pc", require("pi-nvim").close, { desc = "Close Pi" })
vim.keymap.set("n", "<leader>pp", require("pi-nvim").toggle, { desc = "Toggle Pi" })Terminal/window-local keys are configured under setup({ win = { keys = ... } }).
The nvim_context tool supports these actions:
context- focused file, cursor position, selection, filetypesplits- all visible splits with metadatadiagnostics- diagnostics for the current buffercurrent_function- treesitter info for the symbol at the cursor
If multiple matching Neovim instances are found, Pi prompts you to choose one when UI is available.
Commands and API:
:PiNvimStatus- show RPC and terminal staterequire("pi-nvim").open()- open the Pi terminalrequire("pi-nvim").close()- close the Pi terminalrequire("pi-nvim").toggle()- toggle the Pi terminalrequire("pi-nvim").start()- start the RPC server manuallyrequire("pi-nvim").stop()- stop the RPC server manuallyrequire("pi-nvim").status()- get the current RPC state
Check:
:PiNvimStatusshows the RPC server as runningpiandnvimare both onPATH- lockfiles exist under Neovim's data dir, usually
~/.local/share/nvim/pi-nvim/
Discovery prefers:
- exact cwd matches
- Neovim instances whose cwd is a child of Pi's cwd
Pi will prompt for selection in interactive mode. In non-interactive mode, the tool returns an error instead of guessing.
Check:
~/.local/state/nvim/pi-nvim/rpc.log:PiNvimStatus
:checkhealth pi-nvimNeovim plugin (Lua) Pi extension (TypeScript)
------------------- ------------------------
require("pi-nvim").setup() pi --extension /path/to/nvim-pi
| |
v v
rpc.start() src/index.ts registers:
lockfile.create() - hooks
| - tool
v - command
~/.local/share/nvim/pi-nvim/ |
<cwd-hash>-<pid>.json v
| session_start discovers lockfile
| before_agent_start queries splits
| tool_result reloads files
| turn_end requests diagnostics
v |
nvim --server <socket> --remote-expr <luaeval(...)> <------+
The TypeScript extension discovers Neovim instances through lockfiles, then queries the running editor through nvim --remote-expr, which evaluates require("pi-nvim").query(...) inside Neovim.