Skip to content

About

Neovim plugin for AI-assisted coding: Claude CLI & Codex CLI backends with MCP-powered editor control

Topics

Resources

Contributing

Security policy

Stars

13 stars

Watchers

0 watching

Forks

Latest commit

Β 

History

760 Commits

Folders and files

NameName
Last commit message
Last commit date
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

vibing.nvim logo

vibing.nvim

Claude, Codex, Copilot, Grok and Pi as a Neovim buffer β€” with the editor handed back to them

CI License: MIT Release Neovim

English | ζ—₯本θͺž

Demo β€’ Features β€’ Requirements β€’ Installation β€’ Configuration β€’ Usage

01-parallel-chats.mp4

Three chats, opened in seconds, working on three different questions at once β€” in one Neovim.

✨ Features

Unlike chat plugins that send static context to an LLM, vibing.nvim gives the AI direct access to your running Neovim through CLI backends and MCP.

  • πŸ€– Neovim as an agent tool β€” the AI reads and writes buffers, runs Ex commands and queries your live LSP (diagnostics, definitions, references, symbols)
  • πŸ’¬ The chat is a Markdown buffer β€” your keymaps, your motions, your search; saved under .vibing/chat/, resumable, greppable, version-controllable
  • πŸ”€ Multi-backend β€” Claude, Codex, GitHub Copilot, Grok or Pi, switched globally or per chat
  • 🧡 Concurrent chats β€” open as many as you like; start one while another is still streaming
  • πŸͺŸ Multi-agent orchestration β€” one chat creates and drives worker chats, then aggregates what they report back
  • 🌱 Git worktree workflow β€” isolate a task in .vibing/worktrees/<branch>/ by asking for it
  • πŸ“Š Per-turn diffs β€” every turn ends in ### Modified Files; gd opens a patch viewer. The baseline is a git tree snapshot, so a sed -i through Bash is tracked like an Edit
  • πŸ›‘οΈ Granular permissions β€” allow/deny/ask per tool, path and command patterns, answered in the buffer without killing the turn
  • ⏳ Usage-limit scheduling β€” <CR> parks your message instead of burning a doomed request, and sends it verbatim once the limit resets
  • 🌍 Per-chat response language

