NeovimのAIプラグインcodecompanion.nvimの使い方
※ v12.15.0(2025年3月3日)までの内容を反映しました。
この記事はVim駅伝の2024年8月30日の記事です。
前回(2024年8月28日)の記事はteramakoさんのNeovim nvim-cmp の補完ソースプラグインと gin.vim の action 補完ソースを書いた話でした。
NeovimのAIプラグインcodecompanion.nvimを紹介します。
codecompanion.nvimとは
codecompanion.nvimはNeovimのAIプラグインです。
次のようにAIチャットやエージェントの実行ができます。
- チャット
- バッファの編集
- ファイル操作
- コマンドの実行
Ollama、OpenAI、Copilot、Gemini、Anthropic、DeepSeekなどいろいろサポートしています。
プロンプトは間にLuaの処理を挟んで柔軟に定義できます。
たとえば、「LSPのdiagnosticsをまとめてAIに解説してもらうプロンプト」がデフォルトで定義されています(上記の動画)。
導入方法
curl
が必要です。Neovimのバージョンは0.92以上のみ対応しています。
プラグインのインストール
olimorris/codecompanion.nvim
各々が使っているプラグインマネージャーでインストールします。
インストール
lazy.nvimだと次のように書いてインストールできます。
return { "olimorris/codecompanion.nvim", dependencies = { "nvim-lua/plenary.nvim", "nvim-treesitter/nvim-treesitter", }, opts = { -- ここに設定を書く }}
※ 遅延読み込みの例はこの記事の後半で紹介します。
設定の流れ
codecompanionでは各LLMをAdapterとして登録して使います。設定の流れは次のとおりです。
- APIキーの用意またはモデルのダウンロード
adapters
に各LLMの設定を書く- 使いたいadapterを
strategies
に書く
プラグインの設定はsetup
の中に書いていきます。
require('codecompanion').setup({ adapters = { -- TODO: ここにadapterを登録 }, strategies = { -- TODO: ここでadapterを指定 },})
※ lazy.nvimの場合、setup
の中身はopts
に書きます。この書き方について知りたい人は別の記事「lazy.nvimの使い方から起動を爆速にする方法までを解説」を読んでください。
APIキーを設定する場合のadapters
OpenAIを使うなら、次のようにAPIキーを渡します。
require("codecompanion").setup({ adapters = { openai = function() return require("codecompanion.adapters").extend("openai", { env = { api_key = vim.env.OPENAI_API_KEY }, }) end, }, -- ...})
APIキーを環境変数に書きたくない場合、1PasswordのCLIを実行させることもできます。詳しくはSetting an API Keyを読みましょう。
ローカルのLLMを動かす場合のadaptersの例
ここではOllamaのcodellama:7bの設定例を紹介します。
次のコマンドでモデルをダウンロードできます。
ollama run codellama:7b
require("codecompanion").setup({ adapters = { ollama = function() return require("codecompanion.adapters").extend("ollama", { schema = { model = { default = "codellama:7b", }, }, }) end, }, -- ...})
strategiesにadapterを指定
strategies
にどの機能でどのadapterを使うか指定します。
require("codecompanion").setup({ -- ... strategies = { chat = { adapter = "openai", }, inline = { adapter = "openai", }, agent = { adapter = "openai", }, },})
チャット機能ではchat
に指定したadapterが使われます。チャット以外ではinline
のadapterが使われます。agent
は@foo
のように書いたときに動くAIエージェントのことです。後で説明します。
使い方
CodeCompanionの機能やコマンドを紹介します。
チャットの開き方
チャットの開き方はいくつかあります。
:CodeCompanionChat
だと毎回新しいチャットが開きます。
一方、:CodeCompanionChat Toggle
だとチャットをトグルできます。
CodeCompanionChat
:CodeCompanionChat
を実行すると、チャット専用バッファが開きます。最初はノーマルモードで開きます。

質問を入力後、Enterを押すとLLMに送信され、回答が始まります。
※モデルやPCのスペックによっては回答の開始までに時間がかかります。「回答中」をわかりやすくする設定は後で説明します。

画像の回答の審議はさておき、適切にコードブロックがハイライトされていますね。
チャットは通常のバッファと同じように編集できるため、回答が冗長で見づらい場合は適宜削除できます。
チャット閉じるにはCtrl+cを入力します。
?でヘルプが開きます。

