Claude Codeに作業を任せていると、便利な一方で「勝手にgit pushされたら」「作業ブランチをgit branch -Dで消されたら」とヒヤッとする瞬間があります。基本的には自動でどんどん進めてほしい。けれど、取り返しのつかない操作だけはしないでほしい。
この記事では、~/.claude/settings.jsonのpermissionsを使って、確認を挟みたい操作(ask)と実行そのものを禁止したい操作(deny)を宣言的にルール化する方法を紹介します。CLAUDE.mdに「絶対にpushしないこと」とお願いするのではなく、仕組みとして縛るのがポイントです。
AIに操作を任せる怖さ
Claude Codeに自動でコミットやブランチ操作を任せると、知らぬ間にAIのコミットが積まれていたり、git pushが走っていたりすることがあります。具体的に怖いのは次のようなシナリオです。
- 意図しないgit push
- git branch -Dによる作業ブランチの削除
- git reset --hardによる未コミット変更の消失
削除・破壊系の操作は、何も設定していなくてもClaude Codeが確認を挟んでくれることが多いです。とはいえ「多い」であって「必ず」ではないので、念のため仕組みで縛っておきたいところです。
CLAUDE.md(指示文)に「絶対にpushしないこと」と書く方法もありますが、これはあくまでお願いベースで、強制力としては弱いものです。そこで、設定ファイルでガードを仕込みます。
前提知識:3つの権限レベルと優先順位
permissionsには3つの判定レベルがあります。
- allow:確認なしで自動実行する
- ask:実行前に毎回確認する
- deny:実行そのものをブロックする
参照: https://code.claude.com/docs/ja/settings#permission-settings
肝になるのが優先順位です。1つのコマンドが複数のルールに該当した場合、評価順は deny > ask > allow で、もっとも強い deny が勝ちます。つまり、askとdenyに同じコマンドを書いても、denyが優先されてブロックされます。
設定ファイルの置き場所は複数ありますが、今回はgit操作のガードをすべてのプロジェクトに効かせたいので、基本は~/.claude/settings.jsonに書きます。
プロジェクト毎に.claude/settings.jsonを配置すれば、そのプロジェクトだけで適用する運用もできます。
実装①:commit / push / ブランチ作成は「確認」させる(ask)
コミット・プッシュ・ブランチ作成は、禁止したいわけではありません。やってほしいけれど、勝手にやられたくない。こういう操作は ask(毎回確認)がちょうどよい塩梅です。
"ask": [
"Bash(git commit)",
"Bash(git commit:*)",
"Bash(git push)",
"Bash(git push:*)",
"Bash(git checkout -b:*)",
"Bash(git switch -c:*)",
"Bash(git branch:*)"
]
こう設定しておくと、Claude Codeが対象のコマンドを実行しようとしたタイミングで、次のように確認のプロンプトが出ます。
構文のコツがいくつかあります。
-
Bash(git push:*)は「git push + 任意の引数」にマッチする - 引数なしの素の
git pushは:*では拾えないので、bare形のBash(git push)も併記する
注意点として、Bash(git branch:*)はブランチ作成だけでなく、git branch -aのような一覧表示にもマッチします。globでは作成と一覧を区別できないため、一覧表示まで確認対象になってしまうトレードオフがあります。気になる場合は確認を許容するか、ルールを細かく書き分ける必要があります。
実装②:削除・破壊系は「完全禁止」する(deny)
取り返しがつかない操作は、確認(ask)では不十分です。確認プロンプトをうっかり通してしまえば終わりだからです。こうした操作は deny でブロックします。
"deny": [
"Bash(git branch -d:*)",
"Bash(git branch -D:*)",
"Bash(git push --delete:*)",
"Bash(git push -d:*)",
"Bash(git tag -d:*)",
"Bash(git tag --delete:*)",
"Bash(git rm:*)",
"Bash(git clean:*)",
"Bash(git stash drop:*)",
"Bash(git stash clear)",
"Bash(git remote remove:*)",
"Bash(git remote rm:*)",
"Bash(git reset --hard)",
"Bash(git reset --hard:*)",
"Bash(git checkout --:*)",
"Bash(git restore:*)"
]
大きく2系統に分けています。
- 削除系
- ブランチ削除(git branch -d / -D)、リモートブランチ削除(git push --delete / -d)
- タグ削除(git tag -d)、ファイル削除(git rm)、未追跡ファイル削除(git clean)
- stash破棄(git stash drop / clear)、リモート削除(git remote remove / rm)
- 破壊系
- 履歴・作業ツリーの破壊(git reset --hard)、変更の破棄(git checkout -- / git restore)
denyに入れた操作は、確認しても実行できません。正当な用途でどうしても実行したいときは、人間が手動実行することになります。
まとめ
二層で守る構図に整理できます。
- 指示文(CLAUDE.md) = お願い。強制力は弱いが、意図や文脈を伝えられる
- permissions = 強制ガード。宣言的に効くが、表現の網羅には限界がある
線引きの指針はシンプルです。askは「確認したい操作」、denyは「絶対にやられたくない操作」。あとは自分の運用に合わせて調整していくのがよいと思います。完璧は狙えませんが、ヒヤッとする瞬間を確実に減らせます。
定期的に棚卸しすることも重要です。allow / ask / denyを見直し、不要になったルールや広すぎるルールを整理しましょう。
最後に、ここまでのask / denyをまとめた設定全体を載せておきます。
"permissions": {
"allow": [],
"ask": [
"Bash(git commit)",
"Bash(git commit:*)",
"Bash(git push)",
"Bash(git push:*)",
"Bash(git checkout -b:*)",
"Bash(git switch -c:*)",
"Bash(git branch:*)"
],
"deny": [
"Bash(git branch -d:*)",
"Bash(git branch -D:*)",
"Bash(git push --delete:*)",
"Bash(git push -d:*)",
"Bash(git tag -d:*)",
"Bash(git tag --delete:*)",
"Bash(git rm:*)",
"Bash(git clean:*)",
"Bash(git stash drop:*)",
"Bash(git stash clear)",
"Bash(git remote remove:*)",
"Bash(git remote rm:*)",
"Bash(git reset --hard)",
"Bash(git reset --hard:*)",
"Bash(git checkout --:*)",
"Bash(git restore:*)"
]
}
参考文献