Consider alternatives if you

  • Need local/offline models (Ollama, etc.)
  • Prefer minimal dependencies β€” vibing.nvim needs Node.js for the MCP server
  • Want a battle-tested plugin with a large community (we're still growing!)

vibing.nvim doesn't conflict with completion plugins (Copilot, Codeium) or other chat plugins β€” they compose well.

πŸŽ₯ Demo

Real, unedited sessions against the CLI β€” same plugin, same defaults, no mock-ups.

Every turn ends in a diff you can read

A turn closes with ### Modified Files; press gd on a filename and a three-pane patch viewer opens β€” the tree as it was when the turn started, next to what it is now.

02-per-request-diff.mp4

Approvals are answered in the buffer, not in a popup

When a tool needs your say-so, the options are written into the chat. Delete the lines you don't want and press <CR>. The hook blocks while you decide, so the turn resumes instead of being killed and retried β€” the model keeps everything it had worked out so far.

03-approval-prompt.mp4

The model can ask you a question, and wait for your answer

A choice list is rendered into your unsent section. Write your answer under it, press <CR>, and it goes straight back as the tool's return value; the same turn carries on.

04-ask-user-question.mp4

One chat can create and drive others

Ask for parallel work and the chat becomes an orchestrator: a worker chat per task, each with its own transcript you can open mid-task. ## Request and ## Report record who said what to whom.

05-orchestration.mp4

Played at 3Γ— speed.

Risky work goes into its own git worktree

"Start this in its own worktree" is all it takes: a branch under .vibing/worktrees/<branch>/, and every edit, test run and commit happens in there. The checkout you are looking at never moves β€” note that the file in the left window stays untouched throughout.

06-worktree.mp4

It drives your editor, instead of describing it

Ask to be walked through a code path and you get a real tour: the quickfix list holds the whole route (walk it again with :cnext), each stop opens the actual file at the actual line, and the explanation stays inline as a virtual-text annotation.

07-code-tour.mp4

Played at 3Γ— speed.

πŸ“‹ Requirements

  • Neovim 0.10+ (uses vim.system())
  • Node.js 18+ β€” for the bundled MCP server
  • A C compiler β€” optional; without one the chat Tree-sitter parser is skipped and the previous whole-buffer Markdown parser is used
  • At least one AI CLI backend:
Backend Install
Claude CLI npm install -g @anthropic-ai/claude-code
Codex CLI npm install -g @openai/codex (0.140+)
GitHub Copilot CLI npm install -g @github/copilot (needs Node.js 22+)
Grok Build CLI xAI's install docs
Pi coding agent Pi installer (Node.js 22.19+)
Codex version note

vibing.nvim runs the Codex backend's lightweight calls (chat title generation, /summarize, daily summary) with --ignore-user-config --strict-config, which keeps those calls out of your MCP servers and makes them fail loudly rather than silently unfenced if Codex renames a config key. Both flags were verified present in 0.140.0 and 0.147.0, on codex exec and codex exec resume alike. Older releases were not tested; if they lack the flags, ordinary chat is unaffected but lightweight calls fail with an unknown-argument error. Upgrade Codex if you see that.

--ignore-user-config also drops model_provider, so if your config.toml points Codex at a custom or local provider, those lightweight calls go to the default OpenAI endpoint instead. Ordinary chat still uses your provider. vibing.nvim warns once per Neovim session when this applies to you, asking Codex itself (codex doctor --json) which provider is configured; it says nothing if Codex cannot answer. Set ai.agents.codex.extensions.provider_notice = false to turn the warning and its probe off.

πŸ“¦ Installation

With lazy.nvim:

Pi requires Node.js 22.19+; the bundled MCP server itself requires Node.js 18+.

{
  "shabaraba/vibing.nvim",
  build = "./build.sh", -- builds the bundled chat parser and MCP server
  dependencies = {
    "stevearc/oil.nvim", -- optional: add context straight from the file browser
  },
  opts = {},
},

opts is passed to require("vibing").setup(). See Configuration.

packer.nvim
use({
  "shabaraba/vibing.nvim",
  run = "./build.sh",
  config = function()
    require("vibing").setup()
  end,
}),
The bundled Claude Code plugin (MCP + skills + subagent)

vibing.nvim ships a Claude Code plugin that bundles the vibing-nvim MCP server together with Neovim-aware skills and a read-only navigation subagent.

Nothing to install. The plugin is not registered into Claude Code's global state at all β€” vibing.nvim hands the CLI its own agent-plugin/ directory per session with --plugin-dir, so whichever checkout is running is the one that serves you. build.sh builds the MCP server and the small Tree-sitter parser used for chat boundaries (and, once, cleans up an install from an older version of vibing.nvim).

Updating from claude-plugin/. The bundled directory is now agent-plugin/. Update any manually configured MCP args, integrations.plugins.extra, VIBING_MCP_SERVER_DIR, and lazy.nvim watch commands that point at the old directory. Rebuild from the updated checkout with ./build.sh, then restart Neovim and any resident CLI processes. The plugin name, MCP tool names, and .claude-plugin/ manifest directory are unchanged.

That gives you mcp__plugin_vibing-nvim_vibing-nvim__* tools (buffer/window/cursor access, Ex commands, and LSP queries against the running Neovim instance), the bundled skills (nvim-context, nvim-lsp-navigation, vibing-chat-recall, vibing-chat-search, and the vibing-worktree-{list,create,attach,run,finish} worktree workflow), and the nvim-navigator subagent (read-only code navigation via @vibing-nvim:nvim-navigator).

You still need Neovim running with mcp = { enabled = true } (the default) for the MCP tools to have anything to connect to. The one trade-off is that a plain claude session started outside Neovim no longer sees these tools; that was never a supported way to use them.

The Codex backend gets the same plugins without a --plugin-dir of its own: the MCP server is registered per run as -c mcp_servers.vibing-nvim.* (tools named mcp__vibing-nvim__*) and the skills are listed for the model in developer_instructions. Subagents do not carry over.

Your own project plugins. Anything you drop into .vibing/plugins/<name>/ (with a .claude-plugin/plugin.json) is loaded the same way, for chats in that project only. Run :VibingReloadCommands after adding one, or :VibingCreatePlugin <name> to write a working skeleton in the first place. Note that a plugin may declare mcpServers, so a plugin in a repository you cloned can start a process on your machine β€” set integrations.plugins.project_dir = false for repositories you do not trust. See handbook/configuration.md for integrations.plugins.

Upgrading from an older vibing.nvim: build.sh removes the user-scope install and its marketplace entry for you. To do it by hand:

/plugin uninstall vibing-nvim@vibing
/plugin marketplace remove vibing

πŸš€ Quick Start

:VibingChat

Type your message under the ## User header and press <CR> in normal mode to send. The AI responds in the same buffer; <C-c> cancels a running request. Chats stay ordinary Markdown files you can save, search and edit normally β€” a small vibing Tree-sitter parser isolates chat headers and tool output and injects the standard Markdown parser into each message body, so fenced code keeps its highlighting.

βš™οΈ Configuration

require("vibing").setup() works out of the box. Commonly tweaked options:

require("vibing").setup({
  ai = {
    chat = { agent = "claude", model = "sonnet", effort = "default" },
    helpers = { model = "haiku", effort = "low" },
  },
  chat = {
    language = "ja",
    storage = { location = "project" },
  },
  ui = { window = { position = "current", width = 0.4 } },
  permissions = { mode = "acceptEdits", deny = { "Bash" } },
})

The permissions above are a template for new chat files; each chat's frontmatter carries its own permissions, and those are what is enforced at runtime.

Old setup keys are rejected with migration hints. Objects merge recursively and lists replace (including empty lists). See the migration guide.

Full reference: every option (window details, UI/gradient/tool markers, diff backends, granular permission rules, MCP, Node.js executable, daily summary, …) is documented in handbook/configuration.md.

Project-local Codex permission profiles

For the Codex backend, vibing.nvim creates .vibing/codex-permissions.toml when it initializes a project. Its default profile permits workspace and Git metadata writes without using full bypass mode; edit the file to narrow or extend the OS sandbox. Existing files are never overwritten. Git-tracked profiles are rejected unless ai.agents.codex.extensions.allow_tracked_profile = true explicitly trusts the reviewed file; locally generated, untracked profiles continue to load automatically. See Project-local Codex permission profiles.

πŸš€ Usage

Also available offline as :help vibing-commands, which carries per-command help tags.

Commands

Command Description
:VibingChat [position|file] Create new chat with optional position (current|right|left|top|bottom|back) or open saved file
:VibingToggleChat Toggle existing chat window (preserve current conversation)
:VibingChatFork [position] Fork current chat (create branch from current conversation)
:VibingChatHandoff [position] Summarize this chat and start a new one whose first message carries the summary (cheap continuation of a long chat)
:VibingChatJumpNextUser [count] Move the cursor to the next User section in the chat buffer
:VibingChatJumpPrevUser [count] Move the cursor to the previous User section in the chat buffer
:VibingSlashCommands Show slash command picker in chat
:VibingSetFileTitle [--linked] Generate AI title and rename chat file (uses an existing ## summary if present; --linked also renames linked chats)
:VibingSummarize [--with-title] [--linked] Generate AI summary of chat history and insert into buffer (--with-title then renames the file from that summary; --linked does the same to every chat linked through frontmatter)
:VibingDeleteChats [--unrenamed] Delete chat files (use --unrenamed to delete all unrenamed files)
:VibingContext [path] Add context: oil.nvim entry, visual selection (range), path argument, or current buffer when no args
:VibingClearContext Clear all context
:VibingCancel Cancel current request
:VibingSchedule [when] Schedule this chat's unsent message (default: the recorded limit reset; or 30m, 18:30, …)
:VibingPendingResumes List chats waiting on a usage limit reset or a scheduled send
:VibingCancelResume [all] Cancel the pending auto-resume/scheduled send for this chat (or every one with all); also clears the project's recorded usage limit
:VibingReloadCommands Reload custom slash commands and completion candidates
:VibingCreatePlugin [name] Create a project-local Claude Code plugin under .vibing/plugins/
:VibingCopyUnsentUserHeader Copy ## User <!-- unsent --> to clipboard
:VibingDailySummary [YYYY-MM-DD] Generate daily summary from project chat files (default: today)
:VibingDailySummaryAll [YYYY-MM-DD] Generate daily summary from all chat files (default: today)
  • :VibingChat always creates a fresh chat. Pass a position (current / right / left / top / bottom / back) or a saved chat file path to reopen it.
  • :VibingChatFork branches the current conversation in a different direction.
  • :VibingChatHandoff continues a long conversation in a fresh chat: the current one is summarized and the new chat's first message starts with that summary. Unlike a fork it does not carry the history, so every later request reads a few thousand tokens instead of the whole transcript. An existing ## summary section is reused as-is; run /summarize first if it is out of date.
  • Worktree lifecycle is handled by the bundled vibing-worktree-{list,create,attach,run,finish} skills entirely through natural language ("split this off into a worktree"), not by editor commands.

Slash commands (in chat)

Command Description
/context <file> Add file to context
/clear Clear context
/save Save current chat
/summarize Summarize conversation
/model <model> Set AI model for the current backend
/effort <level> Set reasoning effort (low/medium/high/xhigh/max)
/help Show available slash commands
/permissions or /perm Interactive permission builder - configure tool allow/deny rules
/allow [tool] Add tool to allow list (-tool removes), or show current list if no args
/deny [tool] Add tool to deny list (-tool removes), or show current list if no args
/ask [tool] Ask before using tool (-tool removes), or show current list if no args
/permission [mode] Set permission mode (default/acceptEdits/bypassPermissions/plan/dontAsk/auto)
/new-session Reset session and start fresh

/allow, /deny and /ask also accept granular patterns like Bash(git:*), Read(src/**/*.ts) and WebFetch(github.com).

Keymaps (in chat buffers)

All except q are configurable through keymaps.

Key Description
<CR> Send message (normal mode)
<C-c> Cancel current request
<C-a> Add file to context
gd Show diff for file under cursor (in Modified Files section)
gf Open file under cursor (Modified Files section, or any path in the chat)
gx Open URL on current line in browser
q Close chat window

πŸ“ Chat File Format

Frontmatter and layout

Chats are saved as Markdown files (.vibing/chat/chat-<timestamp>-....md by default) with YAML frontmatter for session resumption and configuration:

---
vibing.nvim: true
session_id: <cli-session-id>
created_at: 2024-01-01T12:00:00
working_dir: .vibing/worktrees/feature-x # Optional: working directory (relative to git root)
agent: claude # claude | codex | copilot | grok | pi (overrides global adapter setting for this chat)
mode: code # code | plan | explore
model: sonnet # Backend model id, e.g. sonnet or gpt-5.6-terra
effort: default # CLI/model default | low | medium | high | xhigh | max
permission_mode: acceptEdits # default | acceptEdits | bypassPermissions | plan | dontAsk | auto
permissions_allow:
  - Read
  - Edit
  - Write
  - Glob
  - Grep
permissions_deny:
  - Bash
permissions_ask: []
language: ja # Optional: default language for AI responses
---
# Vibing Chat

## User

Hello, Claude!

## Assistant

Hello! How can I help you today?
  • Session resumption β€” reopening a saved chat resumes the conversation via session_id
  • Fork tracking β€” a forked chat carries a forked_from field until its first response
  • Auditability β€” model, mode and permissions are all visible in frontmatter
  • Language β€” the optional language field fixes the AI's response language

πŸ—οΈ Architecture

How the pieces fit together

For detailed architecture documentation, see CLAUDE.md.

graph TB
    subgraph Neovim["Neovim Process"]
        Plugin["vibing.nvim<br/>(Lua Plugin)"]
        Buffer["Chat Buffer<br/>(.vibing/chat/*.md)<br/>- Markdown + YAML<br/>- Session metadata<br/>- Permission settings"]
        RPC["RPC Server<br/>(Async TCP)"]

        Plugin -->|manages| Buffer
        Plugin -->|uses| RPC
    end

    subgraph MCP["Node.js MCP Server"]
        MCPServer["MCP Server<br/>- Buffer operations<br/>- LSP queries<br/>- Command execution"]
    end

    subgraph AI["AI CLI Backends"]
        Claude["Claude CLI<br/>(claude -p --output-format stream-json)"]
        Codex["Codex CLI<br/>(codex exec --json)"]
        Copilot["Copilot CLI<br/>(copilot -p --output-format json)"]
    end

    RPC <-->|JSON-RPC| MCPServer
    Plugin -->|spawns & communicates<br/>JSON Lines| Claude
    Plugin -->|spawns & communicates<br/>JSON Lines| Codex
    Plugin -->|spawns & communicates<br/>JSON Lines| Copilot
Loading
Aspect Traditional REST API vibing.nvim (CLI Adapters)
Context Manually assembled MCP: agent requests on-demand
Editor Access None (fire & forget) Full bidirectional MCP
Session State Plugin manages CLI session with resume
Tool Execution Plugin implements CLI native tools

❓ FAQ

Which AI backends are supported?
  • Claude CLI (claude -p --output-format stream-json) β€” full Claude Code capabilities
  • Codex CLI (codex exec --json) β€” OpenAI Codex backend
  • GitHub Copilot CLI (copilot -p --output-format json) β€” GitHub Copilot backend
  • Grok Build CLI (grok --single --output-format streaming-json) β€” xAI Grok backend
  • Pi coding agent (pi --mode rpc) β€” a harness rather than a vendor CLI; it uses the provider selected in Pi's own configuration, including local models served through OpenAI-compatible endpoints

Switch globally with ai.chat.agent = "claude"|"codex"|"copilot"|"grok"|"pi" in setup, or per-chat by adding agent: claude, agent: codex, agent: copilot, agent: grok or agent: pi to a chat file's YAML frontmatter. effort: low|medium|high|xhigh|max controls reasoning for Claude, Codex and Grok when the selected model supports that level. New chats use effort: default, which passes no override and therefore preserves the same CLI/model default used before effort was configurable. Omitting the field has the same runtime behaviour for existing chats.

Note: on the Copilot backend, permissions.mode, permissions.ask and the in-chat Tool Approval UI are enforced through a generated Copilot plugin (.vibing/copilot-plugin/) that vibing.nvim loads per run with copilot --plugin-dir. Your own ~/.copilot/ configuration and login are never touched. Copilot's static --deny-tool flags are still passed as a backstop; they cover Bash (including Bash(cmd:*) patterns), Write, Edit, WebFetch and WebSearch, and vibing.nvim warns once when it drops a tool name Copilot cannot express.

Note: the Pi backend is the one backend with no tool approval of its own β€” Pi does not ask before running bash, and its JSON/RPC modes cannot prompt at all. vibing.nvim's permission layer is therefore the only one, and it is delivered as a Pi extension (pi-extension/) that ./build.sh compiles and pi --extension loads. If that bundle is missing, a Pi turn is restricted to read-only tools and says so once. Pi 1.2.0 includes an MCP client; configure servers in Pi's own mcp.json. Claude plugin servers are not injected by this backend. Real Pi/local-model verification is pending; see the manual procedure.

Model selection is Pi's, not vibing.nvim's: model: has to name something Pi can resolve through its own ~/.pi/agent/models.json or a provider you are logged into. For a local endpoint:

{
  "providers": {
    "mlx-local": {
      "baseUrl": "http://127.0.0.1:8081/v1",
      "api": "openai-completions",
      "apiKey": "not-needed",
      "models": [{ "id": "mlx-community/Qwen3.6-27B-4bit" }]
    }
  }
}

then ai.agents.pi.extensions.provider = "mlx-local" and model: mlx-community/Qwen3.6-27B-4bit. Naming the provider is not optional for a local endpoint: --model is a fuzzy pattern Pi matches over its built-in cloud catalogue as well, so an unqualified model: qwen picks a cloud model and the turn fails on a missing API key. With it named, any id your endpoint can serve works from model: alone β€” no models.json edit β€” which is what lets one mlx_lm.server serve every model.

The same extension also adds the two tools Pi does not have. Pi's built-in set is bash, read, write, edit, ls, grep, find and nothing else, so web_fetch and web_search are registered beside the gate β€” shaped like claude's WebFetch / WebSearch, so your existing rules for those apply unchanged. web_fetch works with no configuration; web_search has to call a real search API (claude's and codex's happen server-side inside the inference API, which a local endpoint has no equivalent of), so set BRAVE_SEARCH_API_KEY, TAVILY_API_KEY or SEARXNG_URL. With none of them set the tool is simply not offered. See handbook/configuration.md β†’ "Pi: web tools".

Why does it require Node.js?

Node.js is required for the MCP server, which provides AI with direct access to your running Neovim instance (buffer reads/writes, LSP queries, command execution). The AI CLI binaries themselves (claude, codex, copilot) are separate installs.

How does it compare to the Claude Code CLI?

vibing.nvim provides similar capabilities to Claude Code CLI but integrated into Neovim:

  • Same claude CLI underneath
  • MCP for editor control (the CLI controls a terminal, vibing controls Neovim)
  • Additional Codex, Copilot and Grok backends for non-Anthropic workflows

Think of it as "Claude Code (or Codex, or Copilot) for Neovim users."

Can I use vibing.nvim alongside other AI plugins?

Yes. vibing.nvim doesn't conflict with completion plugins (Copilot, Codeium) or other chat plugins. Use vibing.nvim for deep interactions and other tools for quick completions or different providers.

🀝 Contributing

Contributions are welcome! See CONTRIBUTING.md, and feel free to submit issues or pull requests.

πŸ“„ License

MIT β€” see LICENSE.

πŸ”— Links


Made with ❀️ using Claude Code

About

Neovim plugin for AI-assisted coding: Claude CLI & Codex CLI backends with MCP-powered editor control

Topics

Resources

Contributing

Security policy

Stars

13 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages