Claude Codeのパーミッションプロンプトを設計する——allowlistとsettings.jsonで確認頻度を最適化する
Claude Codeのパーミッションプロンプトが頻繁に出て作業が止まる問題を解決する。settings.jsonのallowlist設定、プロジェクト別権限とグローバル権限の使い分け、危険コマンドは残しつつ安全なコマンドを通す設計パターンを実装例付きで解説。
エンジニアのゆとです。
Claude Codeを使い始めた直後の感想として「確認ダイアログが多すぎる」という話をよく聞く。
ファイルを読むたびに「許可しますか?」、コマンドを実行するたびに「これは安全ですか?」——作業のリズムが完全に崩れる。
かといって全部許可すると今度はセキュリティが心配になる。
このトレードオフをどう設計するかを整理した。自分がyuto-lab.comの運用で実際に使っているsettings.json構成を全部公開する。
Claude Codeのパーミッション設計の基本
Claude Codeのパーミッションは2つの軸で管理されている。
スコープの軸
- グローバル設定(
~/.claude/settings.json): 全プロジェクトに適用 - プロジェクト設定(
.claude/settings.json): そのプロジェクトのみ適用
許可の軸
allow: 確認なしで実行OKdeny: 実行禁止- デフォルト: 都度確認ダイアログ
settings.jsonの基本構造
{
"permissions": {
"allow": [
"Bash(git status)",
"Bash(git diff*)",
"Read(**)"
],
"deny": [
"Bash(rm -rf *)",
"Bash(sudo *)"
]
}
}
allowlistはglobパターンで書ける。* が「何でも」、** が「パスを含めた何でも」。
グローバルとプロジェクトの分け方
自分の運用方針はシンプルだ。
グローバル設定(~/.claude/settings.json)に書くもの
- どのプロジェクトでも安全と判断できるコマンド
- 読み込み系・情報表示系のコマンド
- git の参照系コマンド
プロジェクト設定(.claude/settings.json)に書くもの
- そのプロジェクト固有の書き込み系コマンド
- 特定のスクリプト実行
- 他のプロジェクトでは許可したくないコマンド
実際のグローバル設定
{
"permissions": {
"allow": [
"Read(**)",
"Bash(ls*)",
"Bash(pwd)",
"Bash(echo *)",
"Bash(cat *)",
"Bash(head *)",
"Bash(tail *)",
"Bash(wc *)",
"Bash(date *)",
"Bash(which *)",
"Bash(git status)",
"Bash(git log*)",
"Bash(git diff*)",
"Bash(git branch*)",
"Bash(git show*)",
"Bash(git remote*)",
"Bash(launchctl list*)",
"Bash(ps aux*)",
"Bash(df *)",
"Bash(du *)"
],
"deny": [
"Bash(sudo rm*)",
"Bash(rm -rf /)",
"Bash(sudo mkfs*)",
"Bash(sudo dd*)",
"Bash(curl * | bash*)",
"Bash(wget * | sh*)"
]
}
}
「読む」「確認する」コマンドは全部グローバルで通す。「書く」「消す」系は都度確認かdeny。
ブログプロジェクトの実際の設定
{
"permissions": {
"allow": [
"Bash(npm run build*)",
"Bash(npm run dev*)",
"Bash(npx astro*)",
"Bash(git add src/content/blog/*)",
"Bash(git add src/assets/*)",
"Bash(git commit*)",
"Bash(git push origin main)",
"Bash(python3 scripts/gen_thumb_gpt.py*)",
"Bash(python3 scripts/auto_publish.py*)",
"Write(src/content/blog/**)",
"Write(src/assets/**)"
]
}
}
ブログプロジェクトでやること(ビルド・記事追加・サムネ生成・push)に絞っている。git push origin main はプロジェクト設定に書くので、他リポジトリへの誤pushは起きない。
パターン別設計指針
パターン1: 読み取り専用プロジェクト
レポジトリ分析や調査目的でClaudeを使う場合。
{
"permissions": {
"allow": ["Read(**)", "Bash(git log*)", "Bash(git diff*)", "Bash(grep*)", "Bash(find*)"],
"deny": ["Write(**)", "Bash(git commit*)", "Bash(git push*)"]
}
}
書き込みをdenyに入れると、事故的なファイル変更を完全に防げる。
パターン2: フルオートメーション用プロジェクト
自動化スクリプトを動かすプロジェクト。確認を最小化したい。
{
"permissions": {
"allow": [
"Read(**)",
"Write(**)",
"Bash(python3 *)",
"Bash(node *)",
"Bash(git *)",
"Bash(npm *)"
],
"deny": [
"Bash(sudo *)",
"Bash(rm -rf /)",
"Bash(curl * | *)"
]
}
}
システムレベルの操作(sudo)とパイプ経由の実行(curl | bash)だけはdenyに残す。
パターン3: 本番環境があるプロジェクト
デプロイコマンドや本番DBへの接続があるプロジェクト。
{
"permissions": {
"allow": [
"Read(**)",
"Write(src/**)",
"Bash(npm run test*)",
"Bash(npm run build*)"
],
"deny": [
"Bash(npm run deploy*)",
"Bash(*production*)",
"Bash(psql *prod*)"
]
}
}
本番環境に触れるコマンドは明示的にdenyに入れる。テスト・ビルドはOK、デプロイは手動確認必須。
Hooksと組み合わせる
パーミッション設定だけでなく、Hooksの PreToolUse でより細かい制御もできる。
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "bash /path/to/check_dangerous.sh"
}
]
}
]
}
}
#!/bin/bash
# check_dangerous.sh — 危険コマンドをブロック
TOOL_INPUT="$TOOL_INPUT_COMMAND"
# 本番環境へのアクセスを全ブロック
if echo "$TOOL_INPUT" | grep -qE "(production|prod-db|DROP TABLE)"; then
echo '{"decision": "block", "reason": "本番環境への操作は手動で実行してください"}'
exit 0
fi
echo '{"decision": "approve"}'
Hooksはコマンドの内容を動的に検査できるので、「特定のキーワードを含む場合だけブロック」という柔軟な制御が可能。パーミッション設定のglobパターンでは実現できない条件を補完できる。
よくある誤設定と対策
誤設定1: Bash(*) でBash全許可
// これはやめる
"allow": ["Bash(*)"]
rm -rf * も sudo も全部通ってしまう。「Bashは全部OK」は危険すぎる。
誤設定2: denyが機能していない
// allowにワイルドカードがあるとdenyが無意味になる場合がある
"allow": ["Bash(*git*)"],
"deny": ["Bash(git push origin main)"]
allowが広すぎてdenyが負けるケース。Claude Codeの評価順はallow優先なので、より具体的なパターンでdenyを書く必要がある。
誤設定3: グローバルに書きすぎる
プロジェクト固有の書き込み許可をグローバルに書くと、全プロジェクトでその権限が有効になる。
// グローバルに書くのはNG
"allow": ["Write(src/content/blog/**)"]
プロジェクトのsettings.jsonに書く。
設定のメンテナンス
実際に運用していると「このコマンドがよく確認される」という傾向が分かってくる。
Claude Codeには /permissions コマンドで現在の設定を確認できる機能がある。確認が多いコマンドを定期的にallowlistに追加して最適化していくのが現実的な運用法だ。
また、セキュリティ感度の高いプロジェクト(本番DB、APIキーが含まれる処理)はあえてallowlistを絞って、確認ダイアログを「安全のトリガー」として残すのも一つの判断だ。
「確認が多くて鬱陶しい」は解決できるが、「確認を全部消す」のが正解ではない。
記事が見つかりません:
記事が見つかりません:
記事が見つかりません: