acf207e53b
Adds a Claude Code agent and three skills for collaborating with the user's running Neovim instance via mcp-neovim-server and the official coder/claudecode.nvim plugin: - agents/companion.md — the nvim companion identity, prefers runtime introspection over training-data guessing - skills/editor-introspect — read-only queries against the live editor - skills/editor-act — safe driving (open, jump, toggle, run); no buffer edits - skills/claude-code-handoff — delegate buffer edits to the in-editor Claude Code session so users get a diff to accept or reject
111 lines
4.6 KiB
Markdown
111 lines
4.6 KiB
Markdown
---
|
|
name: editor-introspect
|
|
description: |
|
|
Read-only inspection of the user's running Neovim instance via
|
|
`mcp__neovim__*` tools. Use whenever a question depends on the live
|
|
editor state: what is mapped to a key, which buffers are open, what
|
|
the cursor is on, what diagnostics exist, which plugins are loaded,
|
|
what the messages buffer says. Returns concrete facts grounded in
|
|
the running instance — never guesses from training data.
|
|
Trigger on "what's bound to", "what's mapped to", "what buffers",
|
|
"show me the keymaps", "is X loaded", "what plugins are active",
|
|
"current selection", "what's the cursor on", "any diagnostics",
|
|
"lualine theme actually applied".
|
|
disable-model-invocation: false
|
|
allowed-tools: Bash, Read
|
|
---
|
|
|
|
# editor-introspect — read the live nvim instance
|
|
|
|
Owner: `nvim-agentic-companion:companion`. This skill is for *reading*
|
|
the running editor. Never use it to mutate state — use `editor-act`
|
|
for that.
|
|
|
|
## Preconditions
|
|
|
|
The user's nvim must be running with an RPC socket reachable by the
|
|
`mcp-neovim-server` MCP server. If `mcp__neovim__*` tools are not
|
|
present in this session, **stop and tell the user**:
|
|
|
|
> The neovim MCP server isn't connected to this Claude Code session.
|
|
> Start (or restart) nvim so it creates the socket at `{{nvim_socket}}`,
|
|
> then restart Claude Code.
|
|
|
|
Do not try to fake introspection from the config alone.
|
|
|
|
## The introspection vocabulary
|
|
|
|
These are the queries you should reach for first. All are runnable
|
|
via `mcp__neovim__nvim_command` (returns the rendered command output)
|
|
or `mcp__neovim__nvim_eval` (returns a value).
|
|
|
|
### Keymaps
|
|
|
|
- `verbose nmap <leader>ff` — what (and where in lua) is `<leader>ff`?
|
|
- `verbose imap <C-Space>` — same for insert mode.
|
|
- `nmap <leader>` — all normal-mode mappings starting with leader.
|
|
- For machine-readable form prefer:
|
|
`lua print(vim.inspect(vim.api.nvim_get_keymap("n")))`
|
|
…then grep client-side. `nvim_get_keymap` returns the LHS, RHS, mode,
|
|
desc, and the file/line set when known.
|
|
|
|
### Buffers, windows, tabs
|
|
|
|
- `ls!` — list buffers, including hidden.
|
|
- `lua print(vim.inspect(vim.api.nvim_list_bufs()))`
|
|
- `lua print(vim.api.nvim_buf_get_name(0))` — current buffer path.
|
|
- `lua print(vim.inspect(vim.api.nvim_tabpage_list_wins(0)))`
|
|
- For the *visible* layout the user is staring at, prefer windows over buffers.
|
|
|
|
### Cursor, selection, mode
|
|
|
|
- `lua print(vim.inspect(vim.api.nvim_win_get_cursor(0)))` — `[row, col]`.
|
|
- `lua print(vim.fn.mode())` — `n`, `i`, `v`, `V`, `^V`, etc.
|
|
- For the current visual selection text:
|
|
`lua print(vim.fn.getregion(vim.fn.getpos("v"), vim.fn.getpos("."), {type=vim.fn.mode()}))`
|
|
(Neovim ≥ 0.10).
|
|
|
|
### Options
|
|
|
|
- `set option?` — value of a single option (`set number?`).
|
|
- `verbose set option?` — *and* the file that last set it.
|
|
- `lua print(vim.bo.filetype)` / `vim.wo.wrap` / `vim.o.background`.
|
|
|
|
### Diagnostics
|
|
|
|
- `lua print(vim.inspect(vim.diagnostic.get(0)))` — current buffer's diagnostics.
|
|
- `lua print(vim.inspect(vim.diagnostic.count()))` — counts by severity.
|
|
- `lua print(vim.lsp.get_active_clients() | vim.iter ... | ...)` —
|
|
which LSPs are attached.
|
|
|
|
### Plugins / runtime
|
|
|
|
- `lua print(vim.inspect(package.loaded["lualine"]) ~= nil)` — is X loaded?
|
|
- `messages` — startup warnings, last few notifications.
|
|
- `checkhealth <module>` — for a single module; the long-form output
|
|
is huge, so prefer specific modules (e.g. `:checkhealth lualine`) over
|
|
`:checkhealth` whole.
|
|
- For the lualine theme actually in use:
|
|
`lua print(require("lualine").get_config().options.theme)`
|
|
|
|
### "Why is X happening?"
|
|
|
|
When the user reports a symptom, the introspection script is:
|
|
|
|
1. `messages` — did something fail at startup?
|
|
2. `:checkhealth <suspected-module>` — does the module itself complain?
|
|
3. `verbose set <option>?` or `verbose nmap <key>` — is something overriding?
|
|
4. `vim.lsp.get_active_clients()` / `vim.diagnostic.get(0)` — is LSP behaving?
|
|
|
|
Stop as soon as you have the answer. Do not run a sweep when one query is enough.
|
|
|
|
## How to report findings
|
|
|
|
- Quote the **exact** runtime output you got, not a paraphrase.
|
|
- When citing config provenance, give `file_path:line_number` from
|
|
`{{config_path}}` (default `/home/oleks/projects/servers/emmett/nixos/neovim.nix`).
|
|
- If runtime disagrees with config, say so explicitly:
|
|
"Config sets X but the loaded value is Y — likely a stale build / missing reload."
|
|
- For long outputs, summarize and offer to drill in. Don't paste a 200-line
|
|
`:messages` dump verbatim unless the user asks.
|