目次
Claude Code 内蔵の vim mode を使ってみたら、jj で Esc がきかない、自前の .vimrc を読まない、Dvorak や Colemak を使っていると hjkl の位置がそもそも合わない、という場面ありますよね。自分も自作キーボード(keyball39/corne)で Astarte ベースのオリジナル配列を使っていて、内蔵 vim mode のキー割当が固定なのが地味に効いて結局触らなくなり、Ctrl+G で外部エディタを呼び出す構成に切り替えました。
内蔵vim modeで効かないカスタマイズ
Claude Code の内蔵 vim mode は、INSERT モードのカスタムマッピング(inoremap jj <Esc> など)も、自前 .vimrc の読み込みも、現時点では対応していません。GitHub の関連 Issue は次のとおりで、2026-05 時点で OPEN なものが2件直近に立ち上がっており、過去の類似要望はいずれもクローズされています[1]。
| Issue | 内容 | 状態 |
|---|---|---|
| #60785 | imap 相当の機能要望(2026-05-20 起票) | OPEN |
| #53039 | insert-exit キー(jk/jj)の remap 要望 | OPEN |
| #25306 | jj→Esc の insert-mode マッピング |
CLOSED(#13631 の duplicate) |
| #13631 | jk→Esc の insert-mode マッピング |
CLOSED(inactive) |
| #33763 | non-QWERTY 配列向けの vim motion remap | CLOSED |
| #35855 | langmap 対応(非ラテン配列向け) | CLOSED |
つまり「内蔵 vim mode を頑張って馴染ませる」道は現状塞がっていて、Ctrl+G で外部エディタを呼び出して自前の vim 設定で書く方が素直です。編集を閉じれば内容がチャット欄に戻るので、書きづらい入力欄の中でもがく必要がなくなります。
特に効いてくるのが、INSERT モード内のキー割当を自分で書けない点です。inoremap jj <Esc> のように「jj で Normal モードに戻る」設定は、多くの vim ユーザーが入れている定番ですが、これが Claude Code 側では効きません。~/.claude/keybindings.json で書けるのは Claude Code 全体のキー割当(送信・キャンセル等)に限られ、vim mode の INSERT 内の挙動はそこに書く対象ではない、という棲み分けです[2]。
.vimrc も読み込みません。普段使っている Telescope・fzf・自前関数のような環境はそのまま持ち込めず、内蔵 vim mode は素のキー設定で動きます。
Dvorak / Colemak や、自分のように自作キーボードで独自配列を組んでいる人にとってはここが特に痛いです。.vimrc で noremap を駆使してキー配列を物理位置に合わせている人ほど、内蔵 vim mode で何も反映されないことの違和感が大きくなります。
Ctrl+Gで外部エディタに渡す
設定は2段階です。使うエディタによってコマンドの形が変わる以外、難しいことはありません。
EDITORとVISUALを両方設定する
Claude Code は外部エディタを呼ぶとき、まず $VISUAL を見て、無ければ $EDITOR にフォールバックします。これは git や less、crontab といった Unix 系ツールの慣習に揃えた挙動で、Claude Code 本体のバイナリにも process.env.VISUAL を先にチェックし、無ければ process.env.EDITOR を使う実装が入っています[3]。
罠はここです。EDITOR=nvim だけ書いて満足しても、過去のどこかで VISUAL=vim を設定していた場合、$VISUAL が優先されるので Claude Code は system の vim を起動します。nvim の ~/.config/nvim/init.lua も lazyvim の設定も読まれず、「Ctrl+G でエディタは開くのに自分のキーマップが効かない」状態になります。自分はこれで一度詰まりました。
なので両方揃えます。~/.zshrc / ~/.bashrc などに次のように書きます。
# ~/.zshrc / ~/.bashrc など
export EDITOR="vim -f"
export VISUAL="vim -f"
-f は vim を foreground に保つオプションで、起動時に background へ飛ばないようにします。Claude Code 側は子プロセスの終了を待つ仕組みなので、-f 抜きだと「すぐ終わった」と判定されて空のチャット欄が戻ってきます。
neovim なら nvim、VS Code なら code --wait です。VS Code の --wait も同じ理由で必須。
# neovim
export EDITOR="nvim"
export VISUAL="nvim"
# VS Code
export EDITOR="code --wait"
export VISUAL="code --wait"
設定後は新しいシェルで Claude Code を起動し直し、echo $VISUAL で意図したコマンドになっているかを確認してから Ctrl+G を試すと事故が少ないです。
Claude Code だけ別のエディタを使いたい場合(シェル全体は別の EDITOR / VISUAL を保ちたい場合)は、~/.claude.json を作って env キーで上書きできます[4]。ここでも VISUAL を一緒に書かないとシェル側の $VISUAL が勝つので、両方並べておきます。
{
"env": {
"EDITOR": "vim -f",
"VISUAL": "vim -f"
}
}
Ctrl+Gでエディタを起動する
設定後に Claude Code を再起動し、チャット欄でプロンプトを書き始めた状態(空でも可)で Ctrl+G を押すと、指定したエディタが起動します。書き終えてエディタを閉じると、内容がチャット欄に戻る流れです。
自分の vim 設定がそのまま使えるので、jj での Esc も hjkl のリマップも普段通り動きます。.vimrc 内に物理キーに合わせた noremap を書いていた人は、その設定が即適用されるので、内蔵 vim mode で感じていた違和感が一気に消えます。
まとめ
「内蔵 vim mode を頑張って馴染ませる」より「外部エディタに渡す」方が、現状の Claude Code では筋が良いです。INSERT モードのカスタムマッピング対応は Issue #60785 / #53039 で feature request が直近に出ているので、いずれ要らなくなるかもしれませんが、現状の解はこれです。
副作用として、Ctrl+G の最中は会話履歴が一時的に見えなくなる、ターミナルの組み合わせ次第で挙動が崩れることがある、といった既知の問題があります(Issue #20045 / #9218)。SSH 越しで使うと editor 自体が起動しない場合(Issue #19076)もあるので、立ち上がらないときは $VISUAL / $EDITOR の値とターミナル種別の両方を疑うのが速いです。意図と違うエディタが立ち上がっている場合はほぼ確実に $VISUAL が原因です。
長文プロンプトを楽に入力する目的で同じ仕組みを紹介している先行記事もあります[5]。本記事は同じ仕掛けを、Dvorak / Colemak や自作キーボードで独自配列を組んでいる人の逃げ道として読み替えた角度になっています。
Feature Request: Vim insert mode key remapping (imap equivalent) · Issue #60785 / Allow remapping vim-mode insert-exit key (e.g. jk/jj → Esc) · Issue #53039 ↩︎
Claude Code v2.1.150 のバイナリ内部に
if (process.env.VISUAL) ... else if (process.env.EDITOR) ...という形でエディタ解決ロジックが入っているのを確認した(stringsで抽出)。設定方法の汎用例としては Setting Default Editor for Claude Code (Gist) も参考になるが、こちらは$EDITORのみを扱っており、$VISUALには触れていない ↩︎How to Edit Prompts in External Editor in Claude Code | ClaudeLog ↩︎
