Send editor-aware prompts to the powerful opencode AI from Neovim.
demo.mp4
Note
Uses opencode's currently undocumented, likely unstable API.
Latest tested opencode version: v0.3.76
- Finds your
opencode
process running in or under Neovim's CWD - Sends prompts to its active session
- Injects customizable editor context
- Auto-reloads edited buffers
Please use the opencode TUI to manage its active session until the plugin can do so.
lazy.nvim
{
'NickvanDyke/opencode.nvim',
---@type opencode.Config
opts = {
-- Set these according to https://models.dev/
provider_id = ...,
model_id = ...,
},
-- stylua: ignore
keys = {
{ '<leader>oa', function() require('opencode').ask() end, desc = 'Ask opencode', mode = { 'n', 'v' }, },
{ '<leader>oA', function() require('opencode').ask('@file ') end, desc = 'Ask opencode about current file', mode = { 'n', 'v' }, },
{ '<leader>oe', function() require('opencode').prompt('Explain @cursor and its context') end, desc = 'Explain code near cursor' },
{ '<leader>or', function() require('opencode').prompt('Review @file for correctness and readability') end, desc = 'Review file', },
{ '<leader>of', function() require('opencode').prompt('Fix these @diagnostics') end, desc = 'Fix errors', },
{ '<leader>oo', function() require('opencode').prompt('Optimize @selection for performance and readability') end, desc = 'Optimize selection', mode = 'v', },
{ '<leader>od', function() require('opencode').prompt('Add documentation comments for @selection') end, desc = 'Document selection', mode = 'v', },
{ '<leader>ot', function() require('opencode').prompt('Add tests for @selection') end, desc = 'Test selection', mode = 'v', },
},
}
NixOS/nixvim
programs.nixvim = {
extraPlugins = [
pkgs.vimPlugins.opencode-nvim
];
keymaps = [
{ key = "<leader>oa"; action = "<cmd>lua require('opencode').ask()<CR>"; mode = ["n" "v"]; }
{ key = "<leader>oA"; action = "<cmd>lua require('opencode').ask('@file ')<CR>"; mode = ["n" "v"]; }
{ key = "<leader>oe"; action = "<cmd>lua require('opencode').prompt('Explain @cursor and its context')<CR>"; }
{ key = "<leader>or"; action = "<cmd>lua require('opencode').prompt('Review @file for correctness and readability')<CR>"; }
{ key = "<leader>of"; action = "<cmd>lua require('opencode').prompt('Fix these @diagnostics')<CR>"; }
{ key = "<leader>oo"; action = "<cmd>lua require('opencode').prompt('Optimize @selection for performance and readability')<CR>"; mode = "v"; }
{ key = "<leader>od"; action = "<cmd>lua require('opencode').prompt('Add documentation comments for @selection')<CR>"; mode = "v"; }
{ key = "<leader>ot"; action = "<cmd>lua require('opencode').prompt('Add tests for @selection')<CR>"; mode = "v"; }
];
};
Tip
opencode.nvim
offers a flexible API β customize keymaps to fit your workflow!
Default settings:
---@type opencode.Config
{
provider_id = "github-copilot", -- Provider to use for opencode requests
model_id = "gpt-4.1", -- Model to use for opencode requests
port = nil, -- The port opencode is running on β use `opencode --port <port>`. If `nil`, tries to find a running instance in or under Neovim's CWD.
auto_reload = false, -- Automatically reload buffers edited by opencode
context = { -- Context to inject in prompts
["@file"] = require("opencode.context").file,
["@files"] = require("opencode.context").files,
["@cursor"] = require("opencode.context").cursor_position,
["@selection"] = require("opencode.context").visual_selection,
["@diagnostics"] = require("opencode.context").diagnostics,
["@quickfix"] = require("opencode.context").quickfix,
["@diff"] = require("opencode.context").git_diff,
},
}
When your prompt contains placeholders, the plugin will replace it with context before sending:
Placeholder | Context |
---|---|
@file |
Current file |
@files |
Open files |
@cursor |
Cursor position |
@selection |
Selected text |
@diagnostics |
Current buffer diagnostics |
@quickfix |
Quickfix list |
@diff |
Git diff |
Add custom contexts via opts.context
. The below replaces @grapple
with files tracked by grapple.nvim:
---@type opencode.Config
{
context = {
---@return string|nil
['@grapple'] = function()
local tags = require('grapple').tags()
if not tags or #tags == 0 then
return nil
end
local paths = {}
for _, tag in ipairs(tags) do
table.insert(paths, tag.path)
end
return table.concat(paths, ', ')
end,
}
}
You can prompt opencode on Neovim events:
-- Prompt opencode to fix diagnostics whenever they change in the current buffer.
-- Kind of annoying and should at least debounce, but just to show what's possible.
vim.api.nvim_create_autocmd('DiagnosticChanged', {
callback = function(args)
local diagnostics = vim.diagnostic.get(args.buf)
if #diagnostics > 0 then
require('opencode').prompt('Fix these @diagnostics')
end
end,
})
opencode.nvim
calls any opencode
process running in or under Neovim's CWD, but you can easily embed it in Neovim using snacks.terminal
:
{
'NickvanDyke/opencode.nvim',
dependencies = { 'folke/snacks.nvim' },
keys = {
'<leader>ot', function() require('snacks.terminal').toggle('opencode', { win = { position = 'right' } }) end, desc = 'Toggle opencode' },
}
}
Important
Set your opencode theme to system
β other themes currently have visual bugs in embedded terminals.
- Inspired by (and partially based on) nvim-aider and later neopencode.nvim.
- This plugin uses opencode's familiar TUI for simplicity β see sudo-tee/opencode.nvim for a Neovim frontend.
- mcp-neovim-server may better suit you, but it lacks customization and tool calls are slow and unreliable.