An open API service indexing awesome lists of open source software.

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.

Awesome Lists containing this project

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.

Neovim terminal

```lua
vim.g.opencode_opts = {
provider = {
enabled = "terminal",
terminal = {
-- ...
}
}
}
```

snacks.terminal

```lua
vim.g.opencode_opts = {
provider = {
enabled = "snacks",
snacks = {
-- ...
}
}
}
```

kitty

```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
```

wezterm

```lua
vim.g.opencode_opts = {
provider = {
enabled = "wezterm",
wezterm = {
-- ...
}
}
}
```

tmux

```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

lualine

```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.