Skip to content

AI Code Assistants for Vim & Neovim: Advanced Setup Guide

Set up AI code assistants in Vim and Neovim with copilot.lua, sidekick.nvim, and local LLMs - plus the gotchas no tutorial mentions.

8 min readAdvanced

Here’s something most setup guides skip: the most popular Lua-based Copilot plugin for Neovim exists because the official one made a developer’s laptop overheat. The author of copilot.lua reported that while using copilot.vim, for the first time since starting with Neovim his laptop began to overheat, and the large chunks of ghost text moving around interfered with existing cmp ghost text (tamerlan.dev, quoting the plugin author). That’s the kind of detail that shapes a real workflow.

This guide assumes you already know your way around init.lua, lazy.nvim, and an LSP config. We’re skipping the screenshot-heavy install walkthrough and going straight to a layered AI code assistants setup for Vim and Neovim – one engine for inline completion, one for agentic edits, optional local fallback – plus the conflicts that will eat hours if you don’t see them coming.

The three-layer mental model

Stop thinking about “which AI plugin” and start thinking about which layer. There are three, and each wants different code:

  • Layer 1 – Inline completion: ghost text as you type. copilot.lua, NeoCodeium, Minuet, Supermaven.
  • Layer 2 – Multi-line edits / NES: whole-function rewrites, refactors, hunk navigation. sidekick.nvim, avante.nvim, codecompanion.nvim.
  • Layer 3 – Chat / agent: ask questions about the buffer, run a coding agent. CodeCompanion, Avante, or a CLI like Claude Code piped through sidekick.

You want exactly one tool per layer. Two engines fighting for the same virtual text namespace is the single most common reason “my AI just stopped working.”

Layer 1: a sane copilot.lua install

Skip github/copilot.vim unless you’re on plain Vim – it requires Node.js and Vim 9.0.0185+ (per the official copilot.vim README). For Neovim, zbirenbaum/copilot.lua is 100% Lua and integrates cleanly with cmp. The minimum viable lazy.nvim spec:

-- ~/.config/nvim/lua/plugins/copilot.lua
return {
 "zbirenbaum/copilot.lua",
 cmd = "Copilot",
 event = "InsertEnter",
 opts = {
 suggestion = {
 enabled = true,
 auto_trigger = true,
 debounce = 75,
 keymap = {
 accept = "<M-l>", -- Alt+L, never Tab
 next = "<M-]>",
 prev = "<M-[>",
 dismiss = "<C-]>",
 },
 },
 panel = { enabled = false },
 filetypes = {
 ["*"] = true,
 gitcommit = false,
 [".env"] = false,
 },
 },
}

Two non-obvious choices in there. First, accept is bound to <M-l> not <Tab> – Tab is owned by your snippet engine and your completion menu, and giving it to Copilot is how you get the dreaded “why did it just paste 12 lines I didn’t want.” Second, .env is explicitly off so the plugin doesn’t read your secrets into a remote model. Run :Copilot auth to finish setup.

Layer 2: sidekick.nvim for Next Edit Suggestions

This is the layer most tutorials don’t cover at all. Turns out sidekick.nvim does more than inline completion – it adds Next Edit Suggestions (NES) powered by the Copilot LSP, fetches them automatically when you pause typing, and visualizes them with Treesitter-based diffs down to the word or character level (per the sidekick.nvim README). NES is the difference between “autocomplete the next line” and “the AI proposes a coordinated edit across this function.”

Critical gotcha: NES is not the same as copilot.lua’s inline suggestions. It uses the official copilot-language-server LSP, which has to be installed separately and enabled via vim.lsp.enable – disabled by default in the standard copilot.lua config. Skip that step and sidekick installs cleanly but does literally nothing. The plugin won’t warn you either.

return {
 "folke/sidekick.nvim",
 opts = {
 nes = {
 enabled = true,
 diff = { inline = "words" },
 },
 cli = {
 mux = { backend = "tmux", enabled = true },
 tools = {
 claude = {}, codex = {}, gemini = {},
 },
 },
 },
 keys = {
 { "<tab>", function() require("sidekick.nes").jump() end, mode = { "n" } },
 { "<leader>aa", function() require("sidekick.cli").toggle() end, mode = { "n", "v" } },
 },
}

The sleeper feature here is the CLI integration: direct access to Claude, Gemini, Codex, and Copilot CLI without leaving Neovim, with tmux/zellij keeping those sessions alive across editor restarts. Run :checkhealth sidekick to see which CLIs it actually detected.

Layer 3: pick one chat surface

You only need one. The two serious options:

Plugin Strength Watch out for
codecompanion.nvim Anthropic, OpenAI, Gemini, Copilot – plus built-in ACP and MCP support and agents like Claude Code and Codex Heavier config; the maintainer asks for minimal.lua repros on issues
avante.nvim Cursor-style apply-to-buffer UX Requires Neovim 0.11.0 or later; project is under active development – both functionality and interface may change significantly

