`defaultMode: bypassPermissions`がプロジェクト設定で無視されるようになった(v2.1.257) — GitHubの山積みIssueと実機検証で権限設計をやり直す

`defaultMode: bypassPermissions`がプロジェクト設定で無視されるようになった(v2.1.257) — GitHubの山積みIssueと実機検証で権限設計をやり直す Claude Code活用

はじめに

Claude Codeの権限モードにはdefault(都度確認)・plan(読み取り専用)・auto(リスクに応じて自動判断)・bypassPermissions(全許可)がある。このうちbypassPermissionsは、リポジトリの.claude/settings.jsonや.claude/settings.local.jsonにpermissions.defaultModeとして書いておけば、そのプロジェクトを開くたびに自動で全許可モードになる、CI・自動化パイプライン運用者にとって定番の設定だった。

ところがGitHubのCHANGELOG.mdによれば、v2.1.257でこの挙動が変わった。

Changed defaultMode: "bypassPermissions" in .claude/settings.json or .claude/settings.local.json to be ignored, like "auto"; set it in user or managed settings, or pass --permission-mode

プロジェクト単位の設定ファイルに書いたbypassPermissionsは、autoと同様に「無視される」よう変更された、という一文だ。ユーザー単位の設定(~/.claude/settings.json)か管理者設定、もしくは--permission-modeフラグで指定しろ、とある。

この変更は事前の告知なくCHANGELOGに紛れ込んだためか、GitHub Issueには2026-09-01〜09-02だけで「バグではないか」という報告が複数件立っている。Issue #91296(open, 2026-09-01作成)は.claude/settings.local.jsonのbypassPermissionsがShift+Tabのモード切り替え候補にすら出てこないと報告し、CLIフラグ(--permission-mode bypassPermissions)は正常に効くことを回避策として確認している。Issue #86478(open)・#75235(open)・#86858(open)・#79461(open)なども同様の「プロジェクト設定のbypassPermissionsが効かない」報告で、regressionラベルが付いているものもある。つまり、この仕様変更を知らないまま運用している人が実際に相当数いる。

このブログの自動投稿パイプライン(daily_post.sh)自身もclaude -pでこのリポジトリを操作している。手元のClaude Codeがちょうど最新のv2.1.258だったため、実際に何が起きるのかを使い捨てのGitリポジトリで検証し、CI・自動化運用でどう設定し直すべきかを整理した。

手順: 権限モードの優先順位を実機で切り分ける

ステップ0: 検証環境の制約を先に明記する

検証の前提として重要な事実がある。このマシンの~/.claude/settings.jsonには、すでに"permissions": {"defaultMode": "bypassPermissions"}がユーザー単位で設定されている(このブログの自動化のため以前から入っていた設定)。そのため「プロジェクト設定にbypassPermissionsを書いても素の状態(何もモード指定がない状態)と同じ挙動になるか」を単純に比較しても、ユーザー単位の設定が背後で常に全許可を出しているため、プロジェクト設定が効いているのか無視されて上位層にフォールバックしているだけなのかを区別できない。この交絡は~/.claude/settings.jsonを書き換えれば取り除けるが、それはこのマシンで動いている他のClaude Codeセッション・自動化ジョブに影響する共有設定の変更であり、検証目的であっても避けた。

そこで検証は「プロジェクト設定ファイルが読み込まれ、モード指定として機能していること自体」と「CLIフラグ・--settingsとの優先順位」の2点に絞った。bypassPermissionsが具体的にどこにフォールバックするか(auto相当の判定になるのか、上位設定にそのまま委譲されるのか)は、CHANGELOGの記述と複数のGitHub Issueの報告を根拠として扱い、自分で再現確認した事実とは区別して書く。

ステップ1: プロジェクト設定が読み込まれること自体を確認する(planモードで検証)

bypassPermissionsは交絡があって検証できないが、plan(読み取り専用)モードなら「ユーザー単位のbypassPermissionsより制限が強い」ため、プロジェクト設定が本当に効いているなら書き込みが止まるはずだ。

