Aliou Diallo

nvim-pi

Bidirectional communication between Neovim and Pi.

banner

@aliou/nvim-pi

Neovim plugin with a bundled Pi extension.

This package works in two modes:

When Neovim is not running, the extension still loads cleanly and degrades gracefully.

What it provides

Pi extension

Tool / CommandDescription
nvim_contextQuery the connected Neovim instance for focused buffer, splits, diagnostics, or current function
/neovim:settingsConfigure Neovim integration settings for the Pi extension
/neovim:undotree [file]Inspect a Neovim persistent undo tree for a file
@vim: autocompleteType @vim: in Pi’s input to autocomplete file paths from visible Neovim splits

Additional disabled-by-default behavior:

Behavior provided by hooks:

Neovim plugin

Setup

As a Neovim plugin

Install this repo as a Neovim plugin. The lua/ directory is runtimepath-compatible.

Example with vim.pack:

vim.pack.add({ { name = "nvim-pi", src = "https://github.com/aliou/nvim-pi" } })
require("pi-nvim").setup()

Use an existing Pi git install as a Neovim plugin:

pi install git:github.com/aliou/nvim-pi
vim.opt.runtimepath:append(vim.fn.expand("~/.pi/agent/git/github.com/aliou/nvim-pi"))
require("pi-nvim").setup()

If you installed it into project settings with pi install -l, use that project’s .pi/git/github.com/aliou/nvim-pi path instead.

Local checkout setup for development:

vim.opt.runtimepath:append(vim.fn.expand("/absolute/path/to/nvim-pi"))
require("pi-nvim").setup()

Requirements:

When you open Pi through pi-nvim, the plugin launches:

pi --extension /absolute/path/to/nvim-pi

The extension then injects runtime editor state through hooks. By default (load_extension = "auto"), the plugin checks whether nvim-pi is installed globally in Pi and skips --extension if so — this avoids loading the extension twice when you already installed it with pi install.

As a Pi extension

You can also install it directly in Pi:

pi install git:github.com/aliou/nvim-pi

This 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.

Configuration

Pi extension config

/neovim:settings currently exposes:

SettingDefaultDescription
Connection status messagesonShow nvim: connected / no instance found style messages in the Pi session
Editor state injectionoffInject current Neovim editor state (open splits, cursor position) into each prompt automatically
@vim: autocompleteenabledEnable autocomplete for open Neovim splits
Persistent undo toolsdisabledUpdate Neovim persistent undo files after successful Pi edit and write tool calls

Feature toggles are shown as unavailable if Pi did not load that extension entry point.

Neovim plugin config

require("pi-nvim").setup({
  auto_start = true,
  data_dir = nil,

  -- Pi CLI flags
  models = nil,
  provider = nil,
  model = nil,
  thinking = nil,
  load_extension = "auto", -- "auto": skip --extension if installed globally; true: always pass; false: never pass
  extra_args = nil,

  -- Window configuration
  win = {
    layout = "auto",
    width_threshold = 150,
    width = 80,
    height = 20,
    focus_source_on_stopinsert = true, -- switch to source window on exiting terminal mode
    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" },
    },
  },
})

Keymaps

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 = ... } }).

Usage

From Pi

The nvim_context tool supports these actions:

If multiple matching Neovim instances are found, Pi prompts you to choose one when UI is available.

From Neovim

Commands and API:

Pi extension commands:

Troubleshooting

Pi cannot find Neovim

Check:

Discovery prefers:

  1. exact cwd matches
  2. Neovim instances whose cwd is a child of Pi’s cwd

Multiple Neovim instances found

Pi will prompt for selection in interactive mode. In non-interactive mode, the tool returns an error instead of guessing.

RPC server errors

Check:

Healthcheck

:checkhealth pi-nvim

Architecture

Neovim plugin (Lua)                            Pi extension (TypeScript)
-------------------                            ------------------------
require("pi-nvim").setup()                    pi --extension /path/to/nvim-pi
          |                                                   |
          v                                                   v
   rpc.start()                                     extensions/nvim/index.ts registers:
   lockfile.create()                               - hooks (editor state, lifecycle)
          |                                      - tool (nvim_context)
          v                                      - command (/neovim:settings)
~/.local/share/nvim/pi-nvim/                       - renderers (connection, diagnostics)
<cwd-hash>-<pid>.json                                           |
          |                                          session_start discovers lockfile
          |                                          before_agent_start queries splits
          |                                          tool_result reloads files
          |                                          turn_end requests diagnostics
          v                                                   |
   nvim --server <socket> --remote-expr <luaeval(...)> <------+

Core (src/) has zero Pi dependencies:
  nvim.ts          lockfile discovery + RPC
  types.ts         domain types + type guards
  format.ts        shared formatting helpers

Additional extensions:
  splits-autocomplete/       @vim: autocomplete for open splits
  undo/                       /neovim:undotree plus disabled-by-default persistent undo update hooks

Additional Lua features:
  cli/terminal     open/close/toggle Pi in a split or float
  cli/picker       <C-Space> context picker to send info to Pi
  cli/watch        periodic checktime timer while Pi is open

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.