問題: git logにも許可が要る
Claude Codeを自律モードで動かしていても、驚くほど頻繁に許可を求められる。
🔒 Bash: git log --oneline -5 — 許可しますか? [y/n]
🔒 Bash: ls src/ — 許可しますか? [y/n]
🔒 Bash: cat package.json — 許可しますか? [y/n]
🔒 Bash: grep "TODO" src/*.ts — 許可しますか? [y/n]
読むだけのコマンドに毎回yを押す。1分に10回。1時間で600回。これが「許可プロンプト疲れ(permission fatigue)」だ。
疲れるだけならまだいい。本当の問題はyを押す習慣がつくと、危険なコマンドもろくに読まずに承認してしまうこと。安全のための仕組みが、逆に安全性を下げている。
解決: PreToolUse hookで自動承認
Claude Codeのhook機能を使えば、安全なコマンドだけを自動承認できる。
仕組みはシンプル:
- Claude Codeがツールを使う直前に
PreToolUsehookが発火する - hookスクリプトがコマンドの中身を見る
- 安全だと判断したら
exit 0+ 承認JSONを返す - 危険なコマンドはスルー(
exit 0のみ)→ 通常の許可フローへ
Claude Code → PreToolUse hook → 安全? → YES → 自動承認(許可プロンプトなし)
→ NO → 通常の許可プロンプト
パターン1: 読み取り系コマンドの自動承認
最も効果が高い。cat, ls, grep, git statusなど、何も変更しないコマンドを一括で自動承認する。
~/.claude/hooks/auto-approve-readonly.sh:
#!/bin/bash
COMMAND=$(cat | jq -r '.tool_input.command // empty' 2>/dev/null)
[ -z "$COMMAND" ] && exit 0
# 先頭コマンドを取り出す
BASE=$(echo "$COMMAND" | awk '{print $1}' | sed 's|.*/||')
case "$BASE" in
cat|head|tail|less|more|wc|grep|rg|find|locate|\
ls|tree|stat|file|which|whereis|type|\
date|uptime|uname|hostname|whoami|id|env|pwd|df|du)
echo '{"decision":"approve","reason":"Read-only command"}'
exit 0
;;
esac
# git の読み取りサブコマンド
if echo "$COMMAND" | grep -qE '^\s*git\s+(status|log|diff|show|branch|remote|tag\s+-l|blame|ls-files)\b'; then
echo '{"decision":"approve","reason":"Read-only git command"}'
exit 0
fi
exit 0
settings.jsonへの登録:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "bash ~/.claude/hooks/auto-approve-readonly.sh"
}]
}
]
}
}
これだけで許可プロンプトの60〜80%が消える。
パターン2: ビルド・テスト系の自動承認
開発ワークフローで頻繁に実行される npm test や npm run build も自動承認すると快適になる。
~/.claude/hooks/auto-approve-build.sh:
#!/bin/bash
COMMAND=$(cat | jq -r '.tool_input.command // empty' 2>/dev/null)
[ -z "$COMMAND" ] && exit 0
# npm/yarn/pnpm のビルド・テスト・lint
if echo "$COMMAND" | grep -qE '^\s*(npm|yarn|pnpm)\s+(run\s+)?(build|test|lint|check|typecheck|format|ci)\b'; then
echo '{"decision":"approve","reason":"Build/test command"}'
exit 0
fi
# pytest, cargo test, go test
if echo "$COMMAND" | grep -qE '^\s*(pytest|python3?\s+-m\s+pytest|cargo\s+test|go\s+test|make\s+(build|test))\b'; then
echo '{"decision":"approve","reason":"Test runner"}'
exit 0
fi
exit 0
なぜビルド系は別hookにするのか
読み取り系と分離する理由は粒度のコントロール。プロジェクトによっては npm run build が外部リソースにアクセスしたり、ファイルを大量に生成したりする。そういうプロジェクトではビルド系hookだけ外せばいい。
パターン3: プロジェクト内ファイル操作の自動承認
Claude Codeの Edit や Write ツールも許可を求めてくる。src/ 配下のファイル操作だけを自動承認するhook:
~/.claude/hooks/auto-approve-project-edit.sh:
#!/bin/bash
INPUT=$(cat)
TOOL=$(echo "$INPUT" | jq -r '.tool_name // empty' 2>/dev/null)
# Edit/Write ツールだけを対象にする
case "$TOOL" in
Edit|Write) ;;
*) exit 0 ;;
esac
FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty' 2>/dev/null)
[ -z "$FILE_PATH" ] && exit 0
# src/ 配下のファイルのみ自動承認
if echo "$FILE_PATH" | grep -qE '^(src|lib|test|tests|__tests__)/'; then
echo '{"decision":"approve","reason":"Project source file"}'
exit 0
fi
exit 0
settings.jsonでは matcher を変えて登録する:
{
"matcher": "Edit|Write",
"hooks": [{
"type": "command",
"command": "bash ~/.claude/hooks/auto-approve-project-edit.sh"
}]
}
安全に保つルール: ブロックhookとの組み合わせ
自動承認だけでは危険だ。ブロックhookを先に配置して、危険な操作は確実に止める。
hookの評価順序
Claude Codeのhookは配列の順番に評価される。ブロック("decision":"block")が返ると、後続の自動承認hookは実行されない。
1. ブロックhook: rm -rf, git push --force, git reset --hard → 即ブロック
2. 自動承認hook: cat, ls, git log → 自動承認
3. どちらにも該当しない → 通常の許可プロンプト
ブロックhookの例 ~/.claude/hooks/block-destructive.sh:
#!/bin/bash
COMMAND=$(cat | jq -r '.tool_input.command // empty' 2>/dev/null)
[ -z "$COMMAND" ] && exit 0
# 絶対に自動実行させたくないコマンド
if echo "$COMMAND" | grep -qE 'rm\s+-rf\s+/|git\s+push\s+--force|git\s+reset\s+--hard'; then
echo '{"decision":"block","reason":"Destructive command blocked"}'
exit 0
fi
exit 0
settings.json 完全例
読み取り自動承認 + ビルド自動承認 + 破壊的コマンドブロックを組み合わせた完全な設定:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "bash ~/.claude/hooks/block-destructive.sh"
}]
},
{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "bash ~/.claude/hooks/auto-approve-readonly.sh"
}]
},
{
"matcher": "Bash",
"hooks": [{
"type": "command",
"command": "bash ~/.claude/hooks/auto-approve-build.sh"
}]
},
{
"matcher": "Edit|Write",
"hooks": [{
"type": "command",
"command": "bash ~/.claude/hooks/auto-approve-project-edit.sh"
}]
}
]
}
}
この設定のポイント
| 順番 | hook | 役割 |
|---|---|---|
| 1 | block-destructive |
rm -rf /, git push --force をブロック |
| 2 | auto-approve-readonly |
cat, ls, git log を自動承認 |
| 3 | auto-approve-build |
npm test, pytest を自動承認 |
| 4 | auto-approve-project-edit |
src/ 配下の Edit/Write を自動承認 |
ブロックが最優先。自動承認はその後。 どちらにも該当しないコマンドは従来通り許可プロンプトが表示される。
自分で書くのが面倒な場合
ここで紹介したパターンは全て cc-safe-setup に含まれている。
npx cc-safe-setup@latest
446のhookテンプレート(6,099テスト済み)から選んでインストールできる:
-
auto-approve-readonly.sh— 読み取り系コマンドの一括自動承認 -
auto-approve-git-read.sh— git読み取りコマンド特化(-Cフラグ対応) -
auto-approve-build.sh— ビルド・テスト・lint系 -
auto-approve-test.sh— テストランナー特化(Jest, pytest, cargo test, go test, PHPUnit, RSpec, JUnit, dotnet test) -
auto-mode-safe-commands.sh— Auto Modeの誤検知対策
また、hookの仕組みを体系的に学びたい方は Zenn Bookの「Claude Codeの安全運用ガイド」 も参考になる。
まとめ
| やること | 効果 |
|---|---|
| 読み取り系hookを入れる | 許可プロンプト60〜80%削減 |
| ビルド系hookを追加 | 開発ループがスムーズに |
| ブロックhookで安全弁 | 危険なコマンドは確実に止まる |
| 組み合わせて使う | 安全と快適の両立 |
「yを押す習慣」を作らないこと。安全なものは自動で通し、危険なものだけ人間が判断する。それがhookの正しい使い方だ。