Model or dataset
milanglacier/minuet-ai.nvim avatar
milanglacier/minuet-ai.nvim

minuet-ai.nvim: LLM completion inside Neovim without a background binary

💃 Dance with Intelligence in Your Code. Minuet offers code completion as-you-type from popular LLMs including OpenAI, Gemini, Claude, Ollama, Llama.cpp, Codestral, and more.

1,403 stars64 forksLuaGPL-3.0

At a glance

What is it?
Minuet is a Lua plugin that turns OpenAI, Claude, Gemini, Codestral, Ollama and llama.cpp endpoints into as-you-type completions in Neovim, with virtual text, nvim-cmp, blink.cmp and an opt-in in-process LSP frontend. The interesting part is not the provider list but the plumbing: it talks HTTP through vim.system and curl, so there is no daemon to install.
Who is it for?
Adopt Minuet if you already pay for a hosted model or run Ollama or llama.cpp locally and want completions that never leave your terminal, and if you are willing to tune the fetching timeout because LLM latency sits well above what nvim-cmp expects. Do not adopt it if you need a completion path with no network dependency or no API key, or if you want next-edit prediction that behaves predictably: the README labels Duet highly experimental.
Can I use it commercially?
Yes, with conditions. GPL-3.0 is a copyleft licence: if you distribute software that includes it, you must release that software's source code under the same licence. Running it internally without distributing it does not trigger that obligation.
Is it still maintained?
Yes. The repository last received commits 32 days ago.
What is it written in?
Mainly Lua, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.

DEEP OPEN-SOURCE ANALYSIS

The problem Minuet targets: completion latency and where the model lives

Editor completion has traditionally been local. A language server or a snippet engine answers in milliseconds because it runs on the same machine and does not need a network round trip. Minuet inserts a remote or locally hosted language model into that same interaction: the README describes it as offering code completion as-you-type from providers including OpenAI, Gemini, Claude, Ollama, llama.cpp and Codestral. That framing tells you who it is for. It is for people who already have an API key or a local model server and who want suggestions in the buffer rather than in a chat window they have to switch to.

The design constraint that follows from this is latency. A local language server answers from an index; a language model answers from a forward pass, and a hosted one adds network time on top. The README acknowledges this directly in the nvim-cmp setup, noting that the fetching timeout should be increased because LLMs respond more slowly than other completion sources, and that this is unnecessary when you only need manual completion. That single sentence is the honest core of the plugin: it is built for a slower completion path, and it gives you a manual trigger as the escape hatch when the automatic path is too slow for your taste.

The second problem is deployment surface. Many editor AI integrations ship a compiled helper process that runs alongside the editor. Minuet states as a feature that there is no proprietary binary running in the background, and that it uses curl and your preferred LLM provider. That is a real difference in what you have to install, audit and keep updated.

How Minuet talks to a model: vim.system, curl, and two prompt shapes

The requirements section records a change in the transport layer: Minuet previously depended on plenary.nvim but now uses the builtin vim.system and no longer requires plenary. That places a floor under the supported Neovim version, and the README states it plainly: Neovim 0.10 or newer. The plugin is written in Lua and shells out rather than linking a client library, which is why the README can claim that curl plus a provider is the whole dependency chain.

On top of that transport sit two request shapes. The first is chat-style prompting, where the README says Minuet applies specialized prompts and various enhancements for chat-based LLMs on code completion tasks. The second is fill-in-the-middle, described as FIM completion for compatible models including DeepSeek, Codestral and Qwen. The distinction matters because it changes which endpoint you configure and what the model sees. The README has a dedicated section, Prefix-First vs. Suffix-First, which is where the prompt ordering decision lives; the table of contents lists it under Prompt, so the plugin exposes the choice rather than hiding it.

There is also a synchronization behaviour worth noting because it is not obvious from a feature list. The README says that when your typed text matches the start of a suggestion, Minuet keeps the completion in sync with what you typed instead of discarding it, in order to reduce unnecessary LLM requests. In practice this means the plugin is tracking your input against the pending suggestion rather than treating every keystroke as a reason to call the provider again. Multi-line suggestions are handled line-by-line, so a long suggestion is pulled in incrementally rather than pasted as a block.

Frontends: virtual text, nvim-cmp, blink.cmp, builtin and mini.completion

Minuet does not draw its own completion menu. It feeds one of several frontends, and the README lists virtual-text, nvim-cmp, blink-cmp, builtin and mini.completion. The virtual text path is the one that needs no completion framework at all: the Lazy.nvim snippet marks nvim-cmp and blink.cmp as optional, with the comment that if you are using the virtual-text frontend neither is required.

