Claude Code Hooks 從入門到實(shí)戰(zhàn)(附安全檢查+代碼質(zhì)量+Git工作流腳本)

昨天在知識(shí)星球會(huì)員群中,有人問(wèn)到了如何使用 Stop Hook 來(lái)讓 Claude 不打斷,而是繼續(xù)執(zhí)行。Claude Code 在 coding 方面能力有目共睹,不過(guò)有時(shí)候也確實(shí)會(huì)出現(xiàn)虎頭蛇尾的情況。

換句話說(shuō),新開(kāi)發(fā)的功能或者修改內(nèi)容看似完整實(shí)現(xiàn)了,但 Claude code 可能沒(méi)有主動(dòng)進(jìn)行測(cè)試,或者更新相關(guān)文檔,導(dǎo)致發(fā)現(xiàn)問(wèn)題后還要手動(dòng)再進(jìn)行多次交互,這個(gè)算是 AI coding 的最后一公里問(wèn)題,
我原本計(jì)劃空下來(lái)的時(shí)候先介紹 Claude Skills 的一些用例,不過(guò)還沒(méi)來(lái)及的整理完。這篇就借著這個(gè)問(wèn)題,來(lái)展開(kāi)介紹下 Claude hook 的一些常見(jiàn)實(shí)用方法,特別是 Stop Hook 是如何優(yōu)雅的解決此類問(wèn)題。
這篇試圖說(shuō)清楚:
Claude Code Hook 的快速掃盲、Hook 運(yùn)行機(jī)制拆解、Hook 配置三要素說(shuō)明以及三個(gè)實(shí)用的 Hook 用例參考。
以下,enjoy:
1、Hook 快速掃盲
一句話總結(jié),Claude Code Hooks 是在 Claude Code 特定時(shí)刻自動(dòng)執(zhí)行的腳本,讓你能對(duì) CC 的行為進(jìn)行確定性控制。先看個(gè)簡(jiǎn)單的案例:

感興趣的可以先看下官方文檔:https://docs.claude.com/en/docs/claude-code/hooks#hook-input。
1.1核心機(jī)制
Hook 在 Claude 認(rèn)為任務(wù)完成的時(shí)候自動(dòng)介入,執(zhí)行預(yù)設(shè)的檢查腳本(測(cè)試是否通過(guò)、代碼是否格式化、Changelog 是否更新、是否創(chuàng)建 PR 等)。全部完成則任務(wù)真正結(jié)束;發(fā)現(xiàn)遺漏的時(shí)候,Hook 會(huì)把具體的缺失項(xiàng)反饋給 Claude,Claude 能夠理解這些反饋并自動(dòng)補(bǔ)充收尾工作,補(bǔ)充后 Hook 再次檢查,形成閉環(huán)直到所有收尾工序完成。
1.2價(jià)值對(duì)比
沒(méi)有 Hook:你說(shuō)"重構(gòu)用戶模塊" → Claude 完成代碼 → 你說(shuō)"運(yùn)行測(cè)試" → 你說(shuō)"格式化代碼" → 你說(shuō)"更新 Changelog" → 你說(shuō)"創(chuàng)建 PR" → 需要 5 輪對(duì)話。
有 Hook:你說(shuō)"重構(gòu)用戶模塊" → Claude 完成代碼 → Hook 自動(dòng)發(fā)現(xiàn)缺少測(cè)試、格式化、Changelog → Claude 自動(dòng)補(bǔ)全所有收尾工序 → Hook 確認(rèn)通過(guò) → 1 輪對(duì)話完成。主打一個(gè)靠譜。
2、Hook 運(yùn)行機(jī)制拆解
Hook 腳本并不是簡(jiǎn)單的命令執(zhí)行,而是一個(gè)雙向通信過(guò)程:Claude Code 告訴 Hook 當(dāng)前狀態(tài),Hook 檢查后返回決定,告訴 Claude Code 是繼續(xù)還是阻止,以及具體原因。
2.1通信流程圖
下圖展示了 Hook 的完整通信過(guò)程,可以看到 4 個(gè)關(guān)鍵參與方和兩條路徑:

