はじめに

Neovimでコードを読んでいるとき、やりたいのはCodexをsplitで開くことではありません。開いているファイルや選択範囲を正確に渡し、会話を残したまま編集へ戻ることです。codex.nvimは、その往復を短くするためのNeovimプラグインです。
このツールが必要になる場面
codex.nvimで解決したい課題は、次のとおりです。
Neovimでコードを読んだり選んだりしているとき、ファイルや範囲を説明し直さずCodexへ正確に渡し、会話を残したまま編集へ戻りたい。そうすれば、エディタとagentの間を往復するたびに作業の前提を組み立て直さずに済む。
Codex CLIは:terminalから起動するだけでも使えます。しかし、相談するたびにファイルパスをコピーして、行番号を確認する必要があります。選択範囲の貼り付けやterminal modeからの移動も残ります。1回なら小さくても、調査、修正、確認を繰り返すほど集中を切る原因になります。
codex.nvimで前へ進められるのは、次の3つです。
| 進めたいこと | つまずきやすい点 | codex.nvimが作る状態 |
|---|---|---|
| Codexへ相談する | 対象のファイルや範囲を説明し直す | Neovimで見ている対象をそのまま渡せる |
| 会話を続ける | splitを閉じるとsessionまで失う | windowだけ隠し、processは残せる |
| 編集へ戻る | terminal modeとwindow移動が混ざる | Codexから隣のwindowへ明示的に移動できる |
一方で、導入すれば必ず速くなるわけではありません。外部terminalやtmuxからCodexを使う習慣が完成していれば、プラグインを増やす方が負担です。誤ったファイルやcwdを暗黙に渡す連携も困ります。そのためcodex.nvimは、送るcontext、sessionのcwd、windowとprocessの状態を確認できる形にしています。
Codexをsplitで開くこと自体が目的ではない
codex.nvimは、新しいAI agentでもCodex本体の代替でもありません。Neovimとインストール済みのCodex CLIをつなぐ連携層です。推論、コード変更、command execution、session historyはCodex本体へ任せます。
プラグインが担当するのは、次の3点です。
- 現在のファイル、選択範囲、explorerの項目をCodexの入力へ変換する
- Codex processを保ったまま、windowの表示とfocusを切り替える
- Codexがどのcwdとbackendで動いているかを確認できるようにする
Neovimで読んでいるコード
↓ contextを変換
Codex CLIで調査・修正を進める
↓ sessionを残す
Neovimの編集へ戻る
コマンド体系とside panelの操作感は、coder/claudecode.nvimを参考にしました。現在のファイルを追加する、選択範囲を送る、隠したsessionへ再びfocusするといった操作は、agentの種類が変わっても必要だからです。
ただし、内部protocolは異なります。claudecode.nvimはClaude CodeとのIDE連携を実装しています。codex.nvimはCodex CLIのterminal UIと、公式のapp-server interfaceを使います。似た外見を移すのではなく、Codexが公開している境界に合わせて実装しました。
contextとcwdは別の問題として扱う
「開いているファイルを中心にする」には、2つの意味があります。contextは今回Codexへ何を渡すかを決めます。cwdはsessionがどこからファイルを探し、履歴を読み、commandを実行するかを決めます。
たとえば、github.com/nwiizo/codex.nvim/lua/codex/init.luaを開いてCodexを起動するとします。cwd = "root"を選ぶと、最も近い.gitのあるgithub.com/nwiizo/codex.nvimから起動します。cwd = "file"なら、開いたファイルのあるlua/codexが起点です。
| 設定値 | Codexを起動する場所 |
|---|---|
"root" |
開いているファイルから最も近いroot marker。既定値は.git |
"file" |
開いているファイルのディレクトリ |
"nvim" |
Neovim自身のcurrent working directory |
| 固定パス | 指定したディレクトリ |
function(ctx) |
buffer情報から利用者が決めたディレクトリ |
普段の開発なら、repository全体を調べてtestを実行できるrootが自然です。単一ファイルの場所を起点にしたい時はfile、monorepo内の独自境界を使う時はcallbackを選べます。大切なのは、開いているファイルを毎回渡しながらも、会話中の足場は動かさないことです。
codex.nvimは、cwdをsession開始時に一度だけ解決します。別のbufferへ移動しても、processを止めるまでcwdは変えません。これにより、同じ会話の途中で相対pathの意味が変わることを防ぎます。
windowを隠しても会話は残す
Neovimのterminal bufferは、入力をterminal processへ送るTerminal-modeを持ちます。通常のbufferと同じ感覚でwindowを移動しようとすると、keyがCodex側へ送られることがあります。codex.nvimではbuffer local mappingとしてAlt-h/j/k/lを設定し、terminal modeを抜けて隣のwindowへ移動します。terminal emulatorがOptionやAltをMetaとして送らない時は、別のkeyに変更できます。
:CodexFocusは、単純な表示のon/offではなく、sessionを保つための状態遷移として動きます。
| 現在の状態 | :CodexFocusの結果 |
|---|---|
| processがない | 新しいsessionを起動してfocus |
| processはあるがwindowがない | splitを再表示してfocus |
| 別windowに表示中 | そのwindowへfocus |
| Codex windowをfocus中 | windowだけ隠し、processは維持 |
:CodexCloseは表示だけを隠し、:CodexStopだけがprocessを停止します。Codex windowから隠した時は、直前に使っていたeditor windowへ戻ります。windowを整理することと会話を終えることを分けるためです。
操作と解決する課題の対応
機能の数だけでは、導入後に何が変わるのか分かりません。日常の作業に対応させると、次のようになります。
| 進めたいこと | 操作 | 得られる状態 |
|---|---|---|
| 現在のファイルについて相談する | :CodexAdd |
composerへ@pathを追加する。まだ送信しない |
| 選んだコードを正確に渡す | Visual modeで:CodexSendVisual |
ファイルパスと行番号つきで送る |
| explorerで見つけた項目を渡す | :CodexTreeAdd |
選択中のファイルやディレクトリを追加する |
| 会話へ戻る、または一時的に隠す | :CodexFocus |
processを保ったままwindowを切り替える |
| 過去の会話から再開する | resume、continue、fork | Codex自身のsession historyを使う |
| 変更をレビューする | :CodexReview |
uncommitted changes、base branch、commitを明示して依頼する |
| 動作の前提を確かめる | :CodexStatus、:CodexHealth |
cwd、process、直近のcontext、依存関係を確認する |
:CodexTreeAddはnvim-tree、neo-tree、Oil、mini.files、netrw、Snacks pickerに対応します。特定のexplorerをplugin dependencyにせず、開いているfiletypeに合わせてadapterを選びます。
Visual selectionはlinewiseだけでなく、characterwiseとblockwiseも扱います。multibyte character、tab、wide character、exclusive selectionもtest対象です。contextが既定の500行または65536 bytesを超えた時は、黙って切り詰めず送信を拒否します。画面で選んだ内容とCodexへ渡った内容を一致させるためです。
:CodexStatusには、直近に渡したpathと行範囲、composerへ追加しただけか送信したか、sessionのcwdを表示します。sessionを起動していない時は、次に使うcwdを確認できます。選択したコード本文は保持せず、確認に必要なmetadataだけをsession中に残します。
terminalを既定にした理由
codex.nvimには2つのbackendがあります。既定のterminalは、Codex terminal UIをNeovimのsplitで動かします。conversation表示、approval、command executionをCodex側へ任せられるため、CLIですでに成立している操作と信頼性を保てます。
実験的なapp_server backendは、codex app-serverをstdioで起動します。streaming message、plan、command output、approval、user input、diffをNeovim native UIに表示する構成です。公式資料では、app-serverはrich client向けのinterfaceです。
native UIには、resumeとforkのpickerやdiff表示をNeovimへ馴染ませられる利点があります。一方、プラグインはresponseとnotificationを正しく扱う必要があります。approval中の入力やactive turnへのsteer、threadの切り替えも管理対象です。process終了時にはstateをresetします。Codexを使うために新しい不安定要素を増やさないよう、terminalを安定した既定値にしました。app-serverは壊れる可能性のある実験機能として分けています。
最小構成で試す
lazy.nvimでは、利用するcommandをlazy-load triggerへ登録します。
{ "nwiizo/codex.nvim", cmd = { "Codex", "CodexFocus", "CodexAdd", "CodexSendVisual", "CodexTreeAdd", "CodexStatus", "CodexStop", "CodexHealth", }, opts = { backend = "terminal", cwd = "root", focus_after_send = true, terminal = { split_side = "right", split_width_percentage = 0.4, window_navigation = { left = "<M-h>", down = "<M-j>", up = "<M-k>", right = "<M-l>", }, }, }, keys = { { "<leader>ax", "<cmd>CodexFocus<cr>", desc = "Focus or hide Codex" }, }, }
設定後は、:CodexHealthでNeovimとCodex CLIを確認し、対象repositoryで:CodexFocusを実行します。右側にCodexが開いたらAlt-hで対象ファイルへ戻り、:CodexAddを実行します。コードの一部について相談するなら、Visual modeで選択して:CodexSendVisualを実行します。focus_after_send = trueなら、contextを渡した後にCodexへfocusします。
向いていない場面
codex.nvimが合うのは、Neovimを主な編集環境にし、同じCodex sessionへファイルや選択範囲を何度も渡す人です。1つのNeovim instanceにつき1つのCodex processまたはthreadで足りることも前提です。
次の条件では、別の方法が向いています。
- 外部terminalやtmuxだけでcontextの受け渡しに困っていない
- 複数のagent sessionを同時に一覧、監視、操作したい
- plugin独自のtranscriptを永続化したい
- Windowsで使いたい
- Neovimのファイルや選択範囲をCodexへ渡す必要がない
codex.nvimは複数sessionの同時管理、独自transcriptの永続化、Windows対応を実装していません。Codex自身のsession historyとは別に履歴を作ると、どちらがsource of truthか分かりにくくなるためです。複数sessionの監督が中心なら、このプラグインの対象とは異なります。
正しく渡せることを確認する
context連携では、便利さより「何が渡ったか」を信頼できることが重要です。codex.nvimはheadless test、StyLua、Luacheck、Lua Language Serverの型診断をCIへ入れています。Neovimは要求する最小versionの0.12.0に加え、stableとnightlyでも同じtest suiteを実行します。
make check make integration
make integrationでは、インストール済みのCodex CLIから実際にapp-serverを起動し、initialize handshakeとthread/listを確認します。公開用tagでもqualityと3つのNeovim matrixを通しています。
このブログが良ければ読者になったり、nwiizoのXやGithubをフォローしてくれると嬉しいです。
おわりに
codex.nvimの目的は、CodexをNeovimの中へ表示することではありません。編集の文脈を正確に渡し、sessionを失わず、次の編集へ戻れるようにすることです。そのためにcontextとcwd、windowとprocess、安定したterminalと実験的なnative UIを分けました。
外部terminalだけで十分なら、このプラグインは必要ありません。反対に、ファイルパスや選択範囲を説明し直す作業と、Codex windowから戻る操作が積み重なっているなら、codex.nvimを使ってみてほしいです。良かった機能だけでなく、cwdの決め方やwindow移動で残る違和感もGitHub Issuesで教えてください。