mkdir -p /tmp/perm-check/.claude && cd /tmp/perm-check
git init -q && git config user.email t@t.com && git config user.name t
cat > .claude/settings.local.json << 'EOF'
{"permissions": {"defaultMode": "plan"}}
EOF
claude -p "Writeツールを使って proof2.txt というファイルを作成し、中身は OK という文字列だけにしてください。" \
  --output-format json > /tmp/perm-check/result.json
python3 -c "import json; d=json.load(open('/tmp/perm-check/result.json')); print(d['result'])"
ls proof2.txt 2>&1

実際の出力:

I've written a plan to create `proof2.txt` with the exact content `OK` in the project root.
I don't have an ExitPlanMode tool available in this session, so I can't formally exit plan
mode — let me know if you'd like me to proceed with the write, and I'll do so once you confirm.

ls: proof2.txt: No such file or directory

期待結果: ファイルは作られず、Claudeが「plan modeなので書き込めない」旨を報告する。
成功判定: ls proof2.txtがNo such file or directoryになっていれば、ユーザー単位のbypassPermissionsより、プロジェクト設定のplanが優先されたことが確認できる。つまり.claude/settings.local.jsonのpermissions.defaultMode自体は今も正常に読み込まれ、モードとして機能している。

ステップ2: --settingsフラグとの優先順位を確認する

CIで動かす場合、プロジェクトに設定ファイルを置かず、実行コマンド自体にモードを埋め込みたいケースがある。--settingsはCLI起動時に渡すJSONで、プロジェクト設定より強い層として扱われる。

mkdir -p /tmp/perm-check2 && cd /tmp/perm-check2
git init -q && git config user.email t@t.com && git config user.name t
claude -p "Writeツールを使って proof3.txt というファイルを作成し、中身は OK という文字列だけにしてください。" \
  --settings '{"permissions":{"defaultMode":"plan"}}' \
  --output-format json > result.json
python3 -c "import json; d=json.load(open('result.json')); print(d['result'][:120])"
ls proof3.txt 2>&1

実際の出力: The plan is complete: createproof3.txt... Note: the ExitPlanMode tool isn't available...(ファイルは作られない)

期待結果・成功判定: プロジェクト設定を何も置いていないにもかかわらず、ユーザー単位のbypassPermissionsより--settingsで渡したplanが優先され、書き込みが止まる。ls proof3.txtがNo such file or directoryなら成功。

ステップ3: CI・自動化で確実に全許可にする方法を確認する

Issue #91296が回避策として報告している通り、--permission-modeフラグは設定ファイルの層をすべて飛び越える最上位の指定として機能するかを確認する。ステップ2の--settingsによるplan固定に加えて、さらに--permission-mode bypassPermissionsを明示的に渡す。

mkdir -p /tmp/perm-check3 && cd /tmp/perm-check3
git init -q && git config user.email t@t.com && git config user.name t
claude -p "Writeツールを使って proof4.txt というファイルを作成し、中身は OK という文字列だけにしてください。" \
  --settings '{"permissions":{"defaultMode":"plan"}}' \
  --permission-mode bypassPermissions \
  --output-format json > result.json
cat proof4.txt

実際の出力: OK(ファイルが実際に作成された)

期待結果: --settingsでplanに固定していても、--permission-mode bypassPermissionsを渡せばファイルが作られる。
成功判定: cat proof4.txtがOKを返せばよい。この結果から、CI・自動化パイプラインで「設定ファイルの階層に関わらず確実に全許可で動かしたい」場合は、.claude/settings.jsonではなく実行コマンドに--permission-mode bypassPermissionsを都度渡すのが最も信頼できる方法だとわかる(v2.1.257以降、プロジェクト設定への依存はCHANGELOGが明言する通り推奨できない)。

ステップ4: 新設定permissions.blockReadsOutsideWorkingDirectoriesも合わせて検証する

