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:7brequire("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 Mrequire("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の紹介でした。
開発がかなり活発なようです。この記事を書いている間にも何回も更新されてました。