If you’re already paying for Claude or running a Copilot subscription, CodeCompanion is the more stable bet as of mid-2026. Avante is the playground.

The local-LLM escape hatch

Can’t send code to a cloud at all? Minuet supports OpenAI, Gemini, Claude, Ollama, Llama.cpp, and Codestral as completion backends – meaning you can point it at a local Ollama running Qwen2.5-Coder and never touch a remote API.

The failure mode that’s actually maddening: completions silently stop. No error, no warning. According to the minuet-ai.nvim troubleshooting docs, the two most likely culprits are a wrong API key or a model/context window large enough that requests time out before returning any tokens. If suggestions disappear without explanation, drop the context window size or switch to a smaller model before touching anything else.

The other trap – don’t enable Minuet’s virtualtext mode while also using Neovim’s built-in LSP inline_completion. The minuet-ai.nvim README flags this explicitly: both write to the same virtual text layer and you’ll get duplicate or flickering suggestions. This is the single-engine-per-layer rule biting back.

Common pitfalls that aren’t in any README

Pro tip: Before debugging anything, run :Copilot status, :checkhealth sidekick, and :LspInfo. Three quarters of “my AI broke” issues are one of: expired auth, missing copilot-language-server binary, or a second plugin silently claiming the same insert-mode keymap.

NeoCodeium exists because the official Codeium plugin had flickering suggestions – actually maddening with multi-line virtual text. If you’re on the official plugin and hitting that, switch. One catch: NeoCodeium ships with no debounce by default, so suggestions fire while you’re still typing. On a slow connection that default makes the editor feel possessed. Set debounce = true in the config and you’re done.

The Tab collision. Almost every basic tutorial tells you to bind accept to <Tab>. Then your snippet plugin breaks, your cmp menu navigation breaks, and you spend an evening blaming the wrong plugin. Use Alt-based bindings.

The privacy assumption. Cloud assistants don’t all behave the same. vim-ai, for example, only sends what you explicitly select – it doesn’t transmit surrounding buffer context behind the scenes (per the vim-ai README). Copilot sees the surrounding buffer. If you’re working under an NDA, read each plugin’s data policy before installing it, not after.

Performance: what to actually expect

Latency numbers for Layer 1 vary too much by connection, model, and hardware to quote responsibly here – user reports range widely, and there’s no published benchmark for copilot.lua specifically. What’s consistent: local Ollama on a CPU-only machine is noticeably slower than a cloud backend, and enabling auto-trigger on slow hardware tends to make the editor feel sluggish. If that happens, set auto_trigger = false and use a manual keybind instead.

The honest unknown: there’s no public benchmark comparing NES quality between copilot-language-server and community implementations. Anecdotally, NES wins for refactors and loses for greenfield code. You’ll figure out which side of that line your work falls on within a week.

When you should not install any of this

Three cases. If you’re learning a new language – turn it off. Ghost text robs you of the productive struggle that makes things stick. If you’re working on safety-critical code where every line needs justification – turn it off; defending “the AI suggested it” doesn’t fly in code review. And if your laptop already runs hot under load, think hard before stacking copilot.lua + sidekick + a local Ollama. Three layers is a flex, not a default.

FAQ

Do I need both copilot.lua and sidekick.nvim, or is one enough?

One is enough if all you want is inline ghost text. sidekick adds a different layer – multi-line refactor suggestions and a CLI bridge. They don’t overlap.

My completions stopped showing up after I added a second AI plugin. What happened?

Almost certainly two plugins claiming the same virtual text namespace or insert-mode keymap. Here’s the fastest way to debug it: disable the newer plugin entirely, restart Neovim, confirm the original one works, then re-enable the second in manual mode if it offers one. NeoCodeium has a manual = true option for exactly this reason – it stops competing with nvim-cmp for keymap control. Once both are stable in isolation, test them together. If it breaks again, one of them is silently stealing an insert-mode binding; run :verbose imap <Tab> to find out which.

Can I use these plugins without a paid Copilot subscription?

Yes – Minuet plus a local Ollama model costs nothing. Codeium has a free tier. GitHub documents a free Copilot plan with monthly usage limits (check GitHub’s current pricing page for the latest caps, as these have changed before). The paid Copilot plan mainly buys you the official LSP binary and NES – which is what sidekick.nvim is built around.

Next action: open your ~/.config/nvim/lua/plugins/ directory, create one file per layer (copilot.lua, sidekick.lua, optionally codecompanion.lua), and run :Lazy sync. Then run :checkhealth on each before you write a single line of real code – fix everything red before you trust a suggestion.