by nickjvandyke
Integrate Neovim and OpenCode AI to stay in your flow.
# Add to your Claude Code skills
git clone https://github.com/nickjvandyke/opencode.nvimLast scanned: 4/21/2026
{
"issues": [],
"status": "PASSED",
"scannedAt": "2026-04-21T06:04:13.889Z",
"semgrepRan": false,
"npmAuditRan": true,
"pipAuditRan": true
}https://github.com/user-attachments/assets/077daa78-d401-4b8b-98d1-9ba9f94c2330
opencode, or provide an integrated instanceopencode via an in-process LSP{
"nickjvandyke/opencode.nvim",
version = "*", -- Latest stable release
dependencies = {
{
-- `snacks.nvim` integration is recommended, but optional
---@module "snacks" <- Loads `snacks.nvim` types for configuration intellisense
"folke/snacks.nvim",
optional = true,
opts = {
input = {}, -- Enhances `ask()`
picker = { -- Enhances `select()`
actions = {
opencode_send = function(...) return require("opencode").snacks_picker_send(...) end,
},
win = {
input = {
keys = {
["<a-a>"] = { "opencode_send", mode = { "n", "i" } },
},
},
},
},
},
},
},
config = function()
---@type opencode.Opts
vim.g.opencode_opts = {
-- Your configuration, if any; goto definition on the type or field for details
}
vim.o.autoread = true -- Required for `opts.events.reload`
-- 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", "t" }, "<C-.>", function() require("opencode").toggle() end, { desc = "Toggle opencode" })
vim.keymap.set({ "n", "x" }, "go", function() return require("opencode").operator("@this ") end, { desc = "Add range to opencode", expr = true })
vim.keymap.set("n", "goo", function() return require("opencode").operator("@this ") .. "_" end, { desc = "Add line to opencode", expr = true })
vim.keymap.set("n", "<S-C-u>", function() require("opencode").command("session.half.page.up") end, { desc = "Scroll opencode up" })
vim.keymap.set("n", "<S-C-d>", function() require("opencode").command("session.half.page.down") end, { desc = "Scroll opencode down" })
-- You may want these if you use the opinionated `<C-a>` and `<C-x>` keymaps above — otherwise consider `<leader>o…` (and remove terminal mode from the `toggle` keymap)
vim.keymap.set("n", "+", "<C-a>", { desc = "Increment under cursor", noremap = true })
vim.keymap.set("n", "-", "<C-x>", { desc = "Decrement under cursor", noremap = true })
end,
}
No comments yet. Be the first to share your thoughts!
programs.nixvim = {
extraPlugins = [
pkgs.vimPlugins.opencode-nvim
];
};
[!TIP] Run
:checkhealth opencodeafter setup.
opencode.nvim provides a rich and reliable default experience — see all available options and their defaults here.
opencode.nvim replaces placeholders in prompts with the corresponding context:
| Placeholder | Context |
| -------------- | --------------------------------------------------------------- |
| @this | Operator range or 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 |
| @marks | Global marks |
| @grapple | grapple.nvim tags |
[!TIP]
opencodereads referenced files from disk — save your changes!
Select prompts to review, explain, and improve your code:
| Name | Prompt |
| ------------- | ---------------------------------------------------------------------- |
| diagnostics | Explain @diagnostics |
| diff | Review the following git diff for correctness and readability: @diff |
| document | Add comments documenting @this |
| explain | Explain @this and its context |
| fix | Fix @diagnostics |
| implement | Implement @this |
| optimize | Optimize @this for performance and readability |
| review | Review @this for correctness and readability |
| test | Add tests for @this |
You can manually run opencodes however you like and opencode.nvim will find them!
[!IMPORTANT] You must run
opencodewith the--portflag to expose its server.
If opencode.nvim can't find an existing opencode, it uses the configured server to start one for you, defaulting to an embedded terminal.
opencode.nvim sets these normal-mode keymaps in the embedded terminal for Neovim-like message navigation:
| Keymap | Command | Description |
| ------- | ------------------------ | --------------------- |
| <C-u> | session.half.page.up | Scroll up half page |
| <C-d> | session.half.page.down | Scroll down half page |
| gg | session.first | Go to first message |
| G | session.last | Go to last message |
| <Esc> | session.interrupt | Interrupt |
Example using snacks.terminal instead:
local opencode_cmd = 'opencode --port'
---@type snacks.terminal.Opts
local snacks_terminal_opts = {
win = {
position = 'right',
enter = false,
on_win = function(win)
-- Set up keymaps and cleanup for an arbitrary terminal
require('opencode.terminal').setup(win.win)
end,
},
}
---@type opencode.Opts
vim.g.opencode_opts = {
server = {
start = function()
require('snacks.terminal').open(opencode_cmd, snacks_terminal_opts)
end,
stop = function()
require('snacks.terminal').get(opencode_cmd, snacks_terminal_opts):close()
end,
toggle = function()
require('snacks.terminal').toggle(opencode_cmd, snacks_terminal_opts)
end,
},
}
require("opencode").ask()Input a prompt for opencode.
<Up> to browse recent asks.opencode subagents.
<Tab> to trigger built-in completion.snacks.input, offers completions via in-process LSP.require("opencode").select()Select from all opencode.nvim functionality.
Highlights and previews items when using snacks.picker.
require("opencode").prompt()Prompt opencode.
opencode will interpret references to files or subagents.require("opencode").operator()Wraps prompt as an operator, supporting ranges and dot-repeat.
require("opencode").command()Command opencode:
| Command | Description |
| ------------------------ | -------------------------------------------------- |
| session.list | List sessions |
| session.new | Start a new session |
| session.select | Select a 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 |
[!WARNING] This feature is experimental! Try it out with
vim.g.opencode_opts.lsp.enabled = true.
opencode.nvim provides an in-process LSP to interact