キーマップの他に、Variables
(変数)が出てきましたね。
変数
チャットでは変数が指定できます。
たとえば#buffer:18-21
と書けば、開いているバッファの18~21行目の内容に関連した質問ができます。

変数は他にもいくつか定義されています。
変数名 | LLMに共有される内容 |
---|---|
#buffer | 現在のバッファ |
#buffer:X-Y | 現在のバッファのX~Y行 |
#buffers | 開いているすべてのバッファ |
#editor | 見えている範囲の画面 |
#lsp | 現在のバッファのLSPの情報 |
バッファの指定範囲をチャットに送る
バッファの特定の範囲をLLMに共有する方法は、#buffer
以外にもあります。
共有したい部分をビジュアルモードで選択してコマンド:'<,'>CodeCompanionChat Add
を実行すれば、チャットに入力内容が挿入されます。
※以前はCodeCompanionAdd
でしたが、CodeCompanionChat Add
に変わりました。
Agents / Tools
エージェントも使えます。AIによる回答を解析して適切なツールを呼び出す機能です。
エージェントを使うにはメッセージでメンション風に@foo
を添えます。
@files foo/bar.luaを作成してください。
@cmd_runner
@cmd_runner
を使うと、コマンドが実行できます。テストの実行やライブラリのインストールを指示できるということです。
@editor
@editor
を使うと、開いているバッファを編集してもらえます。
@editor #buffer リファクタリングしてください
コード編集の場合、diffが表示されます。ga
(accept)で反映、gr
(reject)で拒否できます。
@files
@files
を使うと、ファイル関連の操作ができます。ファイルの読み込みや新規作成などなど。
@full_stack_dev
エージェントをいちいち判断するのは面倒ですよね?
@full_stack_dev
と書くだけで@cmd_runner
・@editor
・@files
の3つのエージェントが使えます。
迷ったらこれ。
@rag
URLを渡したり検索したい場合は@rag
を使います。
エージェントの公式ドキュメント:Using Agents and Tools | CodeCompanion
スラッシュコマンド
前述の「エージェント」はAIによる回答を解析して適切なツールを呼び出す機能でした。
一方「スラッシュコマンド」はスラッシュコマンドを書いた瞬間に何らかのアクションが発火されます。主な用途はコンテキストの共有です。
/buffer
/buffer
はバッファをAIと共有できる機能です。
/buffer vs #buffer
スラッシュコマンド/buffer
はバッファを自由に複数選択できます。
一方、変数#buffer
はチャットのバッファに入る前のバッファ1つだけです。
じゃあ/buffer
だけでいいじゃん、と思うかもしれませんが#buffer
だと行数指定ができます。
/file
/file
でファイルをAIと共有できる機能です。
/file vs @files
/file
だとUIを使って読み込んでほしいファイルを選択できます。
一方、@files
はファイル操作をしてもらうためのツールです。文章としてfoo/bar.txtを読み込んで
というような指定ができます。
ファイルの読み込みだけなら/file
の方がプレビューもあるので楽です。
ディレクトリ全体を読み込んでほしいときは@files
の方が楽です。
@files `openapi/`以下のYAMLファイルを読み込んで、おかしい所があれば教えて下さい。
/file vs /buffer
「/file
でファイルを共有できるなら、/buffer
いらないのでは?」と思うかもしれません。/buffer
にもメリットはあります。
/file
だとカレントディレクトリ以下のみが対象です。一方、カレントディレクトリ以外のファイルでもバッファとして開いて/buffer
で選択すれば、AIと共有できます。
/fetch
/fetch
を使うと、指定したURLの内容を取得してAIと共有できます。キャッシュもしてくれます。
/symbols
/symbols
を使うとTree-sitterから作成したコードのシンボル情報をAIと共有できます。
※ 一部の言語のみ対応しています。対応言語はqueriesディレクトリを見てみましょう。
/symbols vs /fileや/buffer
/symbols
はシンボル情報だけを共有するため、ファイル全体を共有する/file
や/buffer
よりもトークン数を節約できます。
/workspace
プロジェクトにcodecompanion-workspace.json
というファイルを用意しておくと、そのファイルに書いたファイルやシステムプロンプトを一括で共有できます。
詳しくは別の記事codecompanion.nvimのworkspaceの作り方・使い方にて解説しています。
その他のスラッシュコマンド
他にもスラッシュコマンドはあります。詳しくは公式ドキュメントのUsing Slash Commandsをご覧ください。
:CodeCompanion
:CodeCompanion /hoge
系のコマンドを実行すると、あらかじめ設定したプロンプトを実行できます。
公式ドキュメントに書かれているものからいくつかピックアップします。
:CodeCompanion /explain
:CodeCompanion /explain
を実行すると、チャットで選択範囲の内容を説明してくれます。
ノーマルモードでは現在の行のみが対象となってしまうため、:CodeCompanion /hoge
系のコマンドではビジュアルモードで実行するとよいでしょう。
:CodeCompanion /tests
:CodeCompanion /tests
を実行すると、選択範囲のテストコードを生成してくれます。コマンド名はtests
(複数形)です。

