Skip to content

coder/claudecode.nvim

Repository files navigation

Claude Code Neovim Integration

Tests Neovim version Status

A Neovim plugin that integrates with Claude Code CLI to provide a seamless AI coding experience in Neovim.

Features

  • 🔄 Pure Neovim WebSocket Server - Zero external dependencies, uses only Neovim built-ins
  • 🌐 RFC 6455 Compliant - Full WebSocket protocol implementation with JSON-RPC 2.0
  • 🔍 Selection tracking to provide context to Claude
  • 🛠️ Integration with Neovim's buffer and window management
  • 📝 Support for file operations and diagnostics
  • 🖥️ Interactive vertical split terminal for Claude sessions (supports folke/snacks.nvim or native Neovim terminal)
  • 🔒 Automatic cleanup on exit - server shutdown and lockfile removal

Requirements

  • Neovim >= 0.8.0
  • Claude Code CLI installed and in your PATH
  • Optional for terminal integration: folke/snacks.nvim - Terminal management plugin (can use native Neovim terminal as an alternative).

Zero External Dependencies: The WebSocket server is implemented using pure Neovim built-ins (vim.loop, vim.json, vim.schedule) with no external Lua libraries required.

Note: The terminal feature can use Snacks.nvim or the native Neovim terminal. If Snacks.nvim is configured as the provider but is not available, it will fall back to the native terminal.

Installation

Using lazy.nvim

Add the following to your plugins configuration:

{
  "coder/claudecode.nvim",
  dependencies = {
    "folke/snacks.nvim", -- Optional dependency for enhanced terminal
  },
  opts = {
    -- Configuration for claudecode main
    -- Optional: terminal_cmd = "claude --magic-flag",

    -- Configuration for the interactive terminal:
    terminal = {
      split_side = "right",            -- "left" or "right"
      split_width_percentage = 0.3,    -- 0.0 to 1.0
      provider = "snacks",             -- "snacks" or "native"
      show_native_term_exit_tip = true, -- Show tip for Ctrl-\\ Ctrl-N
    },
  },
  -- The plugin will call require("claudecode").setup(opts)
  config = true,
  -- Optional: Add convenient keymaps
  keys = {
    { "<leader>cc", "<cmd>ClaudeCode<cr>", desc = "Toggle Claude Terminal" },
    { "<leader>ck", "<cmd>ClaudeCodeSend<cr>", desc = "Send to Claude Code" },
    { "<leader>co", "<cmd>ClaudeCodeOpen<cr>", desc = "Open Claude Terminal" },
    { "<leader>cx", "<cmd>ClaudeCodeClose<cr>", desc = "Close Claude Terminal" },
  },
}

For those who prefer a function-style config:

{
  "coder/claudecode.nvim",
  dependencies = {
    "folke/snacks.nvim", -- Optional dependency
  },
  config = function()
    -- If using snacks, ensure it's loaded
    -- require("snacks")
    require("claudecode").setup({
      -- Optional configuration
    })
  end,
}
use {
  "coder/claudecode.nvim",
  requires = {
    "folke/snacks.nvim", -- Optional dependency
  },
  config = function()
    require("claudecode").setup({
      -- Optional configuration
    })
  end
}

Local Development with LazyVim

For local development with LazyVim, create a lua/plugins/claudecode.lua file with the following content:

return {
  {
    dir = "~/GitHub/claudecode.nvim",  -- Path to your local repository
    name = "claudecode.nvim",
    dependencies = {
      "folke/snacks.nvim", -- Added dependency
    },
    dev = true,
    opts = {
      -- Development configuration for claudecode main
      log_level = "debug",
      auto_start = true,

      -- Example terminal configuration for dev:
      terminal = {
        split_side = "right",
        split_width_percentage = 0.25,
        provider = "native",
        show_native_term_exit_tip = false,
      },
    },
    config = true,
    keys = {
      { "<leader>cc", "<cmd>ClaudeCode<cr>", desc = "Toggle Claude Terminal" },
      { "<leader>ck", "<cmd>ClaudeCodeSend<cr>", desc = "Send to Claude Code" },
      { "<leader>co", "<cmd>ClaudeCodeOpen<cr>", desc = "Open Claude Terminal" },
      { "<leader>cx", "<cmd>ClaudeCodeClose<cr>", desc = "Close Claude Terminal" },
    },
  },
}

This configuration:

  1. Uses the dir parameter to specify the local path to your repository
  2. Sets dev = true to enable development mode
  3. Sets a more verbose log level for debugging
  4. Adds convenient keymaps for testing

Configuration

