Claude Code Hooks入門: 作業前後の自動チェックで事故を減らす実務ガイド
Claude Code Hooksを初心者向けに解説。禁止コマンド防止、ログ保存、format/test自動実行まで現場で使える形にします。
Claude Code Hooksは、ひと言でいうと「Claudeが作業する前後に走る自動チェック」です。人間が毎回「そのコマンド危なくない?」「保存したあとにformatした?」「テストを回した?」と確認する代わりに、Claude Codeの作業タイミングへ小さなガードレールを置けます。
初心者が最初に覚えるべきことは、Hooksは魔法の自動化ではなく、作業を止める場所と記録する場所を決める仕組みだという点です。危ないBashを止めるなら PreToolUse、編集後にformatやtestを走らせるなら PostToolUse、依頼文を記録するなら UserPromptSubmit、最後の返答を点検するなら Stop が向いています。
この記事では、Claude Code Hooks公式リファレンス と Claude Code settings公式ドキュメント を前提に、実務でそのまま試せる .claude/settings.json と小さなNode.jsスクリプトをまとめます。権限設計の全体像は Claude Code権限設定ガイド、プロジェクト文脈の置き方は CLAUDE.mdベストプラクティス も合わせて読むとつながります。
Hooksで最初に理解する4つのイベント
Hooksには多くのイベントがありますが、最初から全部を覚える必要はありません。事故防止と品質改善に効くのは、まず次の4つです。
| イベント | 使いどころ | 例 |
|---|---|---|
UserPromptSubmit | ユーザーの依頼がClaudeへ渡る前 | 依頼内容をログに残す、秘密情報っぽい文字列を警告する |
PreToolUse | ツール実行の直前 | rm -rf や本番DB操作を止める |
PostToolUse | ツール実行の直後 | 編集後にformat、lint、関連テストを走らせる |
Stop | Claudeの応答終了時 | 未完了タスクやテスト未実行を確認する |
PreToolUse はブレーキ、PostToolUse は整備、UserPromptSubmit は受付記録、Stop は退出前チェック、と考えると理解しやすいです。特に自動化に慣れていないチームでは、最初から全部をブロックするより、まずログ保存とformatから始めるのが安全です。
設定ファイルは基本的に .claude/settings.json に置きます。個人の実験だけなら .claude/settings.local.json に置く手もありますが、チームで共有したい品質ルールはプロジェクト側に置いたほうが再現しやすくなります。公式ドキュメントでは、設定はユーザー、プロジェクト、ローカル、管理ポリシーなど複数スコープで扱われるため、どこに置いたHookなのかをコメントやREADMEで明示しておくと混乱が減ります。
まず入れる最小構成
最初の設定は、危険コマンド防止、編集ログ、編集後チェックの3つだけで十分です。以下を .claude/settings.json に置きます。スクリプトは後続セクションで作ります。
{
"hooks": {
"UserPromptSubmit": [
{
"hooks": [
{
"type": "command",
"command": "node .claude/hooks/log-prompt.mjs"
}
]
}
],
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "node .claude/hooks/block-dangerous-command.mjs"
}
]
}
],
"PostToolUse": [
{
"matcher": "Edit|Write|MultiEdit",
"hooks": [
{
"type": "command",
"command": "node .claude/hooks/run-quality-checks.mjs",
"timeout": 120
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "node .claude/hooks/stop-summary.mjs"
}
]
}
]
}
}
ポイントは、Hookごとに役割を分けることです。PreToolUse にformatやtestまで詰め込むと、ツール実行前に時間がかかりすぎます。逆に PostToolUse で危険コマンドを止めようとしても、実行後なので遅いです。どのタイミングで止めたいのか、どのタイミングなら記録だけでよいのかを分けると、運用が安定します。
実例1: 禁止コマンドをPreToolUseで止める
最初のユースケースは、Bash実行前の事故防止です。Claude Codeに大きな変更を任せると、削除、移動、環境変数、デプロイ周りのコマンドが混ざることがあります。全部を疑う必要はありませんが、rm -rf /、.env の表示、本番DBの破壊的操作のようなものは、実行前に止めたいです。
.claude/hooks/block-dangerous-command.mjs を作ります。
import fs from "node:fs";
const input = JSON.parse(fs.readFileSync(0, "utf8") || "{}");
const command = String(input.tool_input?.command || "");
const denyPatterns = [
/rm\s+-rf\s+(\/|\*|\.|\$HOME)/i,
/cat\s+\.env(\.|$|\s)/i,
/printenv/i,
/aws\s+.*\s+delete-/i,
/gcloud\s+.*\s+delete/i,
/kubectl\s+delete\s+(namespace|deployment|secret)/i,
/DROP\s+DATABASE/i
];
const matched = denyPatterns.find((pattern) => pattern.test(command));
if (matched) {
console.log(JSON.stringify({
hookSpecificOutput: {
hookEventName: "PreToolUse",
permissionDecision: "deny",
permissionDecisionReason: `Blocked by project hook: ${matched}`
}
}));
process.exit(0);
}
このスクリプトは、Hookの標準入力からJSONを読み、tool_input.command を見ています。危険なパターンに当たったら permissionDecision: "deny" を返します。公式リファレンスでも、PreToolUse はツール実行前に判断を返せるイベントとして説明されています。
ここで大事なのは、完璧なセキュリティ製品を作ろうとしないことです。正規表現だけで全ての危険操作を防ぐのは無理です。それでも、明らかに危ない操作を一段止められるだけで、初心者チームの事故率はかなり下がります。より厳密にするなら、権限設定ガイド の permissions.deny と組み合わせてください。
実例2: UserPromptSubmitで依頼をログ保存する
2つ目のユースケースは、依頼文のログ保存です。Claude Codeの作業品質が安定しないとき、原因はコードではなく最初の依頼文にあることが多いです。「ざっくり直して」「いい感じにして」だけだと、Claudeは何を成功条件にすればよいか迷います。
UserPromptSubmit で依頼を保存しておくと、あとから「どの依頼で壊れたのか」「どの書き方だと成功したのか」を振り返れます。
import fs from "node:fs";
import path from "node:path";
const input = JSON.parse(fs.readFileSync(0, "utf8") || "{}");
const dir = path.join(process.cwd(), ".claude", "hook-logs");
fs.mkdirSync(dir, { recursive: true });
const record = {
time: new Date().toISOString(),
event: input.hook_event_name,
cwd: input.cwd,
prompt: input.prompt || input.user_prompt || ""
};
fs.appendFileSync(
path.join(dir, "prompts.jsonl"),
JSON.stringify(record) + "\n",
"utf8"
);
このログは外部送信しません。まずはプロジェクト内にJSON Linesで残すだけです。秘密情報を扱う可能性がある会社では、ログ保存そのものがリスクになるため、.claude/hook-logs/ を .gitignore に入れ、保存期間も決めておくべきです。
Masaの実務感としては、依頼ログがあるだけで改善スピードが上がります。失敗した回を見返すと、「修正対象のファイル名を書いていない」「テスト条件を書いていない」「やってほしくないことを書いていない」という原因がすぐ見つかるからです。
実例3: PostToolUseでformatとtestを自動実行する
3つ目のユースケースは、編集後の品質チェックです。Claudeがファイルを書き換えた直後にformat、lint、テストを走らせます。これはHooksの中でも体感効果が大きいです。人間が「最後にformatして」と毎回言わなくてよくなります。
.claude/hooks/run-quality-checks.mjs の例です。
import fs from "node:fs";
import { execFileSync } from "node:child_process";
const input = JSON.parse(fs.readFileSync(0, "utf8") || "{}");
const filePath = String(input.tool_input?.file_path || "");
const isSourceFile = /\.(js|jsx|ts|tsx|css|md|mdx|json)$/.test(filePath);
if (!isSourceFile) process.exit(0);
const run = (cmd, args) => {
try {
return execFileSync(cmd, args, {
cwd: process.cwd(),
encoding: "utf8",
stdio: ["ignore", "pipe", "pipe"]
});
} catch (error) {
return String(error.stdout || "") + String(error.stderr || "");
}
};
const messages = [];
messages.push(run("npx", ["prettier", "--write", filePath]));
if (/\.(js|jsx|ts|tsx)$/.test(filePath)) {
messages.push(run("npm", ["test", "--", "--runInBand"]));
}
console.log(JSON.stringify({
hookSpecificOutput: {
hookEventName: "PostToolUse",
additionalContext: messages.join("\n").slice(-4000)
}
}));
このサンプルは、小さなプロジェクト向けです。大きなリポジトリで毎回 npm test を走らせると重くなります。その場合は、変更ファイルに関連するテストだけに絞る、async: true にしてバックグラウンド実行する、CIに任せる範囲を決める、といった調整が必要です。
重要なのは、失敗結果をClaudeに返すことです。additionalContext にテスト結果を渡すと、Claudeは次の応答で「どのエラーを直すべきか」を理解しやすくなります。ただし、出力が長すぎるとコンテキストを圧迫するので、最後の4000文字だけ返すなど上限を決めます。
実例4: Stopで終わる前に未完了を確認する
Stop はClaudeが返答を終えるタイミングで走ります。ここでは重いテストを毎回走らせるより、作業メモや差分の状態を点検する使い方が向いています。
import fs from "node:fs";
import { execFileSync } from "node:child_process";
const input = JSON.parse(fs.readFileSync(0, "utf8") || "{}");
if (input.stop_hook_active) {
process.exit(0);
}
let status = "";
try {
status = execFileSync("git", ["status", "--short"], {
cwd: process.cwd(),
encoding: "utf8"
});
} catch {
process.exit(0);
}
if (status.includes("UU ")) {
console.error("Git conflict remains. Resolve conflicts before finishing.");
process.exit(2);
}
fs.mkdirSync(".claude/hook-logs", { recursive: true });
fs.appendFileSync(
".claude/hook-logs/stop.jsonl",
JSON.stringify({
time: new Date().toISOString(),
lastAssistantMessage: input.last_assistant_message || "",
gitStatus: status.slice(0, 2000)
}) + "\n"
);
Stop でブロックしすぎると、Claudeが終われないループになります。公式リファレンスでも stop_hook_active を見て再入を避ける考え方が示されています。最初は「競合が残っているときだけ止める」「それ以外はログ保存だけ」に留めるのが現実的です。
落とし穴:よくある失敗と回避策
Hooksの失敗例はだいたい決まっています。
1つ目は、Hookに権限を持たせすぎることです。Command hookは自分のユーザー権限で動きます。つまり、間違ったスクリプトはファイル削除も秘密情報の読み取りもできます。Hookは安全装置ですが、同時に危険な自動実行でもあります。入力を信用しない、パスに .. が含まれる場合は止める、.env や .git は触らない、という基本を入れてください。
2つ目は、遅いHookを同期実行してしまうことです。PostToolUse で毎回フルテスト、型チェック、ビルド、デプロイまで走らせると、Claudeの作業が止まります。重い処理は async: true を検討し、ブロックが必要な処理だけ同期に残します。
3つ目は、ログに秘密情報を残すことです。依頼文やコマンドにはAPIキー、顧客名、社内URLが混ざることがあります。ログを残すなら保存場所、gitignore、保存期間、閲覧権限までセットで決めます。
4つ目は、Hookで承認フローを迂回できると思い込むことです。Hookは便利ですが、Claude Codeの権限設定やレビューを置き換えるものではありません。危険操作は permissions.deny、人間の承認、CIの保護ルールと組み合わせて多層にしてください。
Masaの検証メモ
この記事で紹介した内容を実際に試した結果、いちばん効果があったのは「危険コマンドの事前ブロック」よりも「編集後にformat/test結果をClaudeへ返す」部分でした。Claudeが次の一手を自分で修正しやすくなり、こちらが毎回ログを貼り直す回数が減ります。
一方で、Stop hookに厳しい条件を入れすぎると、作業が終わらない感じになります。初心者向けには、最初の1週間は UserPromptSubmit のログ保存と PostToolUse のformatだけで運用し、慣れてから PreToolUse のブロック条件を足す流れがよさそうです。
この設計をチーム導入したい場合は、Claude Code研修ページ で「権限設定、CLAUDE.md、Hooks、レビュー手順」をまとめて整備する相談ができます。まず自分で試したい人向けには、Gumroadの商品テンプレートからチェックリスト化して使える形にしていく予定です。
まとめ
Claude Code Hooksは、Claudeに作業を任せるための足場です。PreToolUse で危険操作を止め、PostToolUse でformatとtestを走らせ、UserPromptSubmit で依頼を記録し、Stop で終わる前の状態を確認します。
最初から完璧な自動化を目指す必要はありません。小さく始めて、ログを見て、よく起きる失敗だけをHookに移す。この順番なら、Claude Codeの速度を落としすぎず、チームの安心感も上げられます。
無料PDF: Claude Code はじめてのチートシート
まずは無料PDFで基本コマンドと最初の使い方をまとめて確認してください。登録後はそのままテンプレート集や導入相談にも進めます。
スパムは送りません。登録情報は厳重に管理します。
Claude Codeを仕事で使える形にしませんか?
無料PDFで基礎を固めたあと、すぐ使えるテンプレート集で試し、必要なら業務自動化や導入相談まで進められます。
この記事を書いた人
Masa
Claude Codeの実務活用、導入設計、収益導線改善を検証しているエンジニア。10言語の技術メディアを運営中。
関連書籍・参考図書
この記事のテーマに関連する書籍を楽天ブックスで探せます。
※ 当サイトは楽天市場のアフィリエイトプログラムに参加しています。上記リンクから商品をご購入いただくと、運営者に紹介料が支払われる場合があります。
関連記事
Claude Code Permission Receipt Pattern: 許可、証拠、ロールバックを残す運用
Claude Codeの権限運用を安全にする permission receipt。許可範囲、承認待ち、検証コマンド、CTA導線を記録します。
Claude CodeとCodex、結局どっち?事故らない“併用”の現実解
OpenAIのCodexとClaude Code、どっちが得意でどっちに任せる?両方を安全に併用する作業分担と権限・検証のワークフローを、僕の失敗談つきで解説します。
Claude Codeサブエージェント実装ガイド: 記事・コード作業を安全に並列委譲する方法
Claude Codeサブエージェントで記事・コード作業を安全に並列化する実装ガイド。委譲基準、プロンプト、失敗例を解説。