TypeScriptを使って試した所、jestが使われました。
実装を見てみると、プロンプトに「言語に合わせて適切なテストフレームワークを使ってね」と書かれています。
using an appropriate testing framework for the identified programming language
フレームワークを指定したい場合は、実装をコピペして独自のプロンプトを設定しましょう(後述)。
:CodeCompanion /fix
:CodeCompanion /fix
を実行すると、選択範囲のコードの修正方法をチャットで解説してくれます。
:CodeCompanion /lsp
:CodeCompanion /lsp
を実行すると、選択範囲のdiagnosticsを自動でまとめて解説してくれます。

diagnosticsのリスト化としても優秀です。
:CodeCompanion スラッシュなし
:CodeCompanion
単体で実行すると、プロンプト画面が表示されます。

質問を入力後、その内容に応じてチャットで答えたりバッファを書き換えたりします。ビジュアルモードで選択範囲を編集させたいときに便利です。
Action Palette
:CodeCompanionActions
を実行すると、登録したプロンプトやワークフローの一覧が表示されます。選択すると実行できます。

ビジュアルモードで実行すれば、前述の/lsp
なども一覧に入ってきます。
カスタマイズの例
最初に紹介した設定は最低限でした。ここからはもう少しカスタマイズした例を紹介します。
返答を日本語にする
opts.language
でAIの返答を日本語に指定できます。
require("codecompanion").setup({ opts = { language = "Japanese", },}),
lazy.nvimの場合、lazy.nvimのotpsとプラグインのopts
の2つがあり、片方のoptsを書き忘れる可能性があるので注意です。
return { "olimorris/codecompanion.nvim", -- ... opts = { opts = { language = "Japanese", }, }}
/filesなどのUIをプラグインにする
次のプラグインが入っている場合、/file
や/buffer
の選択画面でそのUIを使えます。
- snacks.nvim:
snacks
- telescope.nvim:
telescope
- mini.nvimのmini.pick:
mini_pick
- fzf-lua:
fzf_lua
require("codecompanion").setup({ strategies = { chat = { slash_commands = { ["buffer"] = { opts = { provider = "snacks", }, }, ["file"] = { opts = { provider = "snacks", }, }, ["help"] = { opts = { provider = "snacks", }, }, ["symbols"] = { opts = { provider = "snacks", }, }, ["workspace"] = { opts = { provider = "snacks", }, }, }, }, },})
実行中にステータスラインへ反映
CodeCompanionの実行(というよりLLM周り)は時間がかかるため、ステータスラインに実行中であることを表示しておくと便利です。
動画の例では画面右下にCompanion
という文字とスピナーを表示しています。
たとえばlualine.nvimの例は次のとおりです。別のファイルに書いてlualine側で呼び出しています。
local M = require("lualine.component"):extend()
M.processing = falseM.spinner_index = 1
local spinner_symbols = { "⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏",}local spinner_symbols_len = 10
-- Initializerfunction M:init(options) M.super.init(self, options)
local group = vim.api.nvim_create_augroup("CodeCompanionHooks", {})
vim.api.nvim_create_autocmd({ "User" }, { pattern = "CodeCompanionRequest*", group = group, callback = function(request) if request.match == "CodeCompanionRequestStarted" then self.processing = true elseif request.match == "CodeCompanionRequestFinished" then self.processing = false end end, })end
-- Function that runs every time statusline is updatedfunction M:update_status() if self.processing then self.spinner_index = (self.spinner_index % spinner_symbols_len) + 1 return "Companion " .. spinner_symbols[self.spinner_index] else endend
return M
require("lualine").setup({ -- ... sections = { -- ... lualine_z = { { require("plug/lualine/cc-component") }, }, },})
余談ですが、筆者がインストールした時はドキュメントが古かったため、OSSコントリビュートで更新しました。
公式ドキュメント:User Interface
独自のプロンプトを設定
prompt_library
に設定することで、独自のプロンプトを定義できます。プロンプトごとにモデルも変更できます。
require("codecompanion").setup({ -- ... prompt_library = { ["Hoge"] = { strategy = "chat", description = "foo bar", prompts = { { role = "system", content = "あなたは猫です。全部の語尾ににゃーとつけてください。", }, { role = "user", content = "会話を始めます。", }, }, }, },})
:CodeCompanionActions
から実行できます。
prompts
のcontent
は文字列を返す関数を書いてもOKです。これでかなり柔軟なカスタマイズが可能です。NeovimのAPIを呼んでごにょごにょできます。
興味のある人はCreating Promptsやデフォルトの設定の実装を読んでみると面白いかもしれません。
入力が面倒な人向け
@files
や#buffer
のようなCodeCompanionのエージェント・変数・スラッシュコマンドの補完が用意されています。nvim-cmp・blink.cmpなどをサポートしています。
詳しくは公式ドキュメントのCompletionを見てみましょう。
@files
など一部のエージェントでは反映時に承認が必要です。承認が面倒な場合は次のようにグローバル変数を設定しましょう。
vim.g.codecompanion_auto_tool_mode = true
公式ドキュメント:Using Agents and Tools | CodeCompanion
環境によってAdapterを分けたい
「会社のPCではOpenAI、自宅ではGitHub Copilot」のように分けたい場合は次のように分岐してあげます。
local my_adapter = vim.env.OPENAI_API_KEY and "openai" or "copilot"require("codecompanion").setup({ adapters = { openai = function() return require("codecompanion.adapters").extend("openai", { env = { api_key = vim.env.OPENAI_API_KEY }, }) end, }, strategies = { chat = { adapter = my_adapter, }, inline = { adapter = my_adapter, }, agent = { adapter = my_adapter, }, },})
短縮入力の設定
CodeCompanionのコマンド名はCodeCompanion
から始まります。
コマンド名が少し長いため、次のように設定しておくと楽です。
vim.cmd([[cab cc CodeCompanion]])
コマンドラインでccSpaceを入力したらCodeCompanion
に展開されます。
補完プラグインによっては:CC
のように入力すると候補として出てくるため、わざわざ設定しなくていいかもしれません。
lazy.nvimでの遅延読み込みの設定
筆者のlayz.nvimでの遅延読み込みの設定を紹介します。
---@module "lazy"---@type LazyPluginSpecreturn { "olimorris/codecompanion.nvim", dependencies = { "nvim-lua/plenary.nvim", "nvim-treesitter/nvim-treesitter", }, cmd = { "CodeCompanion", "CodeCompanionActions", "CodeCompanionChat" }, keys = { { "<Space>cc", "<Cmd>CodeCompanionChat Toggle<CR>", mode = { "n" } }, { "<Space>cc", "<Cmd>CodeCompanionChat<CR>", mode = { "v" } }, { "<Space>ca", "<Cmd>CodeCompanionActions<CR>", mode = { "n", "x" } }, },}
チャットの履歴を保存したい
チャットの履歴を保存する方法は別の記事codecompanion.nvimでチャット履歴を保存する方法にて解説しています。
トラブルシューティング
随時追記します。
Noiceを使ってたのにUIの位置が変わってしまった
2025年2月17日追記:dressing.nvimはアーカイブされました。そもそもdressing.nvimを使わないようにしましょう。
というわけでこの項目は不要ですが、一応残しておきます。
noice.nvimユーザーがいきなりdressing.nvimを入れると、UIが少し変わって困惑するかもしれません。
↓dressing.nvimのプロンプトの例。カーソル位置付近に表示されます。

↓noice.nvimのプロンプトの例。画面中央に表示されます。

noice.nvimを優先させたい場合、dressing.nvimの設定を変えましょう。
{ "olimorris/codecompanion.nvim", dependencies = { "nvim-lua/plenary.nvim", "nvim-treesitter/nvim-treesitter", "nvim-telescope/telescope.nvim", -- Optional { "stevearc/dressing.nvim", -- Optional: Improves the default Neovim UI opts = { input = { enabled = false, }, }, }, }, -- config = ... },
以上、CodeCompanionの紹介でした。
開発がかなり活発なようです。この記事を書いている間にも何回も更新されてました。