參與方
你:發(fā)起任務(wù)
Claude Code:管理生命周期,觸發(fā) Hook
Hook 腳本:執(zhí)行檢查邏輯
Claude AI:理解反饋并修正
成功路徑(上半部分)
Stop事件觸發(fā)后,Claude Code 發(fā)送當(dāng)前狀態(tài)給 Hook 腳本(通過(guò) stdin JSON)
Hook 運(yùn)行檢查(測(cè)試、格式化等)
檢查通過(guò),返回 exit code 0
任務(wù)完成
失敗路徑(下半部分)
Hook 檢查發(fā)現(xiàn)問(wèn)題
返回 exit code 2 + JSON 失敗原因(通過(guò) stderr)
Claude Code 將失敗原因顯示給 Claude AI
Claude AI 理解問(wèn)題并修正
繼續(xù)工作,再次觸發(fā) Stop Hook
此時(shí) stop_hook_active: true,Hook 再次檢查
通過(guò)后返回 exit code 0,任務(wù)完成
注意:stop_hook_active 標(biāo)志防止無(wú)限循環(huán),第一次可以阻止,第二次必須放行。
2.2輸入:Hook 接收什么信息?
Hook 腳本通過(guò) stdin(標(biāo)準(zhǔn)輸入) 接收 JSON 格式的當(dāng)前狀態(tài):
import json
import sys
# 讀取 Claude Code 傳來(lái)的狀態(tài)
input_data = json.loads(sys.stdin.read())JSON 內(nèi)容示例:
{
"session_id": "abc123",
"stop_hook_active": false, // 關(guān)鍵:防止無(wú)限循環(huán)
"tool_name": "Write",
"tool_input": {
"file_path": "src/main.py",
"content": "..."
}
}關(guān)鍵字段:
字段 | 含義 | 作用 |
stop_hook_active | 是否已強(qiáng)制繼續(xù)過(guò) | false=可以阻止,true=必須放行 |
tool_name | 觸發(fā)的工具 | 判斷是什么操作 |
tool_input | 工具參數(shù) | 獲取具體執(zhí)行內(nèi)容 |
tool_response | 工具結(jié)果 | PostToolUse 時(shí)可用 |
2.3輸出:Hook 如何返回決定?
Hook 腳本通過(guò)兩種方式告訴 Claude Code 檢查結(jié)果:
方式 1:退出碼(簡(jiǎn)單版)
import sys
# ? 檢查通過(guò)
sys.exit(0)
# ? 檢查失敗,阻止并反饋
sys.exit(2) # stderr 的內(nèi)容會(huì)發(fā)送給 Claude AI方式 2:JSON 響應(yīng)(精細(xì)版)
通過(guò) stderr(標(biāo)準(zhǔn)錯(cuò)誤輸出)返回 JSON,實(shí)現(xiàn)更精細(xì)的控制:
import json
import sys
response = {
"decision": "block", # 阻止繼續(xù)
"reason": "測(cè)試失敗: test_login, test_auth", # ? Claude 會(huì)讀取
"suppressOutput": False
}
print(json.dumps(response, ensure_ascii=False), file=sys.stderr)
sys.exit(2)JSON 字段說(shuō)明:
字段 | 適用場(chǎng)景 | 作用 |
decision | PreToolUse / Stop | "block"= 阻止操作/停止 |
reason | 所有 | Claude AI 會(huì)讀取并理解 |
continue | 所有 | false= 停止所有處理 |
suppressOutput | 所有 | 隱藏 stdout 輸出 |
備注:stdout:人類可讀的日志,方便調(diào)試;stderr:機(jī)器可讀的反饋,Claude AI 處理。
3、Hook 配置三要素梳理
一個(gè) Hook 配置需要回答三個(gè)問(wèn)題:什么時(shí)候觸發(fā)、針對(duì)什么操作、運(yùn)行什么腳本。
3.1事件類型(When - 什么時(shí)候觸發(fā))
Claude Code 目前支持 8 種生命周期事件:
事件 | 觸發(fā)時(shí)機(jī) | 典型用途 |
SessionStart | 會(huì)話開(kāi)始 | 加載項(xiàng)目上下文、初始化環(huán)境 |
UserPromptSubmit | 用戶提交提示詞前 | 注入額外信息、驗(yàn)證輸入 |
PreToolUse | 工具執(zhí)行前 | 阻止危險(xiǎn)命令、參數(shù)校驗(yàn) |
PostToolUse | 工具執(zhí)行后 | 自動(dòng)格式化、運(yùn)行 linter |
Notification | AI 發(fā)送通知時(shí) | 自定義提醒、日志記錄 |
Stop | AI 完成響應(yīng)時(shí) | 確保收尾工作、質(zhì)量門檻 |
SubagentStop | 子任務(wù)完成時(shí) | 子任務(wù)驗(yàn)證、結(jié)果串聯(lián) |
PreCompact | 上下文壓縮前 | 保存完整歷史、備份狀態(tài) |
3.2觸發(fā)條件(What - 針對(duì)什么操作)
可以用 matcher 精確控制哪些工具調(diào)用會(huì)觸發(fā) Hook:
{
"matcher": "Bash", // 只針對(duì) Bash 命令
"matcher": "Write|Edit", // 針對(duì)文件寫入或編輯
"matcher": "*", // 針對(duì)所有工具
"matcher": "" // 針對(duì)所有(Stop 等事件不需要 matcher)
}注意:matcher 只適用于 PreToolUse 和 PostToolUse 事件。對(duì)于 Stop、Notification 等事件,不需要指定 matcher。
3.3執(zhí)行動(dòng)作(How - 做什么)
指定要運(yùn)行的腳本或命令:
{
"type": "command",
"command": "python3 .claude/hooks/my_hook.py"
}支持的腳本類型:Python 腳本(.py)、Shell 腳本(.sh)、任何可執(zhí)行文件
配置多個(gè) Hook
{
"hooks": {
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "python3 .claude/hooks/test_check.py"
},
{
"type": "command",
"command": "python3 .claude/hooks/format_check.py"
}
]
}
]
}
}3.4完整配置示例
把以上三要素組合在 .claude/settings.json 中效果如下:
{
"hooks": {
"Stop": [ // 1?? 事件類型
{
"hooks": [ // 2?? Stop 不需要 matcher
{
"type": "command", // 3?? 執(zhí)行動(dòng)作
"command": "python3 .claude/hooks/stop_check.py"
}
]
}
],
"PreToolUse": [ // 另一個(gè)例子
{
"matcher": "Bash", // 2?? 只針對(duì) Bash 命令
"hooks": [
{
"type": "command", // 3?? 執(zhí)行動(dòng)作
"command": "python3 .claude/hooks/bash_check.py"
}
]
}
]
}
}配置說(shuō)明:
配置文件位置:.claude/settings.json(項(xiàng)目根目錄)
Hook 腳本位置:.claude/hooks/(約定俗成)
路徑推薦使用相對(duì)路徑,方便項(xiàng)目分享
4、三個(gè)實(shí)戰(zhàn)案例
光說(shuō)不練假把式,這里舉三個(gè)相對(duì)常見(jiàn)的用例做個(gè)參考。新手建議從案例 1 開(kāi)始,可以立即見(jiàn)效。案例 2 個(gè)人覺(jué)得最實(shí)用,可以顯著提升代碼質(zhì)量。最后案例 3適用企業(yè)級(jí)工作流中使用。
4.1案例 1: 阻止危險(xiǎn)操作
Claude 可能會(huì)不小心修改敏感文件(.env、密鑰文件),或執(zhí)行危險(xiǎn)命令(rm -rf),導(dǎo)致數(shù)據(jù)丟失或安全問(wèn)題。以下演示如何同時(shí)檢查文件操作和 Bash 命令,使用 matcher 只在相關(guān)工具上觸發(fā)。但不只是阻止,還提供替代方案。
項(xiàng)目結(jié)構(gòu)
your-project/
├── .claude/
│ ├── settings.json
│ └── hooks/
│ └── security_check.py
├── .env # 敏感文件
├── .env.example
└── src/
└── main.pyHook 配置
.claude/settings.json
{
"hooks": {
"PreToolUse": [
{
"matcher": "Edit|Write|MultiEdit",
"hooks": [
{
"type": "command",
"command": "python3 .claude/hooks/security_check.py"
}
]
},
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "python3 .claude/hooks/security_check.py"
}
]
}
]
}
}Hook 腳本
.claude/hooks/security_check.py
#!/usr/bin/env python3
"""
安全防護(hù) Hook - 阻止修改敏感文件和執(zhí)行危險(xiǎn)命令
完整代碼見(jiàn)知識(shí)星球
"""
import json
import sys
def check_sensitive_files(file_path):
"""檢查是否為敏感文件"""
SENSITIVE_FILES = [".env", "secrets.yaml", "private_key.pem", ".ssh/id_rsa"]
for sensitive in SENSITIVE_FILES:
if sensitive in file_path:
return False, f"?? 禁止修改敏感文件: {file_path}"
return True, None
def check_dangerous_commands(command):
"""檢查危險(xiǎn)命令"""
DANGEROUS_PATTERNS = ["rm -rf /", "rm -rf /*", "> /dev/sda", "chmod -R 777 /"]
for pattern in DANGEROUS_PATTERNS:
if pattern in command:
return False, f"?? 禁止執(zhí)行危險(xiǎn)命令: {command}"
return True, None
# ... 更多檢查邏輯和錯(cuò)誤處理見(jiàn)完整版完整代碼(150+ 行)包含:多文件編輯處理、白名單機(jī)制、友好的錯(cuò)誤提示、完整的錯(cuò)誤處理等,詳見(jiàn)知識(shí)星球。
添加執(zhí)行權(quán)限:
chmod +x .claude/hooks/security_check.py
4.2案例 2: 自動(dòng)格式化 + 測(cè)試檢查
Claude 完成代碼后經(jīng)常忘記格式化和運(yùn)行測(cè)試,導(dǎo)致代碼不規(guī)范、存在 bug。以下展示如何使用 PostToolUse 自動(dòng)格式化 + Stop 全面檢查,清晰顯示每項(xiàng)檢查結(jié)果。
項(xiàng)目結(jié)構(gòu)
your-project/
├── .claude/
│ ├── settings.json
│ └── hooks/
│ ├── auto_format.py # PostToolUse
│ └── quality_check.py # Stop
├── src/
│ └── *.py
├── tests/
│ └── test_*.py
└── requirements.txtHook 配置
.claude/settings.json:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write|MultiEdit",
"hooks": [
{
"type": "command",
"command": "python3 .claude/hooks/auto_format.py"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "python3 .claude/hooks/quality_check.py"
}
]
}
]
}
}Hook 腳本 1:自動(dòng)格式化.claude/hooks/auto_format.py為節(jié)省篇幅省略。
Hook 腳本 2:質(zhì)量檢查
.claude/hooks/quality_check.py:
#!/usr/bin/env python3
"""
代碼質(zhì)量檢查 Hook - 確保測(cè)試和格式化
完整代碼見(jiàn)知識(shí)星球
"""
import subprocess
import sys
def run_tests():
"""運(yùn)行測(cè)試套件"""
result = subprocess.run(
["python3", "-m", "pytest", "-v"],
capture_output=True,
text=True,
timeout=60
)
if result.returncode == 0:
return True, "? 所有測(cè)試通過(guò)"
else:
# 提取失敗的測(cè)試
failed = [line for line in result.stdout.split('\n') if 'FAILED' in line]
return False, f"? 測(cè)試失敗\n" + "\n".join(failed[:5])
def check_format():
"""檢查代碼格式"""
result = subprocess.run(
["python3", "-m", "black", "--check", "src/"],
capture_output=True,
timeout=30
)
return result.returncode == 0, "? 格式規(guī)范" if result.returncode == 0 else "? 需要格式化"
# ... 完整的質(zhì)量門檻、lint 檢查、stop_hook_active 處理見(jiàn)完整版使用 subprocess 調(diào)用測(cè)試工具(pytest),使用 subprocess 調(diào)用格式化工具(black),收集所有檢查結(jié)果,有問(wèn)題則返回 exit 2 + JSON 詳情。
完整代碼(300+ 行)包含:自動(dòng)格式化腳本、多工具降級(jí)支持(pytest/unittest/black/autopep8)、lint 檢查、覆蓋率檢查、完整的錯(cuò)誤處理等,詳見(jiàn)知識(shí)星球。
添加執(zhí)行權(quán)限:
chmod +x .claude/hooks/auto_format.py
chmod +x .claude/hooks/quality_check.py
4.3案例 3: Git 提交工作流 - 完整質(zhì)量門檻
團(tuán)隊(duì)協(xié)作當(dāng)中,代碼提交前需要通過(guò)多項(xiàng)檢查,包括提交信息規(guī)范、代碼質(zhì)量、測(cè)試通過(guò)等。以下演示如何使用 PreToolUse 快速檢查 + Stop 完整檢查實(shí)現(xiàn)分層檢查。強(qiáng)制 Conventional Commits 格式,致命錯(cuò)誤阻止,警告提示但不阻止,禁止直接提交到 main/master。
項(xiàng)目結(jié)構(gòu)
your-project/
├── .claude/
│ ├── settings.json
│ └── hooks/
│ ├── pre_commit.py # PreToolUse (git commit)
│ └── final_check.py # Stop
├── src/
├── tests/
└── .git/Hook 配置
.claude/settings.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "python3 .claude/hooks/pre_commit.py"
}
]
}
],
"Stop": [
{
"hooks": [
{
"type": "command",
"command": "python3 .claude/hooks/final_check.py"
}
]
}
]
}
}Hook 腳本 1:提交前檢查
.claude/hooks/pre_commit.py:
#!/usr/bin/env python3
"""
Git 提交前檢查 Hook - 驗(yàn)證提交信息和分支
完整代碼見(jiàn)知識(shí)星球
"""
import re
import subprocess
def check_commit_message(command):
"""檢查提交信息格式(Conventional Commits)"""
match = re.search(r'-m\s+["\'](.+?)["\']', command)
if not match:
return True, None
message = match.group(1)
# 格式:type(scope): subject
pattern = r'^(feat|fix|docs|style|refactor|test|chore)(\(.+?\))?: .{3,}'
if not re.match(pattern, message):
return False, (
f"? 提交信息不符合規(guī)范\n"
f"當(dāng)前:{message}\n"
f"要求:type(scope): subject\n"
f"示例:feat(auth): add user registration"
)
return True, None
def check_branch():
"""檢查當(dāng)前分支"""
result = subprocess.run(["git", "branch", "--show-current"], capture_output=True, text=True)
branch = result.stdout.strip()
if branch in ["main", "master", "production"]:
return False, f"? 禁止直接提交到 {branch} 分支"
return True, None
# ... 完整的未暫存檢查、測(cè)試運(yùn)行、最終檢查見(jiàn)完整版Hook 腳本 2:最終檢查:.claude/hooks/final_check.py,為節(jié)省篇幅省略
正則表達(dá)式驗(yàn)證 Conventional Commits 格式,Git 命令檢查當(dāng)前分支。阻止直接提交到主分支,提交前運(yùn)行快速測(cè)試。
完整代碼(400+ 行)包含:兩個(gè)完整 Hook 腳本(pre_commit.py + final_check.py)、未暫存文件檢查、完整測(cè)試套件、文檔檢查、調(diào)試代碼檢查、分層檢查機(jī)制等,詳見(jiàn)知識(shí)星球。
添加執(zhí)行權(quán)限:
chmod +x .claude/hooks/pre_commit.py
chmod +x .claude/hooks/final_check.py
5、寫在最后
5.1Skills VS Hooks
下篇介紹Claude Skills,其和Hooks定位完全不同。Skills 是教 Claude "怎么做好",通過(guò) Markdown 文檔傳授領(lǐng)域知識(shí)、工作流程、最佳實(shí)踐,Claude 會(huì)自動(dòng)判斷何時(shí)加載相關(guān) Skill 并參考執(zhí)行。而Hooks 則是強(qiáng)制 Claude "必須做對(duì)",在關(guān)鍵節(jié)點(diǎn)執(zhí)行腳本驗(yàn)證,不通過(guò)就物理阻止繼續(xù)。
Skills 是建議性的(Claude 理解后靈活應(yīng)用),Hooks 是確定性的(代碼說(shuō)了算)。實(shí)踐中兩者常常配合使用,Skills 提供方法論指導(dǎo),Hooks 確保最低質(zhì)量標(biāo)準(zhǔn)。
5.2對(duì)2B Agent 工程的參考
Claude Code 的 Skills 和 Hooks 機(jī)制,本質(zhì)上是在解決 AI Agent 的可控性和可靠性問(wèn)題,對(duì)構(gòu)建 2B Agent 也有很強(qiáng)的參考價(jià)值。
首先是分層控制架構(gòu),Skills(知識(shí)層)+ Hooks(控制層)的設(shè)計(jì)在2B Agent 中也應(yīng)該區(qū)分"建議性指導(dǎo)"和"強(qiáng)制性驗(yàn)證"。比如客服 Agent 可以有話術(shù) Skills 提供靈活的溝通方式,但敏感信息泄露、違規(guī)承諾等必須用 Hook 機(jī)制硬攔截。
其次,人機(jī)協(xié)同界面做法也值得借鑒。Hooks 的 stdin/stderr 通信模式,展示了一種清晰的人類意圖注入和 Agent 行為反饋機(jī)制。2B 場(chǎng)景中,決策透明度和可解釋性至關(guān)重要,類似的通信協(xié)議設(shè)計(jì)可以讓業(yè)務(wù)人員理解 Agent 的每個(gè)判斷依據(jù)。
5.3題外話:關(guān)于模型選型的避坑參考
由于最近經(jīng)常又被問(wèn)到不同業(yè)務(wù)場(chǎng)景下的模型選型問(wèn)題。我發(fā)現(xiàn)仍然存在一個(gè)普遍的誤區(qū)是,很多團(tuán)隊(duì)習(xí)慣直接用小尺寸開(kāi)源模型做 POC,結(jié)果陷入不知道是模型能力不足,還是技術(shù)方案有問(wèn)題的困局,浪費(fèi)了大量調(diào)試時(shí)間。
個(gè)人經(jīng)驗(yàn)是,第一步優(yōu)先用頂級(jí)模型(Claude Sonnet 4.5、GPT5、Gemini 2.5 Pro等)驗(yàn)證業(yè)務(wù)場(chǎng)景的準(zhǔn)確度上限。這樣可以快速確認(rèn)當(dāng)前技術(shù)方案是否可行,換句話說(shuō)判斷下業(yè)務(wù)目標(biāo)在理想情況下能否達(dá)成。其次,準(zhǔn)確度驗(yàn)證通過(guò)后,再根據(jù)實(shí)際需求,通過(guò)模型降級(jí)或者算力升級(jí),來(lái)優(yōu)化響應(yīng)速度。最后,考慮成本控制和本地化部署要求,設(shè)計(jì)大小模型分層服務(wù)(路由 + 降級(jí)策略),尤其是針對(duì)高頻低難度任務(wù)使用小模型。
一句話總結(jié),先確保"能做到",再優(yōu)化"做得快"和"做得省"。千萬(wàn)別在小模型上反復(fù)調(diào)試,最后發(fā)現(xiàn)是模型天花板的問(wèn)題。

































