create-or-audit-hook
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseCreate or audit a hook
创建或审核钩子
Hooks are deterministic gates bash-scripted against Claude Code events. Use them for things that must run every time, fast.
钩子是针对Claude Code事件编写的确定性bash脚本门控机制,适用于必须每次快速运行的任务。
Before You Start
开始之前
- — annotated blank hook with stdin parsing, dispatch, and exit-code examples.
skills/meta/create-or-audit-hook/templates/hook.sh - — mechanical checks (shebang, pipefail, stdin read, stderr-when-blocking).
skills/meta/create-or-audit-hook/lib/validate.sh - Event taxonomy: (block before tool runs),
PreToolUse(act after tool runs),PostToolUse(gate session end),Stop(warm caches). Exit codes:SessionStartallow,0block + stderr message.2
- — 带注释的空白钩子模板,包含标准输入解析、分发和退出代码示例。
skills/meta/create-or-audit-hook/templates/hook.sh - — 机械检查脚本(检查shebang、pipefail、标准输入读取、阻塞时的标准错误输出)。
skills/meta/create-or-audit-hook/lib/validate.sh - 事件分类:(工具运行前阻止)、
PreToolUse(工具运行后执行操作)、PostToolUse(会话结束门控)、Stop(预热缓存)。退出代码:SessionStart允许执行,0阻止并输出标准错误信息。2
Mode 1 — build a new hook
模式1 — 构建新钩子
Step 1: pick the event
步骤1:选择事件
| You want... | Event | Matcher |
|---|---|---|
| Block a write to protected files | | |
| Refuse a dangerous shell command | | |
| Format a file after editing | | |
| Run typecheck before "done" | | — |
| Warm caches at session start | | — |
If the rule isn't deterministic (requires judgment), it's not a hook — it's a skill.
| 你需要... | 事件 | 匹配规则 |
|---|---|---|
| 阻止写入受保护文件 | | |
| 拒绝危险的Shell命令 | | |
| 编辑后格式化文件 | | |
| “完成”前运行类型检查 | | — |
| 会话开始时预热缓存 | | — |
如果规则不具备确定性(需要主观判断),则不属于钩子范畴,而是skill。
Step 2: copy the template
步骤2:复制模板
bash
cp .claude/skills/meta/create-or-audit-hook/templates/hook.sh .claude/hooks/{hook-name}.sh
chmod +x .claude/hooks/{hook-name}.shbash
cp .claude/skills/meta/create-or-audit-hook/templates/hook.sh .claude/hooks/{hook-name}.sh
chmod +x .claude/hooks/{hook-name}.shStep 3: fill in the logic
步骤3:填充逻辑
Enforce these rules:
- +
#!/usr/bin/env bashat the top.set -euo pipefail - Read JSON from stdin: .
input=$(cat) - Short-circuit on empty input, wrong tool, or irrelevant file type.
exit 0 - If blocking (), print an actionable message to stderr:
exit 2.echo "BLOCKED: reason + instead" >&2 - Check for tool presence with before running an external tool. Never
command -vbecause a formatter is missing — the user's local state isn't your hook's concern.exit 1
遵循以下规则:
- 文件顶部需包含 +
#!/usr/bin/env bash。set -euo pipefail - 从标准输入读取JSON:。
input=$(cat) - 若输入为空、工具不匹配或文件类型不相关,直接 短路退出。
exit 0 - 如果需要阻止操作(),需向标准错误输出可执行提示信息:
exit 2。echo "BLOCKED: 原因 + 替代方案" >&2 - 运行外部工具前,先用 检查工具是否存在。绝对不要因为格式化工具缺失就
command -v— 用户的本地环境状态不属于钩子的职责范围。exit 1
Step 4: wire it in settings.json
settings.json步骤4:在settings.json
中配置
settings.jsonjson
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [{ "type": "command", "command": ".claude/hooks/{hook-name}.sh" }]
}
]
}
}Without wiring, the hook file exists but never runs — the #1 cause of "my hook doesn't work."
json
{
"hooks": {
"PostToolUse": [
{
"matcher": "Write|Edit",
"hooks": [{ "type": "command", "command": ".claude/hooks/{hook-name}.sh" }]
}
]
}
}如果不配置,钩子文件虽然存在但永远不会运行 — 这是“我的钩子不工作”的头号原因。
Step 5: run the validator
步骤5:运行验证器
bash
bash skills/meta/create-or-audit-hook/lib/validate.sh .claude/hooks/{hook-name}.shbash
bash skills/meta/create-or-audit-hook/lib/validate.sh .claude/hooks/{hook-name}.shStep 6: dry-run
步骤6:试运行
bash
echo '{"tool_name":"Write","tool_input":{"file_path":"test.py","content":"x"}}' | \
bash .claude/hooks/{hook-name}.shConfirm: relevant input acts; irrelevant input (wrong tool, wrong filetype) exits 0 silently.
bash
echo '{"tool_name":"Write","tool_input":{"file_path":"test.py","content":"x"}}' | \
bash .claude/hooks/{hook-name}.sh确认:相关输入会触发操作;无关输入(错误工具、错误文件类型)会静默退出并返回0。
Mode 2 — audit hooks
模式2 — 审核钩子
Step 1: structural on each
步骤1:逐个检查结构
bash
for f in .claude/hooks/*.sh; do
echo "=== $f ==="
bash skills/meta/create-or-audit-hook/lib/validate.sh "$f" | tail -5
donebash
for f in .claude/hooks/*.sh; do
echo "=== $f ==="
bash skills/meta/create-or-audit-hook/lib/validate.sh "$f" | tail -5
doneStep 2: five gates
步骤2:五项检查
Gate 1 — wiring. Every hook file has a matching entry in . Orphans are dead code:
settings.jsonbash
jq -r '.hooks | to_entries[] | .value[] | .hooks[]?.command' .claude/settings.json \
| grep -oE '[^/]+\.sh$' | sort -u > /tmp/wired.txt
ls .claude/hooks/*.sh | xargs -n1 basename | sort > /tmp/exists.txt
comm -23 /tmp/exists.txt /tmp/wired.txt # hooks that exist but are not wired
comm -13 /tmp/exists.txt /tmp/wired.txt # wirings that point to missing hooksGate 2 — tool presence checks. formatters must check for the tool () before running. Missing this makes the hook break silently on machines without the formatter.
PostToolUsecommand -v ruff >/dev/null 2>&1 || exit 0Gate 3 — blocking discipline. without output is broken. The user sees no message, only a refusal.
exit 2>&2Gate 4 — no network. , , in a hook means every tool call pays that latency. Move network-dependent work to a skill or a manual command.
curlwgetfetchGate 5 — idempotency. Running the hook twice on the same input has the same effect. A hook that appends to a log without a staleness check breaks idempotency.
SessionStart检查1 — 配置情况。每个钩子文件在中都有对应的条目。孤立的钩子文件属于无效代码:
settings.jsonbash
jq -r '.hooks | to_entries[] | .value[] | .hooks[]?.command' .claude/settings.json \
| grep -oE '[^/]+\.sh$' | sort -u > /tmp/wired.txt
ls .claude/hooks/*.sh | xargs -n1 basename | sort > /tmp/exists.txt
comm -23 /tmp/exists.txt /tmp/wired.txt # 存在但未配置的钩子
comm -13 /tmp/exists.txt /tmp/wired.txt # 配置指向不存在的钩子检查2 — 工具存在性验证。格式化钩子必须在运行前检查工具是否存在()。缺少此检查会导致在没有格式化工具的机器上钩子静默失效。
PostToolUsecommand -v ruff >/dev/null 2>&1 || exit 0检查3 — 阻塞规范。仅但没有输出的钩子是损坏的。用户只会看到操作被拒绝,却看不到任何提示信息。
exit 2>&2检查4 — 无网络操作。钩子中出现、、意味着每次工具调用都会产生网络延迟。将依赖网络的任务移至skill或手动命令中。
curlwgetfetch检查5 — 幂等性。对相同输入运行两次钩子应产生相同效果。例如,钩子如果在没有过期检查的情况下追加日志,会破坏幂等性。
SessionStartStep 3: report
步骤3:生成报告
markdown
undefinedmarkdown
undefinedHooks Audit
钩子审核报告
Verdict per hook
各钩子判定结果
| Hook | Event | Wired? | Validator | Gates |
|---|---|---|---|---|
| protect-sensitive-files.sh | PreToolUse | yes | PASS | all |
| ... |
| 钩子 | 事件 | 是否已配置 | 验证器结果 | 检查项 |
|---|---|---|---|---|
| protect-sensitive-files.sh | PreToolUse | 是 | 通过 | 全部通过 |
| ... |
Orphan hooks (remove or wire)
孤立钩子(移除或配置)
...
...
Broken wirings (point to missing files)
无效配置(指向不存在的文件)
...
...
Proposed additions (hooks the codebase would benefit from)
建议新增钩子(代码库可从中受益的钩子)
...
undefined...
undefinedVerify
验证
bash
bash skills/meta/create-or-audit-hook/lib/validate.sh .claude/hooks/{name}.shbash
bash skills/meta/create-or-audit-hook/lib/validate.sh .claude/hooks/{name}.shExpected: VERDICT: PASS
预期结果:VERDICT: PASS
Dry-run with a representative payload
使用代表性负载试运行
echo '{"tool_name":"Write","tool_input":{"file_path":"x.py"}}' | bash .claude/hooks/{name}.sh
undefinedecho '{"tool_name":"Write","tool_input":{"file_path":"x.py"}}' | bash .claude/hooks/{name}.sh
undefinedCommon Mistakes
常见错误
| Mistake | Correction |
|---|---|
Hook file exists but isn't in | Wire it. Claude Code only runs what's declared. |
| |
| Add |
Reading | Write's payload is |
| 错误 | 修正方案 |
|---|---|
钩子文件存在但未在 | 进行配置。Claude Code仅运行已声明的钩子。 |
格式化工具缺失时 | 改为 |
| 在 |
针对Write钩子读取 | Write的负载是 |