https://github.com/nickjvandyke/opencode.nvim
Integrate the opencode AI assistant with Neovim — streamline editor-aware research, reviews, and requests.
https://github.com/nickjvandyke/opencode.nvim
ai ai-agents ai-assistant neovim neovim-plugin nvim opencode plugin terminal
Last synced: 2 days ago
JSON representation
Integrate the opencode AI assistant with Neovim — streamline editor-aware research, reviews, and requests.
- Host: GitHub
- URL: https://github.com/nickjvandyke/opencode.nvim
- Owner: nickjvandyke
- License: mit
- Created: 2025-07-12T13:52:17.000Z (8 months ago)
- Default Branch: main
- Last Pushed: 2026-02-06T22:43:12.000Z (16 days ago)
- Last Synced: 2026-02-07T01:20:25.358Z (16 days ago)
- Topics: ai, ai-agents, ai-assistant, neovim, neovim-plugin, nvim, opencode, plugin, terminal
- Language: Lua
- Homepage:
- Size: 522 KB
- Stars: 2,410
- Watchers: 6
- Forks: 82
- Open Issues: 16
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- Funding: .github/FUNDING.yml
- License: LICENSE
- Code of conduct: CODE_OF_CONDUCT.md
Awesome Lists containing this project
- awesome-neovim-sorted - nickjvandyke/opencode.nvim - aware research, reviews, and requests. | (AI)
- awesome-ai-agents - nickjvandyke/opencode.nvim - opencode.nvim integrates the opencode AI assistant into Neovim to provide context-aware code research, reviews, and requests directly within the editor. (Autonomous Research & Content Generation / AI Assistants)
- awesome-neovim - nickjvandyke/opencode.nvim - OpenCode AI assistant integration. (AI / Diagnostics)
- awesome-cli-agents - nickjvandyke/opencode.nvim - Integrate the opencode AI assistant with Neovim — streamline editor-aware research, reviews, and requests. [Vim/Neovim] (2k⭐) (🚀 AI Tools for Vim, Neovim, and Terminal)
- awesome-ccamel - nickjvandyke/opencode.nvim - Integrate the opencode AI assistant with Neovim — streamline editor-aware research, reviews, and requests. (Lua)
README
# opencode.nvim
Integrate the [opencode](https://github.com/sst/opencode) AI assistant with Neovim — streamline editor-aware research, reviews, and requests.
## ✨ Features
- Connect to _any_ `opencode`s running in Neovim's CWD, or provide an integrated instance.
- Share editor context (buffer, cursor, selection, diagnostics, etc.).
- Input prompts with completions, highlights, and normal-mode support.
- Select prompts from a library and define your own.
- Execute commands.
- Respond to permission requests.
- Reload edited buffers in real-time.
- Monitor state via statusline component.
- Forward Server-Sent-Events as autocmds for automation.
- Sensible defaults with well-documented, flexible configuration and API to fit your workflow.
- _Vim-y_ — supports ranges and dot-repeat.
## 📦 Setup
### [lazy.nvim](https://github.com/folke/lazy.nvim)
```lua
{
"nickjvandyke/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" on the type or field.
}
-- Required for `opts.events.reload`.
vim.o.autoread = true
-- Recommended/example keymaps.
vim.keymap.set({ "n", "x" }, "", function() require("opencode").ask("@this: ", { submit = true }) end, { desc = "Ask opencode…" })
vim.keymap.set({ "n", "x" }, "", function() require("opencode").select() end, { desc = "Execute opencode action…" })
vim.keymap.set({ "n", "t" }, "", 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", "", function() require("opencode").command("session.half.page.up") end, { desc = "Scroll opencode up" })
vim.keymap.set("n", "", function() require("opencode").command("session.half.page.down") end, { desc = "Scroll opencode down" })
-- You may want these if you use the opinionated `` and `` keymaps above — otherwise consider `o…` (and remove terminal mode from the `toggle` keymap).
vim.keymap.set("n", "+", "", { desc = "Increment under cursor", noremap = true })
vim.keymap.set("n", "-", "", { desc = "Decrement under cursor", noremap = true })
end,
}
```
### [nixvim](https://github.com/nix-community/nixvim)
```nix
programs.nixvim = {
extraPlugins = [
pkgs.vimPlugins.opencode-nvim
];
};
```
> [!TIP]
> Run `:checkhealth opencode` after setup.
## ⚙️ Configuration
`opencode.nvim` provides a rich and reliable default experience — see all available options and their defaults [here](./lua/opencode/config.lua).
### Contexts
`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](https://github.com/cbochs/grapple.nvim) tags |
### Prompts
Select or reference 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` |
### Provider
You can manually run `opencode`s in Neovim's CWD however you like and `opencode.nvim` will find them!
If `opencode.nvim` can't find an existing `opencode`, it uses the configured provider (defaulting based on availability) to manage one for you.
> [!IMPORTANT]
> You _must_ run `opencode` with the `--port` flag to expose its server. Providers do so by default.
```lua
vim.g.opencode_opts = {
provider = {
enabled = "terminal",
terminal = {
-- ...
}
}
}
```
```lua
vim.g.opencode_opts = {
provider = {
enabled = "snacks",
snacks = {
-- ...
}
}
}
```
```lua
vim.g.opencode_opts = {
provider = {
enabled = "kitty",
kitty = {
-- ...
}
}
}
```
The kitty provider requires [remote control via a socket](https://sw.kovidgoyal.net/kitty/remote-control/#remote-control-via-a-socket) to be enabled.
You can do this either by running Kitty with the following command:
```bash
# For Linux only:
kitty -o allow_remote_control=yes --single-instance --listen-on unix:@mykitty
# Other UNIX systems:
kitty -o allow_remote_control=yes --single-instance --listen-on unix:/tmp/mykitty
```
OR, by adding the following to your `kitty.conf`:
```
# For Linux only:
allow_remote_control yes
listen_on unix:@mykitty
# Other UNIX systems:
allow_remote_control yes
listen_on unix:/tmp/kitty
```
```lua
vim.g.opencode_opts = {
provider = {
enabled = "wezterm",
wezterm = {
-- ...
}
}
}
```
```lua
vim.g.opencode_opts = {
provider = {
enabled = "tmux",
tmux = {
-- ...
}
}
}
```
custom
Integrate your custom method for convenience!
```lua
vim.g.opencode_opts = {
provider = {
toggle = function(self)
-- ...
end,
start = function(self)
-- ...
end,
stop = function(self)
-- ...
end,
}
}
```
Please submit PRs adding new providers! 🙂
#### Keymaps
`opencode.nvim` sets these buffer-local keymaps in provider terminals for Neovim-like message navigation:
| Keymap | Command | Description |
| ------- | ------------------------ | ---------------------------- |
| `` | `session.half.page.up` | Scroll up half page |
| `` | `session.half.page.down` | Scroll down half page |
| `` | `session.interrupt` | Interrupt |
| `gg` | `session.first` | Go to first message |
| `G` | `session.last` | Go to last message |
## 🚀 Usage
### ✍️ Ask — `require("opencode").ask()`
Input a prompt for `opencode`.
- Press `` to browse recent asks.
- Highlights and completes contexts and `opencode` subagents.
- Press `` to trigger built-in completion.
- Registers `opts.ask.blink_cmp_sources` when using `snacks.input` and `blink.cmp`.
### 📝 Select — `require("opencode").select()`
Select from all `opencode.nvim` functionality.
- Prompts
- Commands
- Fetches custom commands from `opencode`
- Provider controls
Highlights and previews items when using `snacks.picker`.
### 🗣️ Prompt — `require("opencode").prompt()`
Prompt `opencode`.
- Resolves named references to configured prompts.
- Injects configured contexts.
- `opencode` will interpret `@` references to files or subagents.
### 🧑🔬 Operator — `require("opencode").operator()`
Wraps `prompt` as an operator, supporting ranges and dot-repeat.
### 🧑🏫 Command — `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 |
## 👀 Events
`opencode.nvim` forwards `opencode`'s Server-Sent-Events as an `OpencodeEvent` autocmd:
```lua
-- Handle `opencode` events
vim.api.nvim_create_autocmd("User", {
pattern = "OpencodeEvent:*", -- Optionally filter event types
callback = function(args)
---@type opencode.cli.client.Event
local event = args.data.event
---@type number
local port = args.data.port
-- See the available event types and their properties
vim.notify(vim.inspect(event))
-- Do something useful
if event.type == "session.idle" then
vim.notify("`opencode` finished responding")
end
end,
})
```
### Edits
When `opencode` edits a file, `opencode.nvim` automatically reloads the corresponding buffer.
### Permissions
When `opencode` requests a permission, `opencode.nvim` waits for idle to ask you to approve or deny it.
### Statusline
```lua
require("lualine").setup({
sections = {
lualine_z = {
{
require("opencode").statusline,
},
}
}
})
```
## 🙏 Acknowledgments
- Inspired by [nvim-aider](https://github.com/GeorgesAlkhouri/nvim-aider), [neopencode.nvim](https://github.com/loukotal/neopencode.nvim), and [sidekick.nvim](https://github.com/folke/sidekick.nvim).
- Uses `opencode`'s TUI for simplicity — see [sudo-tee/opencode.nvim](https://github.com/sudo-tee/opencode.nvim) for a Neovim frontend.
- [mcp-neovim-server](https://github.com/bigcodegen/mcp-neovim-server) may better suit you, but it lacks customization and tool calls are slow and unreliable.