# pi-ide-context > `/ide` for pi — like Claude Code's IDE integration, but for Neovim, VS Code and Obsidian. [![npm version](https://img.shields.io/npm/v/pi-ide-context)](https://www.npmjs.com/package/pi-ide-context) [![GitHub](https://img.shields.io/badge/github-Andy8647/pi--ide--context-blue)](https://github.com/Andy8647/pi-ide-context) Select text in Neovim (or VS Code / Obsidian), switch to pi — pi already knows which file you're in, where your cursor is, and what you selected. No copy-paste. No `:PiAsk`. It just works. ![The /ide picker listing a Neovim and a VS Code instance, and the IDE Context block pi injected for the connected one](https://raw.githubusercontent.com/Andy8647/pi-ide-context/main/assets/demo.png) ## Install ### Pi extension ```bash pi install npm:pi-ide-context ``` Then `/reload` in pi. ### Neovim plugin (lazy.nvim) ```lua { "Andy8647/pi-ide-context", lazy = false, } ``` ### VS Code extension Not published to the marketplace yet — build and install locally: ```bash cd editors/vscode npm install && npm run build code --extensionDevelopmentPath="$PWD" # dev instance, or package + install a vsix ``` ### Obsidian plugin In the community plugin directory — search **pi-ide-context** under Settings → Community plugins → Browse, or install from [community.obsidian.md/plugins/pi-ide-context](https://community.obsidian.md/plugins/pi-ide-context). To build from source instead: ```bash cd editors/obsidian npm install && npm run build mkdir -p "/.obsidian/plugins/pi-ide-context" cp main.js manifest.json "/.obsidian/plugins/pi-ide-context/" ``` Then enable **pi-ide-context** under Settings → Community plugins. ## Usage Nothing connects on its own — you decide per session: ``` pi starts (no IDE attached, ever) ↓ /ide → lists every live editor (nvim / VS Code / Obsidian), wherever it was started from — no project/cwd filtering; you pick the relevant one ↓ status shows `in main.ts`; select lines → `5 lines selected in main.ts` ↓ ask pi → context injected automatically (selection fresh for 60s) ↓ /ide off (or pick "Disconnect" in the /ide list) → disconnect ``` When connected, every message you send to pi automatically includes: ``` ### IDE Context - File: /Users/andy/my-project/src/main.ts - Language: typescript - Cursor: line 42, column 10 - Buffer: 200 lines (modified) - Selection: lines 40–45 ```typescript const foo = bar(); // ... ``` ``` Selection text is injected only while fresh (within 60s of making it); after that the file/cursor context is still sent but the selection text is not — same as Claude Code's chip disappearing. When you send a message while a selection is fresh, the sent message also shows the selection as a gray quote line (`│ ↳ main.ts:40-45 · …`) inside its own box, so you can see exactly what was attached. Status text is pure ASCII (no Nerd Font needed). The `/ide` list shows each editor's directory and launch args (`nvim pi/` vs `nvim pi-ide-context/`) so several instances are easy to tell apart; a bare `nvim .` shows the directory name. If the connected editor exits, the session disconnects with a notice — run `/ide` again to reconnect. ## How it works ``` ┌──────────┐ writes JSON ┌──────────────┐ reads JSON ┌────────┐ │ Neovim │ ─────────────► │ /tmp/pi-ide/ │ ◄──────────── │ pi │ │ autocmd │ debounced │ .json │ before_ │ auto │ │ hooks │ every 200ms │ │ agent_start │ inject │ └──────────┘ └──────────────┘ └────────┘ ``` **Neovim side**: autocmd on CursorMoved / TextChanged / BufEnter / ModeChanged / DirChanged writes editor state to a JSON file. Zero dependencies — a single Lua file. Sends its launch args (`argv`) so same-cwd instances can be told apart. **Pi side**: `before_agent_start` reads the JSON for the connected editor and injects formatted editor context (lightweight file/cursor/buffer every time; selection text only while fresh). Connecting is fully manual: `/ide` lists every live editor without project filtering, publishes `in main.ts` / `N lines selected in main.ts` through `ctx.ui.setStatus("pi-ide", …)`, and `/ide off` disconnects. With [pi-starline](https://github.com/Andy8647/pi-starline) installed, set `"extensionStatuses": { "placements": { "pi-ide": "editor" } }` to move that text to the editor's bottom-right metadata row instead of the footer. Full protocol in [`docs/protocol.md`](docs/protocol.md). ## Protocol Editor state is written to `/tmp/pi-ide/.json`: ```json { "pid": 12345, "cwd": "/Users/andy/my-project", "timestamp": 1700000000, "app": "nvim", "argv": ["pi-ide-context/"], "active_buffer": { "file": "/Users/andy/my-project/src/main.ts", "name": "main.ts", "language": "typescript", "cursor": { "line": 42, "column": 10 }, "selection": { "start": { "line": 40, "column": 1 }, "end": { "line": 45, "column": 20 }, "text": "selected code here...", "selected_at": 1700000000 }, "modified": false, "lines_total": 200 } } ``` Columns are 1-based. `selected_at` drives the freshness window (60s on the pi side). The same protocol works for VS Code / Obsidian — just write this JSON. The pi extension is editor-agnostic; all three clients (Neovim, VS Code, Obsidian) write it. See `editors/` for the VS Code and Obsidian clients. ## License MIT