Intelligent AI-Powered Code Assistant for Neovim
A powerful Neovim plugin that integrates Claude, Codex, and GitHub Copilot AI via CLI backends, bringing intelligent, context-aware chat conversations directly into your editor.
English | 日本語
Features • Installation • Usage • Configuration • Contributing
- Features
- Installation
- Quick Start
- Usage
- Configuration
- Chat File Format
- Architecture
- FAQ
- Contributing
- License
- Links
Unlike chat plugins that send static context to an LLM, vibing.nvim gives the AI direct access to your Neovim instance through CLI backends and MCP integration.
- 🤖 Neovim as an agent tool — via MCP, the AI reads and writes buffers, executes commands, and queries LSP (diagnostics, definitions, references, symbols) in your running editor
- 🔀 Multi-backend — Claude CLI (
claude -p --output-format stream-json), Codex CLI (codex exec --json), GitHub Copilot CLI (copilot -p --output-format json), or Grok Build CLI (grok --single --output-format streaming-json); switch globally viaadapteror per-chat via theagentfrontmatter field - 💾 File-based session persistence — chats are plain Markdown files with YAML frontmatter
saved under
.vibing/chat/: portable, resumable (full CLI session state), auditable, and version-controllable - 🔀 Concurrent sessions — run multiple independent chats simultaneously; start a new chat while another is still processing
- 🛡️ Granular permissions — allow/deny/ask lists per tool, path-based rules for sensitive files, Bash command patterns, and an interactive Permission Builder UI
- 📊 Diff viewer —
gdon a changed file shows a before/after diff. Each turn is snapshotted as a git tree object, so ased -i, amvor a formatter run through Bash is tracked exactly like anEdit— with no external tool and no setup, and without touching your index - 🎯 Smart context — add files manually, from oil.nvim, or from a visual selection
- ⏳ Usage-limit scheduling — while a usage limit is in force,
<CR>parks your message instead of burning a doomed request, and sends it verbatim once the limit resets;:VibingSchedule 30mschedules one by hand, with or without a limit - 🌍 Multi-language support — configure the AI response language per chat
- Need local/offline models (Ollama, etc.)
- Prefer minimal dependencies (vibing.nvim requires 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.
- Neovim 0.10+ (uses
vim.system()) - Node.js 18+ (for the MCP server)
- At least one AI CLI backend:
- Claude CLI (
claude) —npm install -g @anthropic-ai/claude-code - Codex CLI (
codex) —npm install -g @openai/codex(0.140+; see note below) - GitHub Copilot CLI (
copilot) —npm install -g @github/copilot(needs Node.js 22+, higher than the 18+ the MCP server itself requires) - Grok Build CLI (
grok) — see xAI's install docs
- Claude CLI (
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, oncodex execandcodex exec resumealike. 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-configalso dropsmodel_provider, so if yourconfig.tomlpoints 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. Setagent.codex_provider_notice.enabled = falseto turn the warning and its probe off.
Using lazy.nvim
{
"shabaraba/vibing.nvim",
dependencies = {
"stevearc/oil.nvim", -- Optional: file browser integration
},
build = "./build.sh", -- Builds the bundled chat parser and MCP server
config = function()
require("vibing").setup()
end,
}See Configuration for the options you can pass to setup().
Using packer.nvim
use {
"shabaraba/vibing.nvim",
run = "./build.sh",
config = function()
require("vibing").setup()
end,
}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 claude-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). If no C compiler is available, the parser build is skipped and chat
buffers fall back to the previous whole-buffer Markdown parser.
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
agent.plugins.project_dir = false for repositories you do not trust. See
handbook/configuration.md for agent.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
:VibingChat " Open a new chatType 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 remain ordinary Markdown
files that you can save, search, and edit normally. In Neovim, the small vibing Tree-sitter
parser isolates chat headers and tool output, then injects the standard Markdown parser into each
message body. Existing Markdown highlighting, including fenced code languages, is preserved.
Also available offline as :help vibing-commands, which carries per-command
help tags.
| 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 |
Generate AI title and rename chat file (uses an existing ## summary if present) |
:VibingSummarize [--with-title] |
Generate AI summary of chat history and insert into buffer (--with-title then renames the file from that summary) |
: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) |
Command Semantics:
:VibingChat— always creates a fresh chat. Optionally specify a position (current/right/left/top/bottom/back) or a saved chat file path to reopen it.:VibingChatFork— fork the current conversation to branch in a different direction (accepts the same positions).:VibingChatHandoff— continue a long conversation in a fresh chat: the current chat 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 of summary instead of the whole transcript (accepts the same positions). An existing## summarysection is reused as-is; run/summarizefirst if it is out of date.:VibingToggleChat— show/hide your current conversation, preserving its state.- Worktree lifecycle — handled by the bundled
vibing-worktree-{list,create,attach,run,finish}Claude Code skills entirely via natural language ("split this off into a worktree"), not by editor commands.
| 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).
In chat buffers (all except q are configurable via keymaps — see
Configuration):
| 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 |
require("vibing").setup() works out of the box. Commonly tweaked options:
require("vibing").setup({
adapter = "claude", -- "claude" | "codex" | "copilot" | "grok"
chat = {
window = {
position = "current", -- "current" | "right" | "left" | "top" | "bottom" | "back" | "float"
width = 0.4, -- screen-width ratio (0-1)
},
save_location_type = "project", -- "project" | "user" | "custom"
},
agent = {
default_model = "sonnet", -- backend model id, e.g. "sonnet" or "gpt-5.6-terra"
default_effort = "default", -- "default" | "low" | "medium" | "high" | "xhigh" | "max"
scheduled_requests = {
enabled = true, -- during a usage limit, <CR> schedules instead of sending
},
},
permissions = {
mode = "acceptEdits", -- "default" | "acceptEdits" | "plan" | "auto" | "dontAsk" | "bypassPermissions"
allow = { "Read", "Edit", "Write", "Glob", "Grep", "Skill", "StructuredOutput" },
deny = { "Bash" },
codex_profile_file = ".vibing/codex-permissions.toml", -- false disables loading the generated profile
-- codex_profile_content = [[...]], -- initial TOML used only when creating the profile
codex_allow_tracked_profile = false, -- true explicitly trusts a Git-tracked profile
},
language = nil, -- e.g. "ja", or { default = "ja", chat = "ja" }
})The default permissions shown above are used as a template when creating new chat files; each chat file's frontmatter carries its own permissions, which are what's enforced at runtime.
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 codex_allow_tracked_profile = true explicitly trusts
the reviewed file; locally generated, untracked profiles continue to load automatically.
See Project-local Codex permission profiles.
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.
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 (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?Key Features:
- Session Resumption — reopening a saved chat resumes the conversation via
session_id - Fork tracking — a forked chat carries a
forked_fromfield until its first response - Auditability — model, mode, and permissions are all visible in frontmatter
- Language Support — optional
languagefield for consistent AI response language
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
| 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 |
- 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
Switch globally with adapter = "claude"|"codex"|"copilot"|"grok" in setup, or per-chat by adding
agent: claude, agent: codex, agent: copilot, or agent: grok 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.askand the in-chat Tool Approval UI are enforced through a generated Copilot plugin (.vibing/copilot-plugin/) that vibing.nvim loads per run withcopilot --plugin-dir. Your own~/.copilot/configuration and login are never touched. Copilot's static--deny-toolflags are still passed as a backstop; they coverBash(includingBash(cmd:*)patterns),Write,Edit,WebFetchandWebSearch, and vibing.nvim warns once when it drops a tool name Copilot cannot express.
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.
vibing.nvim provides similar capabilities to Claude Code CLI but integrated into Neovim:
- Same
claudeCLI underneath - MCP for editor control (CLI controls terminal, vibing controls Neovim)
- Additional Codex and GitHub Copilot backend options for non-Anthropic workflows
Think of it as "Claude Code (or Codex, or Copilot) for Neovim users."
Yes. vibing.nvim doesn't conflict with completion plugins (Copilot, Codeium) or other chat plugins. Use vibing.nvim for deep Claude interactions and other tools for quick completions or different providers.
Contributions are welcome! See CONTRIBUTING.md, and feel free to submit issues or pull requests.
MIT License - see LICENSE file for details
Made with ❤️ using Claude Code!