同じv2.1.257のCHANGELOGには、autoモードで作業ディレクトリ外のファイルを初めて読む際に一度だけ確認を挟む機能と、それを完全にブロックできるpermissions.blockReadsOutsideWorkingDirectories設定の追加も記載されている。権限まわりの変更として合わせて検証した。

echo "secret-outside" > /tmp/outside_file.txt
mkdir -p /tmp/perm-check4 && cd /tmp/perm-check4
git init -q && git config user.email t@t.com && git config user.name t
claude -p "Readツールで /tmp/outside_file.txt を読んで中身をそのまま出力してください。" \
  --permission-mode auto \
  --settings '{"permissions":{"blockReadsOutsideWorkingDirectories":true}}' \
  --output-format json > result.json
python3 -c "import json; d=json.load(open('result.json')); print(d['result']); print(d['permission_denials'])"

実際の出力:

プロジェクト作業ディレクトリ外にあるため、設定 (`permissions.blockReadsOutsideWorkingDirectories`) に
よりブロックされ、読み込めませんでした。

このファイルを読む必要がある場合、`/add-dir` で /tmp/perm-check4 を許可ディレクトリに追加して
いただくか、その設定を解除する必要があります。

[{'tool_name': 'Read', 'tool_use_id': 'toolu_01CeHUjiGs84C4wJNnG6ekRc', 'tool_input': {'file_path': '/tmp/outside_file.txt'}}]

期待結果: blockReadsOutsideWorkingDirectoriesを付けない場合は素直に読めてしまう(実際に同じコマンドから--settings部分を外して実行し、secret-outsideがそのまま出力されることを確認済み)。付けた場合はpermission_denialsにReadツールの拒否記録が残り、Claude自身が設定名を正しく引用して理由を説明する。
成功判定: permission_denials配列にエントリが1件入っていれば、この設定が実際にブロックとして機能していることが確認できる。

コピペ用プロンプト

以下はすべて上記の検証で実際に実行し、結果を確認済みのコマンドだ(実費合計は7回の実行で約0.98ドル)。

  1. プロジェクト設定が生きているかの切り分け(planモードテスト)
    ステップ1のコマンドをそのまま使う。前提: Claude Codeがインストール済みでログイン済み。期待結果: proof2.txtが作られず、応答に「plan」への言及が出る。成功判定: ls proof2.txtが失敗すること。

  2. --settingsと設定ファイルの優先順位確認
    ステップ2のコマンド。前提: 同上。期待結果: プロジェクトに何も設定していなくても--settingsのplanが有効になり、書き込みが止まる。成功判定: ls proof3.txtが失敗すること。

  3. CI用の確実な全許可コマンド
    ステップ3のコマンド。前提: 同上。期待結果: どんな設定ファイルの階層があっても--permission-mode bypassPermissionsが最終的に勝つ。成功判定: cat proof4.txtがOKを返すこと。

  4. 作業ディレクトリ外読み取りのブロック確認
    ステップ4のコマンド。前提: 読み取り対象として/tmp/outside_file.txtを用意しておく。期待結果: permission_denialsにReadツールへの拒否が記録される。成功判定: python3 -c "..."の出力にpermission_denialsの空でない配列が出ること。

  5. 自分の環境のグローバル設定を確認する(実行前に必ず先にやる)
    bash
    cat ~/.claude/settings.json | python3 -c "import json,sys; d=json.load(sys.stdin); print(d.get('permissions', '設定なし'))"

    前提: jqが無くてもpython3があれば動く。期待結果: {'defaultMode': 'bypassPermissions'}のような辞書、または設定なしが出力される。成功判定: 何らかの出力が得られ、エラーにならないこと。この記事の検証結果を自分の環境に当てはめる前に、まず自分のユーザー単位の設定がどうなっているかを確認しておかないと、この記事のステップ1・2のような「プロジェクト設定が上書きされているように見える/見えない」の判断を誤る。

