A Neovim plugin that uses LLMs to improve the grammar and spelling of natural language text.
Show errors and suggestions as inlay hints

or in a scratch buffer.

This plugin uses curl.
Examples:
MiniDeps.later(function()
MiniDeps.add {
source = "bennorichters/taal.nvim",
depends = { "nvim-lua/plenary.nvim" },
}
require("taal").setup()
vim.keymap.set("n", "<leader>tg", "<Cmd>TaalGrammar scratch<Cr>")
vim.keymap.set("n", "<leader>tl", "<Cmd>TaalGrammar inlay<Cr>")
vim.keymap.set("n", "<leader>tr", "<Cmd>TaalGrammar<Cr>")
vim.keymap.set("n", "<leader>th", "<Cmd>TaalHover<Cr>")
vim.keymap.set("n", "<leader>ta", "<Cmd>TaalApplySuggestion<Cr>")
vim.keymap.set("n", "<leader>ts", "<Cmd>TaalSetSpelllang<Cr>")
vim.keymap.set("v", "<leader>ti", "<Cmd>TaalInteract<Cr>")
end)
{
"bennorichters/taal.nvim",
dependencies = { "nvim-lua/plenary.nvim" },
keys = {
{ "<leader>tg", "<cmd>TaalGrammar<cr>" },
{ "<leader>tl", "<Cmd>TaalGrammar inlay<Cr>" },
{ "<leader>tr", "<Cmd>TaalGrammar<Cr>" },
{ "<leader>th", "<Cmd>TaalHover<Cr>" },
{ "<leader>ta", "<Cmd>TaalApplySuggestion<Cr>" },
{ "<leader>ts", "<Cmd>TaalSetSpelllang<Cr>" },
{ "<leader>ti", "<Cmd>TaalInteract<Cr>", mode = "v" },
},
opts = {},
},
The LLMs need an API key. These keys should be made available via an environment variable:
{{CLAUDE_API_KEY}}{{GEMINI_API_KEY}}{{OPENAI_API_KEY}}(If you want to use Claude or OpenAI_responses instead of the default Gemini, do not forget to configure the plugin accordingly, see below.)
This plugin needs to be set up with require("taal").setup({}). The setup arg {} is optional and can be a custom config table, to overwrite the defaults. Calling the setup function, with or without a table, is mandatory.
{
log_level = "error", -- one of: trace, debug, info, warn, error, fatal
timeout = 6000, -- time out for API requests to LLM in ms
adapters = {
claude = {
-- URL for Claude
url = "https://api.anthropic.com",
},
gemini = {
-- URL for Gemini
url = "https://generativelanguage.googleapis.com"
},
openai_responses = {
-- URL for Openai_responses
url = "https://api.openai.com",
},
},
-- default LLM and model, used by all commands if not overriden by one
-- of the options below
adapter = "gemini", -- one of: claude, gemini, openai_responses
model = "gemini-2.5-flash",
commands = {
grammar = {
adapter = nil, -- overrides default LLM for TaalGrammar
model = nil, -- overrides default model for TaalGrammar
},
setspelllang = {
adapter = nil, -- overrides default LLM for TaalSetSpelllang
model = nil, -- overrides default model for TaalSetSpelllang
},
interact = {
adapter = nil, -- overrides default LLM for TaalInteract
model = nil, -- overrides default model for TaalInteract
},
},
}
This example uses Gemini and the model gemini-2.5-flash as the default LLM (because this config does not override the default), except for the interact command. For that command it will use Claude with the model claude-sonnet-4-5-20250929.
require("taal").setup({
commands = {
interact = {
adapter="claude", model="claude-sonnet-4-5-20250929",
}
}
})
The following five commands are exposed:
TaalGrammarTaalHoverTaalApplySuggestionTaalSetSpelllangTaalInteract:TaalInteract as using the colon will switch Neovim back to normal mode. Map this command to a key using <Cmd>TaalInteract<Cr> instead, as in the example below.No default key mapping is provided. Here is an example mapping you can use.
vim.keymap.set("n", "<leader>tg", "<Cmd>TaalGrammar scratch<Cr>")
vim.keymap.set("n", "<leader>tl", "<Cmd>TaalGrammar inlay<Cr>")
vim.keymap.set("n", "<leader>tr", "<Cmd>TaalGrammar<Cr>")
vim.keymap.set("n", "<leader>th", "<Cmd>TaalHover<Cr>")
vim.keymap.set("n", "<leader>ta", "<Cmd>TaalApplySuggestion<Cr>")
vim.keymap.set("n", "<leader>ts", "<Cmd>TaalSetSpelllang<Cr>")
-- Note that this mapping is for Visual Mode
vim.keymap.set("v", "<leader>ti", "<Cmd>TaalInteract<Cr>")