require("claudecode").setup({
  -- Port range for WebSocket server (default: 10000-65535)
  port_range = { min = 10000, max = 65535 },

  -- Auto-start WebSocket server when the plugin is loaded.
  -- Note: With lazy-loading (e.g., LazyVim), this means the server starts when a plugin command is first used.
  auto_start = true,

  -- Custom terminal command to use when launching Claude
  -- This command is used by the new interactive terminal feature.
  -- If nil or empty, it defaults to "claude".
  terminal_cmd = nil, -- e.g., "my_claude_wrapper_script" or "claude --project-foo"

  -- Log level (trace, debug, info, warn, error)
  log_level = "info",

  -- Enable sending selection updates to Claude
  track_selection = true,

  -- Milliseconds to wait before "demoting" a visual selection to a cursor/file selection
  -- when exiting visual mode. This helps preserve visual context if quickly switching
  -- to the Claude terminal. (Default: 50)
  visual_demotion_delay_ms = 50,

  -- Configuration for the interactive terminal (passed to claudecode.terminal.setup by the main setup function)
  terminal = {
    -- Side for the vertical split ('left' or 'right')
    split_side = "right", -- Default

    -- Width of the terminal as a percentage of total editor width (0.0 to 1.0)
    split_width_percentage = 0.30, -- Default

    -- Terminal provider ('snacks' or 'native')
    -- If 'snacks' is chosen but not available, it will fall back to 'native'.
    provider = "snacks", -- Default

    -- Whether to show a one-time tip about exiting native terminal mode (Ctrl-\\ Ctrl-N)
    show_native_term_exit_tip = true -- Default
  }
})

Usage

  1. Start the Claude Code integration with the interactive terminal:

    :ClaudeCode
    

    This will:

    • Start the WebSocket server
    • Open a terminal split with Claude Code CLI already connected
    • Configure the necessary environment variables automatically
  2. You can now interact with Claude in the terminal window. To provide code context, you can:

    • Make a selection in visual mode (v key), then run:

      :ClaudeCodeSend
      
    • This sends the selected lines with file references to Claude

  3. Switch between your code and the Claude terminal:

    • Use normal Vim window navigation (Ctrl+w commands)
    • Or toggle the terminal with :ClaudeCode
    • Open/focus with :ClaudeCodeOpen
    • Close with :ClaudeCodeClose
  4. Use Claude as normal - it will have access to your Neovim editor context!

Commands

  • :ClaudeCodeStart - Start the Claude Code integration server
  • :ClaudeCodeStop - Stop the server
  • :ClaudeCodeStatus - Show connection status
  • :ClaudeCodeSend - Send current selection to Claude
  • :ClaudeCode - Toggle the Claude Code interactive terminal window
  • :ClaudeCodeOpen - Open (or focus) the Claude Code terminal window
  • :ClaudeCodeClose - Close the Claude Code terminal window

Keymaps

No default keymaps are provided. Add your own in your configuration:

vim.keymap.set("n", "<leader>cc", "<cmd>ClaudeCode<cr>", { desc = "Toggle Claude Terminal" })
vim.keymap.set({"n", "v"}, "<leader>ck", "<cmd>ClaudeCodeSend<cr>", { desc = "Send to Claude Code" })

-- Or more specific maps:
vim.keymap.set("n", "<leader>co", "<cmd>ClaudeCodeOpen<cr>", { desc = "Open Claude Terminal" })
vim.keymap.set("n", "<leader>cx", "<cmd>ClaudeCodeClose<cr>", { desc = "Close Claude Terminal" })

Architecture

The plugin follows a modular architecture with these main components:

  1. WebSocket Server - Handles communication with Claude Code CLI using JSON-RPC 2.0 protocol
  2. Lock File System - Creates and manages lock files that Claude CLI uses to detect the editor integration
  3. Selection Tracking - Monitors text selections and cursor position in Neovim
  4. Tool Implementations - Implements commands that Claude can execute in the editor

For more details, see ARCHITECTURE.md.

Developing Locally

This project uses Nix for development environment management. For the best experience:

  1. Install Nix with flakes support

  2. Clone the repository:

    git clone https://github.com/coder/claudecode.nvim
    cd claudecode.nvim
  3. Enter the development shell:

    nix develop
    # Or use direnv if available
    direnv allow
  4. Run development commands:

    # Format code
    nix fmt
    
    # Check code for errors
    make check
    
    # Run tests
    make test
  5. Link to your Neovim plugins directory:

    # For traditional package managers
    ln -s $(pwd) ~/.local/share/nvim/site/pack/plugins/start/claudecode.nvim

Without Nix, ensure you have:

  • Lua 5.1+
  • LuaCheck for linting
  • StyLua for formatting
  • Busted for testing

Troubleshooting

Connection Issues

If Claude isn't connecting to Neovim:

  1. Check if the WebSocket server is running: :ClaudeCodeStatus
  2. Verify lock file exists in ~/.claude/ide/
  3. Check that Claude CLI has the right environment variables set

Debug Mode

Enable more detailed logging:

require("claudecode").setup({
  log_level = "debug",
})

Contributing

Contributions are welcome! Please see DEVELOPMENT.md for development guidelines.

License

MIT

Acknowledgements

About

🧩 Claude Code Neovim IDE Extension

Topics

Resources

License

Code of conduct

Security policy

Stars

Watchers

Forks

Contributors 6

Languages