メインコンテンツへスキップ
見出し画像

1行のrm -rfで全消失|9割が知らないHooks19連ガード

    あなたが許可プロンプトを1回ずつ目で追っている間に、同じClaude Codeを使う側は19個の禁止パターンを物理的に塞いで席を離れている。

    差はスキルではない。設定ファイル1枚だ。

    この記事は、その1枚を今日埋めるための全文を渡す。

    事故は「判断ミス」ではなく「設定の不在」で起きる

    Claude Codeは確率的に動く。だから`rm -rf`や`git reset --hard`を提案する確率は0にならない。

    permissionsのallow/denyは強力だが、人間の確認を前提にした仕組みだ。autoモードや`-p`の無人実行では、確認する人間が席にいない。

    ここで起きるのは「Claudeが暴走した」ではない。止める経路を誰も作らなかったという結果だ。

    失うものは具体的だ。`git reset --hard`は未コミットの作業を丸ごと消す。`git push --force`は共同作業者の履歴を書き換える。`.env`の上書きは本番の接続情報を消す。

    どれも「あとで直す」ができない操作だ。そして3つとも、設定2行で経路を塞げる。

    止めるべきはClaudeの判断ではなく、操作そのものの経路。


    これを担うのがHooksだ。ユーザーが定義したコマンドを、Claude Codeがライフサイクルの特定点で必ず実行する。

    LLMが「実行しようと思うか」には依存しない。公式リファレンスはこれを決定論的な制御(deterministic control)と明記している。

    フックイベントは33種類。日本語記事で見るのは5つだけ

    2026年10月8日時点の公式リファレンスに載るフックイベントは33種類ある。

    PreToolUse / PostToolUse / UserPromptSubmit / Stop / SessionStart。解説記事で見かけるのはこの5つで止まる。残り28個に、事故を止める本体が入っている。

    • `PermissionRequest`: 許可ダイアログが出る直前に割り込み、allow/denyを自動で返す

    • `PermissionDenied`: autoモードが拒否した瞬間を記録する

    • `FileChanged`: 誰が書いたかに関係なく、監視ファイルの変更で発火する

    • `ConfigChange`: 設定ファイル自体の書き換えをexit 2で止める

    • `TaskCompleted`: テストが通るまでタスクを閉じさせない

    • `PreCompact`: 圧縮で消える前に全文を退避する

    5つしか知らないと、PreToolUseだけで全部やろうとする。そしてシェル経由のファイル書き込みを取りこぼす。ここが最大の穴だ。

    なぜ誰もHooksを書かないのか

    機能は公式に用意されている。それでも入れていない環境が多い理由は3つに絞れる。

    1つ目は優先順位が読み取れないこと。33イベントは公式リファレンスに平等に並んでいる。「どれを最初に入れると事故が止まるか」は、そこには書かれていない。

    2つ目はバージョンで挙動が変わること。exit 2とJSON出力の優先関係はv2.1.214で、PreToolUseのタイムアウト扱いはv2.1.210で変わった。半年前の解説をコピペすると、ブロックしたつもりで素通りする。

    3つ目が最悪だ。設定を間違えたフックは、エラーを出さずに静かに無効化される。`if`をツール系以外のイベントに付けた場合も、matcherに括弧を書いて正規表現として解釈された場合も、画面には何も出ない。

    「入れたつもり」が一番高くつく。発火の確認までやって初めて守りになる。


    実際に無人運用しているパイプラインのフックディレクトリには、スクリプトが17ファイル・合計2,308行入っている。そのうち最初に書くべき1本は決まっている。

    今日入れる最小の1本(.envと.gitを守る)

    まずこれだけで、最頻の事故は落ちる。`.claude/hooks/protect-files.sh`に保存する。

    bash
    #!/bin/bash

    protect-files.sh

    INPUT=$(cat)
    FILE_PATH=$(echo "$INPUT" | jq -r '.tool_input.file_path // empty')

    Windowsのバックスラッシュを正規化(これが無いとパターンが一致しない)

    FILE_PATH="${FILE_PATH//\//}"

    PROTECTED_PATTERNS=(".env" "package-lock.json" ".git/")

    for pattern in "${PROTECTED_PATTERNS[@]}"; do
    if [[ "$FILE_PATH" == "$pattern" ]]; then
    echo "Blocked: $FILE_PATH matches protected pattern '$pattern'" >&2
    exit 2
    fi
    done
    exit 0

    `.claude/settings.json`に登録する。macOSとLinuxでは`chmod +x`が必須で、忘れると起動しない。

    {
    "hooks": {
    "PreToolUse": [
    {
    "matcher": "Edit|Write",
    "hooks": [
    {
    "type": "command",
    "command": ""$CLAUDE_PROJECT_DIR"/.claude/hooks/protect-files.sh"
    }
    ]
    }
    ]
    }
    }

    `/hooks`と打てば、いま効いているフックがイベント別に一覧で出る。発火しない時は`claude --debug`、もしくはセッション中に`/debug`で理由が見える。

    ここまでが無料で渡す範囲だ。だがこの構成には3つの穴が残っている。exit 2とJSONの優先順位、matcherの文字判定、そしてシェル経由の抜け道だ。塞がないと「入れたつもり」で終わる。

     
     
    「Claude AI×副業で永続的な収益化を目指し中📝AI活用で日常業務を効率化しながら、実体験ベースのノウハウを発信。一緒に成長できる仲間募集🤖✨ #AI活用 #副業 #効率化」

    あなたへのおすすめ