3c5851e95e
mcp-neovim-server no longer runs as a per-session npx stdio child.
It is now a MetaMCP namespace upstream on emmett (one persistent
process), reached over Streamable-HTTP via the mcp-session-pool:
Claude Code -> pool.localhost:12010/p/neovim/mcp
-> MetaMCP neovim namespace -> mcp-neovim-server -> nvim socket
- .mcp.json: stdio npx server -> streamable-http pool endpoint
- agents/companion.md + skills: tool names are now 3-segment
(mcp__neovim__neovim__vim_*) — the MetaMCP aggregation shape; the
surface description and unavailability runbook updated for the
three-link path (nvim socket / MetaMCP / session)
- README: connection-path diagram
Host side (servers/emmett, deployed separately): neovim added to
services.mcp-session-pool.upstreams; metamcp.nix seeds the neovim
mcp_servers row + mapping and adds nodejs to the unit PATH.
130 lines
4.8 KiB
Markdown
130 lines
4.8 KiB
Markdown
---
|
|
name: editor-act
|
|
description: |
|
|
Drive the user's running Neovim instance — open files, run user
|
|
commands, trigger keymaps, jump to LSP locations, toggle UI,
|
|
evaluate small lua snippets. Uses the `mcp__neovim__neovim__*` tools
|
|
(`vim_command`, `vim_file_open`, `vim_window`, …) against the live
|
|
instance. Prefers the user's own commands and keymaps over teaching
|
|
new vim syntax. Will *not* edit buffer contents — that work is
|
|
handed off via the `claude-code-handoff` skill. Trigger on
|
|
"open <file> in nvim",
|
|
"jump to definition of", "show file finder", "split this", "toggle
|
|
neo-tree", "run this command in my nvim", "go to next diagnostic",
|
|
"save my buffer".
|
|
disable-model-invocation: false
|
|
allowed-tools: Bash, Read, Skill, AskUserQuestion, mcp__neovim__neovim__*
|
|
---
|
|
|
|
# editor-act — do things in the user's nvim
|
|
|
|
Owner: `nvim-agentic-companion:companion`. This skill is for *acting*
|
|
on the running editor in ways that **do not modify buffer contents**.
|
|
For buffer edits, invoke `claude-code-handoff` instead.
|
|
|
|
## Preconditions
|
|
|
|
`mcp__neovim__neovim__*` tools must be present. If they aren't, stop and tell
|
|
the user to restart nvim + Claude Code (see `editor-introspect` for
|
|
the recovery message).
|
|
|
|
## The action hierarchy
|
|
|
|
When you need to do X, pick the lowest-impact form that works:
|
|
|
|
1. **An existing user command** the user already has — `:Telescope find_files`,
|
|
`:Neotree`, `:Trouble`, `:GitSigns ...`. These reflect how the user
|
|
already navigates and produce no surprises.
|
|
2. **A user keymap** — when the user asks "open the file finder," running
|
|
their `<leader>ff` is preferable to running `:Telescope find_files`
|
|
directly: same result, but if they later remap it you also get the
|
|
new behavior. Feed the keys via `nvim_feedkeys` after running them
|
|
through `nvim_replace_termcodes` — see the "Common patterns" block
|
|
at the bottom of this file for the canonical snippet.
|
|
3. **A built-in vim command** — `:edit`, `:vsplit`, `:tabnew`, `:write`,
|
|
`:bnext` — fine for navigation when no plugin command applies.
|
|
4. **Lua eval** — last resort, for things with no command surface:
|
|
`lua vim.diagnostic.goto_next()` or `lua vim.lsp.buf.definition()`.
|
|
Keep snippets short and obvious. Never paste multi-line scripts.
|
|
|
|
## Safe actions you can do without asking
|
|
|
|
- Open a file (`:edit`, `:vsplit`, `:tabnew <path>`).
|
|
- Jump to a location, definition, or reference (`vim.lsp.buf.*`,
|
|
`vim.diagnostic.goto_*`).
|
|
- Trigger a user command/keymap they already have.
|
|
- Toggle a UI element (file tree, trouble, bufferline state).
|
|
- Run `:write` *if* the buffer's only change is one you just made via a
|
|
user-blessed command (e.g. they asked you to format and you ran
|
|
`:lua vim.lsp.buf.format()`).
|
|
|
|
## Actions that require a confirmation first
|
|
|
|
`AskUserQuestion` before:
|
|
|
|
- Closing windows or buffers (`:q`, `:bd`, `:tabclose`, `:close`).
|
|
- Writing files the user did *not* just ask you to write.
|
|
- Touching files outside the current project root.
|
|
- Changing global state: colorscheme, leader, options that affect every
|
|
buffer.
|
|
- Running anything destructive against the filesystem from inside lua
|
|
(`os.remove`, `vim.fn.delete`, etc.).
|
|
|
|
## Actions you do not do
|
|
|
|
- **Editing buffer contents.** If the user wants code changed, that's
|
|
`claude-code-handoff`'s job. Do not type characters into a buffer
|
|
via `feedkeys`, do not `nvim_buf_set_text`, do not paste into a buffer.
|
|
The reason: changes should land as a *diff* the user can review via
|
|
claudecode.nvim's accept/reject UI, not as silent mutations.
|
|
- **Quitting nvim** (`:qa`, `:wqa`).
|
|
- **Source new lua / vimscript files** the user didn't approve. The
|
|
declarative config is the source of truth.
|
|
|
|
## After each action
|
|
|
|
Leave one short trail sentence in your response: what you did, and what
|
|
the user should see. Examples:
|
|
|
|
- "Ran `<leader>ff` — telescope file picker is open in your nvim window."
|
|
- "Jumped to `lualine/init.lua:312` via `vim.lsp.buf.definition()`."
|
|
- "Opened `neovim.nix` in a vsplit on your right pane."
|
|
|
|
If the action didn't produce visible feedback (e.g. you only saved a
|
|
buffer), say so — the user can't tell from the screen alone.
|
|
|
|
## Common patterns
|
|
|
|
**Open a file from a path you just produced:**
|
|
|
|
```vim
|
|
:e /home/oleks/projects/servers/emmett/nixos/neovim.nix
|
|
```
|
|
|
|
**Open at a specific line:**
|
|
|
|
```vim
|
|
:e +199 /home/oleks/projects/servers/emmett/nixos/neovim.nix
|
|
```
|
|
|
|
**Find what the user has mapped, then run their mapping:**
|
|
|
|
```vim
|
|
:verbose nmap <leader>ff " confirm what's there
|
|
" then feed the keys so their setup runs end-to-end
|
|
:lua local k = vim.api.nvim_replace_termcodes("<leader>ff", true, false, true)
|
|
:lua vim.api.nvim_feedkeys(k, "n", false)
|
|
```
|
|
|
|
**Move to next LSP diagnostic in current buffer:**
|
|
|
|
```vim
|
|
:lua vim.diagnostic.goto_next()
|
|
```
|
|
|
|
**List loaded LSP clients for the current buffer:**
|
|
|
|
```vim
|
|
:lua print(vim.inspect(vim.lsp.get_clients({ bufnr = 0 })))
|
|
```
|