CLAUDE_CODE_BASH_EDIT_DIFFで全パーミッションモードのBash差分を記録する
Bashコマンドが変更したファイルの差分を、どのパーミッションモードでも記録させる環境変数の使い方と、設定との優先関係を扱います。
CLAUDE_CODE_BASH_EDIT_DIFFで何ができるか
CLAUDE_CODE_BASH_EDIT_DIFFは、Bashコマンドの実行中にリポジトリ内のファイルがどう変わったかを、パーミッションモードに関係なく記録させる環境変数です。1を設定すると、通常モードや計画モードのように本来は記録されない場面でも差分が残ります。0を設定すると記録そのものを止められます。Claude Code v2.1.269以降が対象です。
対になる仕組みが設定キーbashEditDiffEnabledです。両者はどちらも「Bashコマンドが変更したファイルを記録するか」を制御しますが、有効化できる場所と優先順位が違います。この違いを知らずに設定だけ触ると、チーム全体には効かず自分のセッションだけ動く、といったすれ違いが起きます。
使いどころとして考えられるのは、Claudeが自律的にBashを何度も呼び出すセッションを、あとから振り返って確認する場面です。通常モードでは1コマンドごとに承認するので、変更点を目視しやすいと考えられます。自動実行モードでは連続してコマンドが走るため、どのタイミングでどのファイルが動いたかを追いにくくなります。
全モード記録はこのギャップを埋める手段です。計画モードで想定外の書き込みが起きていないかを確認する用途にも向きます。
環境変数と設定キーのどちらを使うか
どちらも「記録するか」を決める仕組みですが、効く範囲と置ける場所が違います。
環境変数と設定キーの違い
CLAUDE_CODE_BASH_EDIT_DIFF
設定キーより優先され、1で全モード記録、0で停止です。シェルでexportすればそのセッション限り、settings.jsonのenvブロックに書けば起動のたびに適用されます。envブロックはプロジェクト設定にも書けます(フォルダを信頼した後に適用される値が大半です)。
bashEditDiffEnabled
trueが効くのはユーザー設定・--settingsで渡すJSON・管理者設定だけです。プロジェクトの.claude/settings.jsonや.claude/settings.local.jsonのtrueでは記録は始まりません。falseはどのファイルに書いても有効ですが、より上位の設定ファイルがtrueを設定していれば上書きされます。
Claude Codeには環境変数と設定キーが対になっているペアが複数あり、どちらを先に読むかは組ごとに違います。ANTHROPIC_MODELとCLAUDE_CODE_AUTO_CONNECT_IDEは環境変数が設定されていれば常にそちらを優先し、設定キーは環境変数が未設定のときだけ参照します。CLAUDE_CODE_BASH_EDIT_DIFFとbashEditDiffEnabledも、環境変数が設定キーより優先される同じ型です。
既定では、Claude Codeが差分を記録するのは自動実行モードとbypassPermissionsモードだけです。しかもBashツール経由でClaudeにファイル編集を指示したときに限ります。bashEditDiffEnabledをtrueにすると、この制限を外してすべてのパーミッションモードで記録します。
値の書式にも注意が必要です。環境変数一覧の共通規則では、オン・オフを切り替える変数は1・true・yes・onでオン、0・false・no・offでオフになり、大文字・小文字は区別されません。CLAUDE_CODE_BASH_EDIT_DIFF=TRUEでも=1でも同じ扱いです。
パーミッションモード別の記録状況
記録の既定値はパーミッションモードごとに違います。CLAUDE_CODE_BASH_EDIT_DIFF=1を立てると、この差を無視してすべて「記録する」に揃えられます。
| パーミッションモード | 既定の記録 | CLAUDE_CODE_BASH_EDIT_DIFF=1のとき |
|---|---|---|
| 通常モード(都度確認) | 既定の記録記録しない | CLAUDE_CODE_BASH_EDIT_DIFF=1のとき記録する |
| 計画モード | 既定の記録記録しない | CLAUDE_CODE_BASH_EDIT_DIFF=1のとき記録する |
| 自動実行モード | 既定の記録Claude CodeがBash経由の編集をClaudeに指示したときだけ記録 | CLAUDE_CODE_BASH_EDIT_DIFF=1のとき記録する(バックグラウンド実行・読み取り専用コマンドを除く) |
bypassPermissionsモード | 既定の記録同上 | CLAUDE_CODE_BASH_EDIT_DIFF=1のとき記録する(バックグラウンド実行・読み取り専用コマンドを除く) |
レビュー目的で全モードの記録を確認したいときに、この環境変数が効きます。
設定方法 — シェルと設定ファイル
シェルで一時的に切り替えるなら次のように実行します。
CLAUDE_CODE_BASH_EDIT_DIFF=1 claude常設したい場合はsettings.jsonのenvブロックに書きます。
{
"env": {
"CLAUDE_CODE_BASH_EDIT_DIFF": "1"
}
}bashEditDiffEnabled側は次の形です。
{
"bashEditDiffEnabled": true
}PostToolUseフックが受け取るデータ
記録が有効なとき、Bashツールの実行結果はPostToolUseフックにtool_response.bashEditDiffとして渡されます。中身は次のフィールドで構成されます。
| フィールド | 内容 |
|---|---|
changedFiles | 内容変更されたファイルの絶対パス配列(最大200件) |
files | 内容表示用の差分。最大5ファイルぶんのhunkを含み、追加・削除はcreated/deletedで示す |
moreFiles | 内容filesに差分が入らなかった変更ファイルの件数 |
unavailable | 内容差分が不完全、または取得できなかったときに立つ |
skipped | 内容git checkoutやgit stashのように作業ツリーごと動かすGitコマンドで、差分を取らなかったときに立つ |
shared | 内容サブエージェント等、別のBashツール呼び出しが同じリポジトリで同時に走っていたときに立つ |
sharedが立っている場合、リストされた変更が自分のコマンドではなく並行して動いていた別の呼び出しによるものである可能性があります。Gitが無視するファイルとサブモジュール内のファイルは、そもそもリストに載りません。バックグラウンド実行のコマンドと読み取り専用のコマンドには差分が付きません。
記録が有効なら、コマンド直後にターミナルへこの差分が表示されます。ディスク上の変更そのものを検知したいだけなら、FileChanged hookの方が用途に合う場面もあります。
実際のペイロードはおおよそ次の形になります。hunksの中身は省略しています。
{
"changedFiles": ["/repo/src/app.ts", "/repo/src/utils.ts"],
"files": [
{
"filePath": "/repo/src/app.ts",
"hunks": [...]
}
],
"moreFiles": 1,
"unavailable": false,
"skipped": false,
"shared": false
}変更ファイルが6件以上あるときは、filesにhunkが入るのは5件までです。残りのファイルのパスはchangedFiles(最大200件)に載り、差分の入らなかった件数がmoreFilesに入ります。
PostToolUseフックで差分を使う
tool_response.bashEditDiffはフック側から読めるので、変更されたファイルに対して自動でリンタやフォーマッタをかけるフックを組めます。次の例は、Bashコマンドが変更したファイルの一覧をjqで取り出し、ESLintの--fixに渡します。
{
"hooks": {
"PostToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "jq -r '.tool_response.bashEditDiff.changedFiles[]? // empty' | xargs -r npx eslint --fix"
}
]
}
]
}
}changedFilesが空ならフックは何もせず終わります。unavailableがtrueのとき、つまり差分の取得自体に失敗しているときは、このフックはそれを検知しません。差分の有無を条件分岐に使う場合はunavailableとskippedもあわせてチェックし、両方ともfalseのときだけchangedFilesを信用するようにフック側を書くと安全です。
もうひとつ気をつけたいのは、changedFilesが拡張子を問わないことです。Markdownや画像が変わったときも、そのパスがそのままeslint --fixに渡ります。対象を絞るなら、grep -E '\.(ts|tsx|js)$'のような絞り込みをxargsの前に挟みます。
シェルとsettings.jsonで値が食い違ったとき
シェルのプロファイルでexportしつつ、settings.jsonのenvブロックにも同じキーを書くと、どちらが勝つか迷います。Claude Codeはenvの値をプロセス環境に書き込んでシェルから継承した値を置き換えるため、設定ファイル側の値が優先されます。シェルで0にしていても、ユーザー設定のsettings.jsonが"1"を指定していれば記録は有効になります。
例外もあります。Claude Desktopアプリや自己ホスト環境のランナーがセッションを起動する場合は、起動側が組み立てた環境が優先されます。起動環境がすでに設定している変数については、settingsファイルのenv値は無視されます。
公式ドキュメントは、モデル選択・タイムアウト・機能トグルのような変数を、起動時にすべての設定ファイルから適用すると説明しています。例外は、プロジェクト設定とローカル設定が設定できない変数の一覧です(CLAUDE_CONFIG_DIRやOpenTelemetryのエクスポーター関連など)。CLAUDE_CODE_BASH_EDIT_DIFFはその一覧に載っていません。そのためプロジェクトの.claude/settings.jsonや.claude/settings.local.jsonのenvにも書けます。ただし、env値の大半はフォルダを信頼した後に適用されます。
チェックインした設定ファイルでは、bashEditDiffEnabled: trueは効きません。一方、同じファイルのenvに環境変数を書く形は取れます。有効化の経路が非対称です。
複数の設定ファイルに同じキーがあるときの優先順は、次のとおりです。
- 管理者設定
- コマンドライン引数
- プロジェクトローカル設定(
.claude/settings.local.json) - 共有プロジェクト設定(
.claude/settings.json) - ユーザー設定
「シェルで無効にしたはずなのに記録が消えない」と感じたら、まず優先度の高い設定ファイルのenvブロックを確認してください。
導入の進め方
個人で試してから組織へ広げる流れが、フックの実装ミスを広げずに済みます。
個人から組織へ広げる順番
- 1
自分のセッションで試す
CLAUDE_CODE_BASH_EDIT_DIFF=1 claudeで起動し、通常モードのままBashを走らせて、差分がターミナルに出ることを確かめます。 - 2
フックのペイロードを見る
PostToolUseフックでtool_response.bashEditDiffをファイルに書き出し、sharedやskippedが立つ場面を実際のリポジトリで観察します。 - 3
常設の置き場所を選ぶ
個人の常設ならユーザー設定の
envかbashEditDiffEnabled、組織全体に効かせたいなら管理者設定に置きます。
よくある誤解と注意点
- 「記録されない」と「変更が無い」は別:
git checkoutやgit stashのようなGitコマンドはskipped: trueになり、差分を取りません。「変更が無かった」のではなく「差分を取っていない」状態なので、空のchangedFilesと混同しないでください。 - バージョン要件を先に確認する: この環境変数も
bashEditDiffEnabled設定も、Claude Code v2.1.269より前のバージョンには存在しません。古いバージョンで動かないときは、まずアップデートを疑ってください。 - 監査やポリシー強制の代わりにはならない: 公式ドキュメントは、この差分記録をベストエフォート・パブリックベータの機能と位置づけています。変更の取りこぼし、他プロセスによる変更の混入、フィールド形状の将来変更が起こり得るため、用途はレビューすべき箇所を見つけることに限られます。コンプライアンス上の変更履歴が必要な場面では、Gitのコミット履歴やCIのログのような、切り詰めのない記録手段を別に用意してください。
記録と実行制限は別の設定
Bashの実行そのものを制限するsandbox.enabledとは目的が異なります。sandbox.enabledはコマンドの実行環境を隔離する設定です。bashEditDiffEnabledとその環境変数は「実行を許すかどうか」ではなく「実行後に変更を記録するかどうか」だけを担当します。Bashのタイムアウトを変えるBASH_DEFAULT_TIMEOUT_MSとも独立しているので、片方だけ有効にしても矛盾は起きません。
まとめ
組織全体で記録したいなら管理者設定、自分のセッションだけならCLAUDE_CODE_BASH_EDIT_DIFF=1と使い分けます。チェックインしたプロジェクト設定で有効にしたいなら、env経由が唯一の経路です。