Refine is an AI grammar checker powered by a local language model, so it can run entirely offline. This plugin brings its contextual grammar and fluency suggestions to Neovim, helping you improve your writing without leaving your editor.
Features:
- Private, offline checks powered by a local LLM on your device
- Native highlights and floating cards for reviewing changes in context
- Clear explanations of why each change is suggested
- macOS 14+
- Neovim 0.11+
- Refine 1.35+
Refine is free to use for grammar and fluency checks, with no account or credit card required.
Install Refine with Homebrew:
brew install --cask refineYou can also download Refine for Mac directly.
Choose one of the following installation methods. No setup() call is
required.
Add refine.nvim to your lazy.nvim
plugin spec:
{
"refine-sh/refine.nvim",
}Alternatively, clone the plugin into Neovim's native package directory:
mkdir -p ~/.local/share/nvim/site/pack/refine/start
git clone --filter=blob:none https://github.com/refine-sh/refine.nvim \
~/.local/share/nvim/site/pack/refine/start/refine.nvimRestart Neovim if it was already open, then open a supported prose buffer while Refine is running. Automatic Checks are enabled by default, so suggestions appear after you pause while editing.
Use :RefineCheck whenever you want an immediate manual check. An explicit
check can launch Refine in the background without stealing focus. Passive
buffer activity never launches the app.
The plugin installs no permanent key mappings. These mappings cover the common review workflow:
vim.keymap.set({ "n", "x" }, "<leader>rc", "<Plug>(RefineCheck)")
vim.keymap.set("n", "<leader>rs", "<Plug>(RefineShow)")
vim.keymap.set("n", "]r", "<Plug>(RefineNext)")
vim.keymap.set("n", "[r", "<Plug>(RefinePrevious)")
vim.keymap.set("n", "<leader>ra", "<Plug>(RefineApply)")Record custom Apply and Dismiss combinations in Refine's Shortcuts settings, such as Option+Right Arrow or Control+Option+K. Combinations are synchronized when both Refine and this plugin support them; older versions keep the previous single-key bindings shown in Refine. Command combinations require Neovide; terminal frontends and ambiguous control-key aliases may be unavailable.
Refine also records held modifier combinations and modifier double-taps. These gestures cannot be observed through Neovim's input path, so the plugin displays an unavailable message and installs no fallback mapping. Use the existing Refine commands or explicit action mappings instead.
When the configured Apply key cannot be intercepted by Neovim, the activation
tip says Apply shortcut unavailable. The card explains how to configure
another Apply key in Refine or add the Neovim mapping above. Refine does not
remap the key automatically.
The Check mapping supports Normal and Visual mode. Characterwise and linewise Visual selections preserve their exact endpoints. Blockwise selections are not supported.
See Advanced configuration for every
available <Plug> target and card mapping.
| Command | Action |
|---|---|
:[range]RefineCheck |
Check the buffer or the complete sentences touched by a line range. |
:RefineShow |
Open and focus the suggestion under the cursor, or focus its open preview. |
:RefineNext / :RefinePrevious |
Move through suggestions, opening and focusing each card. Navigation wraps. |
:RefineApply |
Apply the open suggestion, or the suggestion under the cursor. |
:RefineDismiss |
Dismiss the open suggestion, or the suggestion under the cursor. |
:RefineExplain |
Request an explanation for the current suggestion. |
:RefineReport |
Send feedback about the current suggestion when available. |
:RefineClose |
Close the card without applying or dismissing the suggestion. |
:RefineStatus |
Show the current integration state. |
A plain click on an underlined suggestion also opens and focuses its card.
Every card opens focused, so a, d, e, r, and q act immediately; the
cursor stays on the suggestion and closing the card returns focus to it.
Refine can show check progress in your statusline. It never rewrites
'statusline' for you, so add its component to your own.
Put this in your Neovim config, usually ~/.config/nvim/init.lua:
vim.o.statusline = "%f %m%r%=%{v:lua.require'refine'.statusline()} %l:%c"That is a complete statusline showing the file name, the Refine component, and
the cursor position. If you already have a statusline you like, copy just the
%{v:lua.require'refine'.statusline()} part into it.
Using lualine? Add it as a component instead:
require("lualine").setup({
sections = {
lualine_x = {
{ function() return require("refine").statusline() end },
"encoding", "fileformat", "filetype",
},
},
})Open a Markdown or text file and type a sentence. As Refine checks it, the component moves through these states:
| Text | Meaning |
|---|---|
Refine … |
Connecting to Refine. |
Refine 3/7 |
Checking, showing progress reported by Refine. |
Refine 5 |
Check complete, with the number of suggestions. |
Refine ! |
Refine is unavailable. |
Refine · |
Waiting for the next check. |
The component is intentionally empty in any buffer Refine is not checking, so an unsupported filetype shows nothing at all. If it stays empty, or you want custom wording and icons instead of this text, see Advanced configuration.
Markdown, plain text, Git commit messages, email, TeX, and LaTeX are enabled by default. You can add another Neovim filetype or disable a default through advanced configuration.
Only ordinary, editable, valid UTF-8 buffers within the configured size limit are eligible. Refine never changes file format or end-of-line settings.
The plugin sends a complete canonical snapshot of each eligible buffer to the local Refine app. When Refine uses a downloaded local model, that source and the model response stay on your Mac. Once downloaded, the model continues working offline.
Refine can also use a provider you connect. Those requests go directly from your Mac to that provider and may include the source, so that provider's terms and privacy practices apply. Downloads, updates, optional license services, and hosted providers still require an internet connection.
The Neovim plugin connects only to the local Refine app through a same-UID Unix-domain socket using Refine's current per-launch token. This boundary excludes network clients and other OS users, but it does not identify a specific plugin or protect against another process already running as you. The plugin makes no direct network, telemetry, analytics, or update-check requests. Persistent diagnostics are off by default; when enabled for troubleshooting, they retain only bounded, redacted metadata and never source, diffs, explanations, launch tokens, or provider credentials.
:RefineReport is a separate, explicit feedback action. Only when you invoke
it, the Refine app may send original and revised excerpts plus suggestion,
model, language, custom-instruction, Refine-version, and macOS-version context
to Refine's feedback service.
Read How Refine works, the offline grammar checker guide, and the privacy policy for full details.
Integration Protocol 1.0 is a supported public API that third-party writing-host clients may implement. Refine for Neovim requires the exact 1.0 wire contract. Refine maintains exact Protocol 1.0 compatibility throughout the Refine 1.x release line.
The supported production profile connects a conforming writing-host client to the shipping Refine server on the same Mac and as the same OS user, with Refine already running. Network transports, cross-user access, and third-party production servers are outside that profile. Technical conformance is self-assessed and does not imply certification or endorsement.
A protocol mismatch stops before source is sent and reports the exact local and remote versions. Because version ordering does not identify which component should change, the diagnostic asks for a compatible app-and-plugin pair without inferring an update direction.
Run the built-in health check:
:checkhealth refineIt checks the Neovim version and macOS platform, plugin configuration, local endpoint permissions, protocol compatibility, frontend detection, action-key support, integration state, and the optional debug-log path.
:RefineStatus provides a shorter view of the current buffer state. If no
suggestions appear, first confirm that Refine is running, Automatic Checks are
enabled, and the current filetype is supported.
- Advanced configuration covers filetypes, buffer overrides, mappings, statusline integration, frontend detection, and diagnostics.
:help refineis the complete public interface reference.- Contributing covers development setup, tests, module boundaries, and documentation synchronization.
- Changelog records user-visible changes.