Seamlessly integrate the opencode AI assistant with Neovim.
demo.mp4
Note
Uses opencode's currently undocumented, likely unstable API.
Latest tested opencode version: v0.3.110
- Toggle an embedded
opencodeterminal or auto-find anyopencodeprocess running inside Neovim's CWD - Send and input customizable prompts
- Inject customizable editor context
- Prompt quickly with completion integration
- Auto-reload edited buffers
When your prompt contains placeholders, the plugin will replace them with context before sending:
| Placeholder | Context |
|---|---|
@file |
Current file |
@files |
Open files |
@cursor |
Cursor position |
@selection |
Selected text |
@diagnostic |
Current line diagnostics |
@diagnostics |
Current buffer diagnostics |
@quickfix |
Quickfix list |
@diff |
Git diff |
lazy.nvim
{
'NickvanDyke/opencode.nvim',
dependencies = { 'folke/snacks.nvim', },
---@type opencode.Config
opts = {
-- Your configuration, if any
},
-- stylua: ignore
keys = {
{ '<leader>ot', function() require('opencode').toggle() end, desc = 'Toggle embedded opencode', },
{ '<leader>oa', function() require('opencode').ask() end, desc = 'Ask opencode', mode = 'n', },
{ '<leader>oa', function() require('opencode').ask('@selection: ') end, desc = 'Ask opencode about selection', mode = 'v', },
{ '<leader>op', function() require('opencode').select_prompt() end, desc = 'Select prompt', mode = { 'n', 'v', }, },
{ '<leader>on', function() require('opencode').command('session_new') end, desc = 'New session', },
{ '<leader>oy', function() require('opencode').command('messages_copy') end, desc = 'Copy last message', },
{ '<S-C-u>', function() require('opencode').command('messages_half_page_up') end, desc = 'Scroll messages up', },
{ '<S-C-d>', function() require('opencode').command('messages_half_page_down') end, desc = 'Scroll messages down', },
},
}nixvim
programs.nixvim = { extraPlugins = [ pkgs.vimPlugins.opencode-nvim ]; keymaps = [ { key = "<leader>ot"; action = "<cmd>lua require('opencode').toggle()<CR>"; } { key = "<leader>oa"; action = "<cmd>lua require('opencode').ask()<CR>"; mode = "n"; } { key = "<leader>oa"; action = "<cmd>lua require('opencode').ask('@selection: ')<CR>"; mode = "v"; } { key = "<leader>oe"; action = "<cmd>lua require('opencode').select_prompt()<CR>"; mode = ["n" "v"]; } { key = "<leader>on"; action = "<cmd>lua require('opencode').command('session_new')<CR>"; } ]; };
See all the available options and their defaults here.
Tip
opencode.nvim offers a flexible API β customize prompts, contexts, and keymaps to fit your workflow!
Add custom selectable prompts to opts.prompts:
{
prompts = {
joke = {
description = 'Tell me a cat joke',
prompt = 'Tell me a joke about cats. Make it funny, but not too funny.',
-- Map it to a key if you really like it!
key = '<leader>oj',
},
},
}Add keymaps to built-in prompts:
{
prompts = {
explain = {
key = '<leader>oe',
},
},
}Add custom contexts to opts.context. The below replaces @grapple with files tracked by grapple.nvim:
{
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,
}
}The plugin offers context placeholder completions in the ask input.
Add the following to your blink.cmp config:
{
sources = {
providers = {
opencode = {
module = 'opencode.cmp.blink',
},
},
per_filetype = {
opencode_ask = { 'opencode', 'buffer' },
},
},
}Press <Tab> to trigger Neovim's built-in completion.
- 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.