Neovimの履歴管理ができるAIプラグインsenpai.nvimの使い方

この記事はVim駅伝の2025年4月9日の記事です。
前回(2025年4月7日)の記事はmikoto2000さんのdevcontainer.vim で Claude Code を使うでした。

NeovimのAIプラグインもかなり増えてきましたね。今回はチャット履歴を保存して、後から会話も継続できるAIプラグインsenpai.nvimを紹介します。

senpai.nvimの画面

senpai.nvimとは

senpai.nvimはNeovimのAI系プラグインです。筆者が作りました。

既存プラグインと比べた特徴は次のとおり。

  • チャットの履歴が管理できる
  • Mastra/Vercel AI SDKベースで作られている
  • 呼び出しのためのデフォルトキーマップを設定していない

他の機能は次のとおり。

  • MCP(Model Context Protocol)
  • RAG(Retrieval Augmented Generation)
  • プロンプトをカスタマイズしてチャットを開く(一言でなんていえばいいんでしょうね)
  • conventionalコミットメッセージの作成

導入方法

リポジトリ名だけコピペしたい人向け
eetann/senpai.nvim

依存

依存はあります。なるべく依存減らしたいって人、ごめんなさいね。

Node.jsではなくBunを採用したのは速いからです。

インストール

lazy.nvimだと次のように書いてインストールできます。

lazy.nvimの例
return {
"eetann/senpai.nvim",
build = "bun install",
dependencies = {
"MunifTanjim/nui.nvim",
"nvim-lua/plenary.nvim",
"nvim-treesitter/nvim-treesitter",
},
opts = {}
}

bun install、ちょっと時間かかります。履歴とかRAGの管理で必要なライブラリがあるんです。

lazy.nvimでの遅延読み込み

lazy.nvimでの遅延読み込みの例も載せておきます。

return {
"eetann/senpai.nvim",
build = "bun install",
dependencies = {
"MunifTanjim/nui.nvim",
"nvim-lua/plenary.nvim",
"nvim-treesitter/nvim-treesitter",
},
keys = {
{ "<space>ss", "<Cmd>Senpai toggleChat<CR>" },
{ "<space>sl", "<Cmd>Senpai promptLauncher<CR>" },
{ "<space>sv", "<Cmd>Senpai transferToChat<CR>", mode = "v" },
},
cmd = { "Senpai" },
ft = "gitcommit",
opts = {}
}

設定の書き方

プラグインの設定はsetupの中に書きます。

require("senpai").setup()

lazy.nvimの場合、setupの中身はoptsに書きます。この書き方について知りたい人は別の記事「lazy.nvimの使い方から起動を爆速にする方法までを解説」を読んでください。

lazy.nvimの例
return {
"eetann/senpai.nvim",
-- 省略
opts = {
-- ここに書く
}
}

対応しているLLM

現在対応しているのプロバイダーは次のとおりです。

名前API tokenの環境変数
anthropicANTHROPIC_API_KEY
deepseekDEEPSEEK_API_KEY
googleGOOGLE_GENERATIVE_AI_API_KEY
openaiOPENAI_API_KEY
openrouterOPENROUTER_API_KEY

デフォルトでどのプロバイダーを使うかはproviders.defaultに書きます。

require("senpai").setup({
providers = {
default = "openrouter",
},
})

各プロバイダーでのモデルの指定はmodel_idに書きます。

require("senpai").setup({
providers = {
default = "openrouter",
openrouter = { model_id = "openai/chatgpt-4o-latest" },
},
})

model_idの書き方は次のリンクを参考にしてください。

主要な機能の紹介

機能を紹介していきます。詳しい使い方はREADMEかヘルプを読んでください。

チャット機能

:Senpai toggleChatでチャットのウィンドウをトグルできます。

senpai.nvimの画面

入力欄(下のウィンドウ)に入力したら<CR>で送信です。

ファイル読み込み

ファイル名があればAIが判断して読み込みます。
たとえばfoo/bar/buz.txtbuz.txtのように書いても反応します。

Git管理下のファイルから**/buz.txtを探す、という実装になっています。ゆくゆくはプロジェクト毎に読み取り禁止とか承認を設定できるようにしたいところです。

ファイル編集

ファイル編集もできます。AIにファイル編集頼んだらReplace Fileというブロックが表示されます。
このブロック内でaを入力するとdiffが開きます。

diffはNeovimのdiffthisを使っているので、dodpといったキーマップでdiffを適用できます(ヘルプは:help copy-diffs)。

キーマップ

?でチャットのヘルプが開きます。キーマップをカスタマイズしたらこのヘルプにも反映されます。

チャットのヘルプ画面

ここでEnterを押すとそのキーを入力したときと同じ動作になります。

キーマップを設定していないやつも実行できます。
たとえばopen_api_docで、senpai.nvim開発者向けのOpenAPI(OpenAIではない)のUIが開きます。