The virtual text setup block is explicit about the keymaps, which is useful because these are the controls you will actually press:

accept = '<A-A>' accepts the whole completion, accept_line = '<A-a>' accepts one line, accept_n_lines = '<A-z>' prompts for a number (the README gives "A-z 2 CR" as accepting two lines), prev = '<A-[' and next = '<A-]' cycle or manually invoke completion, and dismiss = '<A-e>' clears it. The auto_trigger_ft list is empty by default in that snippet, which means virtual text completion does not fire automatically until you name the filetypes you want it in.

For buffer-level completion, the nvim-cmp setup adds minuet as a source by name and pairs it with your other sources. The README's FAQ section addresses two integration annoyances by name: customizing the cmp and blink UI for source and kind icons, and a significant input delay when moving to a new line with nvim-cmp. It also documents integration with lazyvim. The builtin frontend requires Neovim 0.11 or newer, which is a stricter floor than the plugin's own 0.10 requirement, and the README notes the builtin and inline completion paths are reached through an in-process LSP mode that is opt-in.

Running it: setup, provider selection and the commands you type

Installation is a Lazy.nvim spec pointing at milanglacier/minuet-ai.nvim with a config function calling require('minuet').setup, or Rocks install minuet-ai.nvim from luarocks.org. Beyond that, configuration is a Lua table, and the README points to a Configuration section rather than enumerating every key inline in the material available here.

Provider choice is where the real setup work sits. The README provides worked examples for Openrouter deepseek-v4-flash, Opencode Go deepseek-v4-flash, Deepseek deepseek-v4-flash, Ollama Qwen-2.5-coder:7b and llama.cpp Qwen-2.5-coder:1.5b. The two local examples are the ones that change your dependency profile: with Ollama or llama.cpp there is no API key to manage, but you are responsible for running and sizing the model. The Providers section then breaks down individual integrations: OpenAI, Claude, Codestral, Mercury Coder, Gemini, OpenAI-compatible, and OpenAI-FIM-compatible, with a subsection on non-OpenAI-FIM-compatible APIs for endpoints that do not match the expected shape. There is also a separate API Keys section, so key handling is a documented concern rather than something you scatter through the config.

Day to day you drive the plugin through commands. Minuet change_provider and Minuet change_model switch the active backend, Minuet change_preset switches between saved configurations, Minuet blink and Minuet cmp wire up the respective frontends, Minuet virtualtext controls the virtual text mode, Minuet lsp starts the in-process LSP, and Minuet duet is the next-edit prediction entry point. The README also documents an API surface with Virtual Text and Duet functions, a Lualine integration, and a Minuet Event system with separate standard completion events and Duet events, each carrying event data. If you want completion state visible in your statusline or want to hook behaviour on completion results, that is the supported path.

Duet and RAG: the experimental parts, and what that label means

Two features carry an experimental label in the README, and both deserve scrutiny before you build a workflow on them.

Duet is next-edit prediction. The README calls it highly experimental. It has its own command, Minuet duet, its own event category with its own event data, and its own configuration block covering auto trigger, recent edits, and a TODO list. The presence of a TODO section in the documentation is itself informative: parts of the feature are described as not yet done. Next-edit prediction is a harder problem than completion because the model is guessing where you will edit next rather than continuing text you have already written, and the failure mode is a suggestion that moves your cursor or edits a region you did not intend. The recent edits configuration suggests the plugin feeds prior edit context to the model, which is the mechanism by which it tries to make that guess. Treat Duet as something to try on a branch, not something to rely on during a deadline.

RAG is listed under an Enhancement section and marked experimental as well. The material available here does not describe its retrieval mechanism in detail, so it is not possible to say what it indexes or how it is queried. That is a gap, not a criticism of the feature itself.

Where Minuet is the wrong tool

The clearest limitation is the one the README states about its own speed. Completion through a language model is slower than completion through a language server, and the plugin's own documentation tells you to raise the nvim-cmp fetching timeout to compensate. If your workflow depends on suggestions appearing within the same keystroke, Minuet will feel like a different kind of tool, because it is one. The manual trigger exists precisely for this reason, and the README frames the timeout increase as unnecessary when you only need manual completion. That is a fair description of the trade: automatic triggering costs you latency, manual triggering costs you a keypress.

