by nickjvandyke
Bridge Neovim and OpenCode AI to stay in your flow.
# Add to your Claude Code skills
git clone https://github.com/nickjvandyke/opencode.nvimGuides for using ai agents skills like opencode.nvim.
Last scanned: 4/21/2026
{
"issues": [],
"status": "PASSED",
"scannedAt": "2026-04-21T06:04:13.889Z",
"semgrepRan": false,
"npmAuditRan": true,
"pipAuditRan": true
}No comments yet. Be the first to share your thoughts!
30 days in the Featured rail · terms & refunds
Bridge Neovim and OpenCode AI to stay in your flow.
https://github.com/user-attachments/assets/e85e021c-fa8f-466e-830c-c667b28f611e
Like what you see? Check out my config.
vim.pack (recommended)
vim.pack.add({
{
src = "https://github.com/nickjvandyke/opencode.nvim",
version = vim.version.range("*"), -- Latest stable release
},
})
---@type opencode.Opts
vim.g.opencode_opts = {
-- Your configuration, if any; goto definition on the type for details
}
vim.o.autoread = true -- Required for `vim.g.opencode_opts.events.reload`
-- Recommended/example keymaps
vim.keymap.set({ "n", "x" }, "<leader>oa", function() require("opencode").ask("@this: ") end, { desc = "Ask opencode…" })
vim.keymap.set({ "n", "x" }, "<leader>os", function() require("opencode").select() end, { desc = "Select 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" })
{
"nickjvandyke/opencode.nvim",
version = "*", -- Latest stable release
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 `vim.g.opencode_opts.events.reload`
-- Recommended/example keymaps
vim.keymap.set({ "n", "x" }, "<leader>oa", function() require("opencode").ask("@this: ") end, { desc = "Ask opencode…" })
vim.keymap.set({ "n", "x" }, "<leader>os", function() require("opencode").select() end, { desc = "Select 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" })
end,
}
programs.nixvim = {
extraPlugins = [
pkgs.vimPlugins.opencode-nvim
];
};
[!TIP] Run
:checkhealth opencodeafter setup.
require("snacks").setup({
input = {
enabled = true, -- Enhances `ask()`
},
picker = {
enabled = true, -- Enhances `select()`
actions = {
---@param picker snacks.Picker
opencode_send = function(picker)
local items = vim.tbl_map(function(item) ---@param item snacks.picker.Item
return item.file
and require("opencode").format({ path = item.file, from = item.pos, to = item.end_pos })
or item.text
end, picker:selected({ fallback = true }))
require("opencode").prompt(table.concat(items, ", ") .. " ")
end,
},
win = {
input = {
keys = {
["<a-a>"] = { "opencode_send", mode = { "n", "i" } },
},
},
},
},
})
require("lualine").setup({
sections = {
lualine_z = {
{
-- Shows the currently connected server and its status
require("opencode").statusline,
},
}
}
})
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 |
Range or selection if any, else cursor position |
@buffer |
Current buffer |
@buffers |
Open buffers |
@visible |
Visible text |
@diagnostic |
Diagnostics within the range or selection if any, else under the cursor |
@diagnostics |
Current buffer diagnostics |
@quickfix |
Quickfix list |
@diff |
Git diff |
@marks |
Global marks |
[!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 |
Run local opencodes however you like and opencode.nvim will find them! Or point vim.g.opencode_opts.server.url to a specific server, including remotes.
[!IMPORTANT] You must run
opencodewith the--portflag to expose its server.
If opencode.nvim can't find an existing opencode, it starts one for you via vim.g.opencode_opts.server.start, defaulting to term://opencode --port.
local opencode_cmd = 'opencode --port'
---@type snacks.terminal.Opts
local snacks_terminal_opts = {
win = {
position = 'right',
enter = false,
},
}
---@type opencode.Opts
vim.g.opencode_opts = {
server = {
start = function()
require('snacks.terminal').open(opencode_cmd, snacks_terminal_opts)
end,
},
}
-- Can also leverage toggle functionality.
-- Avoid <leader> here — Neovim watches for keymaps in terminal mode, so your leader key will have input delay.
vim.keymap.set({ 'n', 't' }, '<C-.>', function()
require('snacks.terminal').toggle(opencode_cmd, snacks_terminal_opts)
end, { desc = 'Toggle opencode' })
-- Optionally show upon submitting prompt
vim.api.nvim_create_autocmd('User', {
pattern = { 'OpencodeEvent:tui.command.execute' },
callback = function(args)
---@type opencode.server.Event
local event = args.data.event
if event.properties.command == 'prompt.submit' then
local win = require('snacks.terminal').get(opencode_cmd, { create = false })
if win then
win:show()
end
end
end,
})
require("opencode").ask()Input a prompt for opencode.
<Up> to browse recent asks.opencode subagents.
<Tab> to trigger built-in completion.snacks.input.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 |