open_api_docの入力

senpai.nvimが内部で使っているAPIをここで試せます。

履歴機能

履歴は自動で保存されます:Senpai 〇〇Saveみたいなコマンドを打つ必要はありません。

過去のチャットを復元したい場合、:Senpai loadThreadで選択UIが開きます。

snacks.nvimユーザーであれば、画像のようにシステムプロンプトとかモデルもプレビューに表示されます。

履歴から復元したらそのまま会話も継続できます

AIとの会話を一過性のものにはしたくないので履歴機能のあるプラグインにしました。「せんぱああああい、この前話してた実装なんですけど〜」みたいなノリです。

MCP

流行りのMCPも使えます。チャットでの呼び出しはAIが勝手に考えてくれます。
「このタイミングで呼び出さなくても……」ということはあるので、いずれメンションでの呼び出し(@fooみたいな)機能でオンオフできるようにしたいところです。

mcp.serversにこんな感じで設定します。

require("senpai").setup({
mcp = {
servers = {
sequential = {
command = "bunx",
args = { "-y", "@modelcontextprotocol/server-sequential-thinking" },
},
mastra = {
command = "bunx",
args = { "-y", "@mastra/mcp-docs-server" }
},
},
},
})

bunxというのはnpxBun版です。npxより速いです。

server-sequential-thinkingなどは数回ツールを呼び出す都合で、一度のメッセージだけでは処理しきれないことがあります。その場合は「続きをお願いします」みたいに会話すればOKです。

RAG

RAGも使えます。URL以外はまだ対応していません。

チャットの入力欄にてgRを打つと、URL入力欄が表示されます。

URLを入力したらfetchして内部のDBに保存されます。MCP同様、チャットでの呼び出しはAIが勝手に考えてくれます。

設定の可視化

AI系のプラグインで設定していると、「これ本当に反映されたのかな?」と思うことがあります。たとえばプロバイダーをvim.env.OPENAI_API_KEY and "openai" or "openrouter"のように動的に設定している場合です。

senpai.nvimではいくつかの設定を可視化できます。
現在チャットに紐づくLLMプロバイダー・モデル名はチャットのトップに表示されます。

設定したシステムプロンプトはヘルプ?show_system_prompt、MCPのツール設定はshow_mcp_toolsから確認できます。

プロンプトのカスタマイズ

どのチャットでも共通のシステムプロンプトを設定したい場合、設定のchat.system_promptに書きます。

require("senpai").setup({
chat = {
system_prompt = "Answers should be in Japanese."
}
})

システムプロンプトは別に英語以外で書いてもかまいません。

カスタマイズしたプロンプトを使い分けたい場合、prompt_launchersに書きます。

require("senpai").setup({
prompt_launchers = {
["Tsundere"] = {
system = "Answers should be tsundere style.",
priority = 100,
},
["test message"] = {
user = "test message. Hello!",
},
},
})

ここで書いたやつは:Senpai promptLauncherで一覧として表示されます。選んだやつがチャットで開きます。

実際に筆者がこの記事の構成を考えるときに使ったpromptLauncherを載せておきます(記事自体は頑張って25歳の人間が書いてます!)。

コミットメッセージの自動生成

:Senpai commitMessageでコミットメッセージを生成できます。.git/COMMIT_EDITMSGを開いたときに実行してみてください。いわゆるConventional Commits形式で書いてくれます。

この機能を作ってから、senpai.nvimのコミットメッセージの大半はこの機能で書かせてます(実例:eetann/senpai.nvim@b865dcf)。

言語指定も可能です。

:Senpai commitMessage Japanese

プロンプトに渡すだけなので厳密な言語名じゃなくてもかまいません。

:Senpai commitMessage English(Tsundere)

筆者は英語と日本語を使い分けたいので、次のようにキーマップを設定しています。
.config/nvim/after/ftplugin/gitcommit.lua.

vim.keymap.set("n", "<C-g><C-g>", function()
if vim.env.COMMIT_MESSAGE_ENGLISH == "1" then
vim.cmd("Senpai commitMessage English")
else
vim.cmd("Senpai commitMessage Japanese")
end
end, { buffer = true, desc = "Senpai commitMessage" })

環境変数COMMIT_MESSAGE_ENGLISHが1なら英語、それ以外は日本語にしています。リポジトリ毎の環境変数の設定にはmiseを使ってます。


以上、自作AIプラグインsenpai.nvimの紹介でした。動画で所々senpai(先輩)をsenapi(せなぴ)とtypoしていますが、現在は修正済みです。純粋に無能でした。

まだ1か月くらいしか経っていないひよっこプラグインです。速度面とかパフォーマンスは改善していきたいです。進捗はvim-jpのSlackの#times-eetann@eetann092でウォッチできます。

他にもNeovimの記事を書いてます。よかったらどうぞ。最近のイチオシは:=について書いている記事です。