The second limitation is the network and key dependency. The README lists an API key for at least one supported provider under Requirements. If you point Minuet at a hosted provider, your code context is leaving your machine, and if the provider is unreachable the completion path is unreachable. The local options, Ollama and llama.cpp, remove that dependency but move the cost to your hardware and to model quality at the size you can run. The README's own local examples use Qwen-2.5-coder at 7b and 1.5b, which are small models; nothing in the material claims they match hosted models on completion quality.

The third limitation is version floor. Neovim 0.10 or newer is required, and the builtin completion frontend raises that to 0.11 or newer. If you are on an older Neovim, this plugin is not an option regardless of how well the rest of it fits.

Finally, the licence is GPL-3.0. That is a copyleft licence, and how it interacts with your own configuration and distribution is a question for someone qualified to answer it, not something to settle from a README. If you vendor the plugin into a distributed Neovim configuration, that is worth checking before you ship.

What Minuet is not doing, compared with a local completion engine

The natural comparison is with a local, index-based completion engine rather than with another LLM plugin, because the difference in approach is structural rather than a matter of provider support.

A local engine builds an index of your project and answers from it. It has no API key, no per-request cost, no network dependency, and its latency is bounded by your disk and CPU rather than by a model's forward pass. Its suggestions are drawn from code that already exists in your repository or its dependencies, which means it will not invent an API that does not exist, but it also means it cannot propose an idiom you have never written before. Minuet inverts each of those properties. It sends a prompt built from your buffer context to a model and streams the answer back, which is why the README lists streaming support as a feature and why it can suggest code that has no precedent in your project. The cost is latency, a key or a local server, and the possibility of a plausible-looking suggestion that does not compile.

That inversion is the whole reason to choose Minuet. If your complaint with existing completion is that it only ever repeats what is already in the codebase, a model-backed source addresses that complaint directly. If your complaint is that completion is too slow or too unpredictable, Minuet is likely to make it worse rather than better, and the README's own timeout guidance is the evidence for that claim.

The provider abstraction is the other differentiator, and it is worth being precise about it. Minuet separates chat-based prompting from FIM, and it separates OpenAI-compatible from OpenAI-FIM-compatible endpoints, with a documented path for APIs that are neither. That means the same plugin can front a hosted frontier model, a mid-tier hosted coder model, or a model running on your own machine through Ollama or llama.cpp, and you can switch between them with Minuet change_provider and Minuet change_model without reinstalling anything. Whether that flexibility is worth the setup cost depends on whether you actually intend to switch, or whether you will pick one provider on day one and never touch it again.

Maintenance, upgrades and what to check before you commit

The release cadence visible in the material is roughly quarterly: v0.8.0 in December 2025, v0.9.0 in April 2026, v0.10.0 in July 2026, with the last push to the default branch in August 2026. That is a plugin under active development, and the changelog history shows that the internals move. The removal of the plenary.nvim dependency in favour of vim.system is the concrete example: a change like that can alter your minimum Neovim version, and it did, to 0.10. Upgrading across a minor release is therefore worth doing with the release notes open rather than by pulling the latest commit and hoping.

Upgrade cost is otherwise low. There is no compiled artifact to rebuild and no background service to restart, because the plugin shells out through vim.system and curl. Your configuration is a Lua table, and the provider, model and preset switches are runtime commands, so changing backends does not require editing files and reloading. The thing to keep an eye on is the experimental surface: Duet has its own config block, its own events and a TODO list in the documentation, which means its configuration keys are the most likely to move between releases. If you build keymaps or statusline integrations on Duet events, expect to revisit them.

On licensing, GPL-3.0 is the stated licence. The practical implication for most users is nil, since you are running the plugin rather than distributing it. The case that deserves a second look is a shared or distributed Neovim configuration that includes the plugin source. That is a question for a lawyer, not for this article, and the repository's licence file is the document that governs it.

Editorial conclusion

Adopt Minuet if you already pay for a hosted model or run Ollama or llama.cpp locally and want completions that never leave your terminal, and if you are willing to tune the fetching timeout because LLM latency sits well above what nvim-cmp expects. Do not adopt it if you need a completion path with no network dependency or no API key, or if you want next-edit prediction that behaves predictably: the README labels Duet highly experimental. Before committing, verify three things in your own setup: that Neovim is 0.10 or newer, that your chosen provider is listed under the Providers section with the request shape you intend to use (chat prefix-first or FIM), and that your prompt and provider combination returns something usable at your typing speed.

Official sources

  1. Issues
  2. License: GPL-3.0
  3. milanglacier/minuet-ai.nvim on GitHub
  4. README
  5. Releases
Community notes

Community notes