Integrate the opencode AI assistant with Neovim — streamline editor-aware research, reviews, and requests.
demo.mp4
- Auto-connects to any
opencoderunning inside Neovim's CWD, or provides an integrated instance. - Input prompts with completions, highlights, and normal-mode support.
- Select prompts from a library and define your own.
- Inject relevant editor context (buffer, cursor, selection, diagnostics, etc.).
- Control
opencodewith commands. - Respond to
opencodepermission requests. - Monitor state via statusline component.
- Auto-reloads buffers edited by
opencodein real-time. - Forwards
opencode's Server-Sent-Events as autocmds for automation. - Sensible defaults with well-documented, flexible configuration and API to fit your workflow.
Tip
Run :checkhealth opencode after setup.
{
"NickvanDyke/opencode.nvim",
dependencies = {
-- Recommended for `ask()` and `select()`.
-- Required for `snacks` provider.
---@module 'snacks' <- Loads `snacks.nvim` types for configuration intellisense.
{ "folke/snacks.nvim", opts = { input = {}, picker = {}, terminal = {} } },
},
config = function()
---@type opencode.Opts
vim.g.opencode_opts = {
-- Your configuration, if any — see `lua/opencode/config.lua`, or "goto definition".
}
-- Required for `opts.auto_reload`.
vim.o.autoread = true
-- Recommended/example keymaps.
vim.keymap.set({ "n", "x" }, "<C-a>", function() require("opencode").ask("@this: ", { submit = true }) end, { desc = "Ask opencode" })
vim.keymap.set({ "n", "x" }, "<C-x>", function() require("opencode").select() end, { desc = "Execute opencode action…" })
vim.keymap.set({ "n", "x" }, "ga", function() require("opencode").prompt("@this") end, { desc = "Add to opencode" })
vim.keymap.set({ "n", "t" }, "<C-.>", function() require("opencode").toggle() end, { desc = "Toggle opencode" })
vim.keymap.set("n", "<S-C-u>", function() require("opencode").command("session.half.page.up") end, { desc = "opencode half page up" })
vim.keymap.set("n", "<S-C-d>", function() require("opencode").command("session.half.page.down") end, { desc = "opencode half page down" })
-- You may want these if you stick with the opinionated "<C-a>" and "<C-x>" above — otherwise consider "<leader>o".
vim.keymap.set('n', '+', '<C-a>', { desc = 'Increment', noremap = true })
vim.keymap.set('n', '-', '<C-x>', { desc = 'Decrement', noremap = true })
end,
}programs.nixvim = {
extraPlugins = [
pkgs.vimPlugins.opencode-nvim
];
};opencode.nvim provides a rich and reliable default experience — see all available options and their defaults here.
You can manually run opencode inside Neovim's CWD however you like and opencode.nvim will find it!
If opencode.nvim can't find an existing opencode, it uses the configured provider (defaulting based on availability) to toggle, start, and show one when appropriate.
vim.g.opencode_opts = {
provider = {
enabled = "snacks", -- Default when `snacks.terminal` is enabled.
snacks = {
-- Customize `snacks.terminal` to your liking.
}
}
}vim.g.opencode_opts = {
provider = {
enabled = "tmux", -- Default when running inside a `tmux` session.
tmux = {
options = "-h", -- options to pass to `tmux split-window`
}
}
}Integrate your custom method for convenience!
vim.g.opencode_opts = {
provider = {
toggle = function(self)
-- ...
end,
start = function(self)
-- ...
end,
show = function(self)
-- ...
end
}
}Please submit PRs adding new providers! 🙂
Input a prompt to send to opencode.
- Press
<Up>to browse recent asks. - Highlights contexts and
opencodesubagents. - Completes contexts and
opencodesubagents.- Press
<Tab>to trigger built-in completion. - When using
blink.cmpandsnacks.input, registersopts.auto_register_cmp_sources.
- Press
Select from all opencode.nvim functionality.
- Fetches custom commands from
opencode.
Send a prompt to opencode.
Replaces placeholders in the prompt with the corresponding context:
| Placeholder | Context |
|---|---|
@this |
Visual selection if any, else cursor position |
@buffer |
Current buffer |
@buffers |
Open buffers |
@visible |
Visible text |
@diagnostics |
Current buffer diagnostics |
@quickfix |
Quickfix list |
@diff |
Git diff |
@grapple |
grapple.nvim tags |
Reference a prompt by name to review, explain, and improve your code:
| Name | Prompt |
|---|---|
ask |
... |
explain |
Explain @this and its context |
optimize |
Optimize @this for performance and readability |
document |
Add comments documenting @this |
test |
Add tests for @this |
review |
Review @this for correctness and readability |
diagnostics |
Explain @diagnostics |
fix |
Fix @diagnostics |
diff |
Review the following git diff for correctness and readability: @diff |
buffer |
@buffer |
this |
@this |
Send a command to opencode:
| Command | Description |
|---|---|
session.list |
List sessions |
session.new |
Start a new session |
session.share |
Share the current session |
session.interrupt |
Interrupt the current session |
session.compact |
Compact the current session (reduce context size) |
session.page.up |
Scroll messages up by one page |
session.page.down |
Scroll messages down by one page |
session.half.page.up |
Scroll messages up by half a page |
session.half.page.down |
Scroll messages down by half a page |
session.first |
Jump to the first message in the session |
session.last |
Jump to the last message in the session |
session.undo |
Undo the last action in the current session |
session.redo |
Redo the last undone action in the current session |
prompt.submit |
Submit the TUI input |
prompt.clear |
Clear the TUI input |
agent.cycle |
Cycle the selected agent |
opencode.nvim forwards opencode's Server-Sent-Events as an OpencodeEvent autocmd:
-- Listen for `opencode` events
vim.api.nvim_create_autocmd("User", {
pattern = "OpencodeEvent",
callback = function(args)
-- See the available event types and their properties
vim.notify(vim.inspect(args.data.event))
-- Do something useful
if args.data.event.type == "session.idle" then
vim.notify("`opencode` finished responding")
end
end,
})When opencode edits a file, opencode.nvim automatically reloads the corresponding buffer.
When opencode requests a permission, opencode.nvim waits for idle to ask you to approve or deny it.
require("lualine").setup({
sections = {
lualine_z = {
{
require("opencode").statusline,
},
}
}
})- Inspired by nvim-aider, neopencode.nvim, and sidekick.nvim.
- Uses
opencode's 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.