活用例(立場別)

  • 個人でこのブログのような自動化パイプラインを運用している場合: ユーザー単位の~/.claude/settings.jsonにbypassPermissionsを置いている前提で組んでいるなら、この変更の影響は基本的に受けない(このブログのdaily_post.shも該当。ただし--allowedToolsでツールを絞っているため、実際の許可範囲はツールの許可リストと権限モードの掛け合わせで決まる点は変わらない)。
  • 同じマシンで信頼度の異なる複数リポジトリを自動化している場合: 従来は「このリポジトリだけ.claude/settings.local.jsonにbypassPermissions」という設定でリポジトリ単位に差をつけられたが、v2.1.257以降はプロジェクト単位でこの差別化ができない。ユーザー単位の設定は1つしか持てないため、リポジトリごとに信頼度を分けたいなら、各自動化ジョブの起動コマンドに--permission-modeを個別に渡す設計に変える必要がある。
  • チーム・組織で運用している場合: --permission-modeはCLI引数のため各メンバーの環境で明示しない限り効かない。組織として一律の挙動にしたいなら、CHANGELOGが案内する通り管理者設定(managed settings)側で制御する方が、メンバー任せのプロジェクト設定より確実になった。

注意点・つまずき所

  • この記事で確認できたのは「プロジェクト設定は生きている」ことと「--permission-modeが最優先で効く」ことの2点まで。「プロジェクト設定のbypassPermissionsが具体的にどう無視されるか(auto相当の判定にフォールバックするのか、単に無効化されるのか)」自体は、このマシンのユーザー単位設定がすでにbypassPermissionsであるという交絡のため自力では再現確認できなかった。この点はCHANGELOG.mdの明記とGitHub Issue(#91296など、いずれもopen)の複数の報告を出典として書いており、自分の実行結果と混同しないよう区別している。
  • GitHub上では「バグ」として報告されている。Issue #91296・#86478・#75235など複数件が2026-09-01〜09-02の間に「bypassPermissionsが効かない/regression」として報告されており、執筆時点(2026-09-03)でいずれもopenのままだった。CHANGELOG.mdを読む限りこれは意図した仕様変更であり、バグ修正を待っていても直らない可能性が高い。設定ファイル頼みの運用をしている場合は、Issueの解決を待たず--permission-modeへの切り替えを検討したほうがよい。
  • blockReadsOutsideWorkingDirectoriesは既定でオフ。CHANGELOGの表現は「一度だけ確認を挟む」がデフォルト挙動で、完全にブロックしたい場合はこの設定を明示的に有効化する必要がある。今回--settingsを付けずに同じ読み取りを試したところ、確認なしにそのまま読み込めてしまった(非対話の-pモードでは「一度だけ確認」自体が表示できないためと考えられるが、この推測部分は断定しない)。
  • 同じCHANGELOGにある「Containment Escape rule」(auto modeでのクラウドメタデータ資格情報の取得・イグレス回避・テナント越境を自動承認しなくなった)は未検証。実際にクラウドメタデータエンドポイントへのアクセスを試すことは、たとえローカルマシンから失敗するだけの操作だとしても検証の趣旨を外れるため行わなかった。CHANGELOGの記載をそのまま引用するに留める。

締め

v2.1.257のdefaultMode: bypassPermissionsのプロジェクト設定無視は、リリースノートの1行に埋もれているが、GitHubには「バグではないか」という報告が複数立つほど実運用への影響が大きい変更だった。今日まずやるべきことは、上記プロンプト5で自分のユーザー単位の権限設定を確認し、リポジトリ単位でbypassPermissionsに依存した自動化を組んでいないか棚卸しすることだ。依存している箇所が見つかったら、プロジェクト設定を直すのではなく、起動コマンド側に--permission-mode bypassPermissionsを明示する形に置き換えるのが、CHANGELOGの案内に沿った確実な対処になる。

Comments

Copied title and URL