·技能与命令
如何在 Claude Code 生命周期事件上用 hooks(PreToolUse、PostToolUse、Stop)跑脚本,以及如何用 subagents 拉起专门的并行 agent——附真实配置和经得起日常使用的模式。
Claude Code Hooks 与 Subagents:确定性自动化与并行工作
有两个特性让 Claude Code 从一个聪明的聊天工具,变成你可以依赖它做可复现工作的工具:hooks 和 subagents。Hooks 让你在 Claude Code 生命周期的固定节点上跑自己的脚本,所以确定性的副作用——格式化、校验、通知、阻止危险命令——每次都会发生,而不需要模型记得去做。Subagents 让你起一些带有自己上下文和工具额度的专门 Agent,所以你可以把独立的工作并行化,让主线程保持聚焦。本指南讲这两者,附真实配置和经得起日常使用的模式。
Hooks 是做什么的
一个 hook 是 Claude Code 在某个具名的生命周期事件上跑的 shell 命令。是否运行不是由模型决定的——Host 会保证它跑。这正是它的全部意义:任何你必须在每次工具调用、每次编辑、每次会话结束时发生的事,都应该放进 hook,而不是放进一个你指望模型记得的提示词里。
日常最常用的事件:
- PreToolUse —— 在工具运行前触发。让你检查或阻止调用。
- PostToolUse —— 在工具完成后触发。让你校验、格式化,或把上下文反馈给模型。
- UserPromptSubmit —— 用户提交提示词时触发。适合记录日志或注入上下文。
- Stop —— Claude 结束响应时触发。适合通知。
- SubagentStop —— subagent 结束时触发,是 Stop 的 subagent 版本。
- Notification —— Claude Code 抛出系统通知时触发。
- SessionStart / SessionEnd —— 会话边界触发。
- PreCompact —— 上下文压缩前触发。
此外还有几个(Setup、PermissionRequest,以及一些失败变体),但上面这些几乎覆盖了所有真实场景。
配置 hooks
Hooks 配置在 settings.json 里(项目级在 .claude/settings.json,用户级在 ~/.claude/settings.json)。结构是一个「事件名 → 匹配器组数组」的 map,每个组里放一串命令:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "prettier --write \"$CLAUDE_PROJECT_DIR/$tool_input.file_path\" 2>/dev/null || true"
}
]
}
]
}
}
matcher 是一个针对工具名做匹配的正则(用于 PreToolUse/PostToolUse),留空表示匹配每个工具。type 永远是 "command"。command 是 Host 执行的 shell 字符串。用 $CLAUDE_PROJECT_DIR 把路径锚到项目根——相对路径不可靠,因为工作目录不总是你以为的那个。
每个 hook 通过 stdin 接收一个 JSON 对象作为上下文。字段因事件而异,但总会包含 session_id、timestamp、cwd。工具事件额外有 tool_name、tool_input(参数)、tool_use_id;PostToolUse 还会有 tool_response。一个 hook 读 stdin、决定做什么,然后用两种方式之一表达结果:退出码,或 stdout 上的 JSON。
一个 PreToolUse 守卫
最常见的 PreToolUse 模式是守卫:当一次调用违反了模型不该违反的规则时,阻止它。下面这个脚本会阻止任何 rm -rf 调用:
#!/usr/bin/env bash
# .claude/hooks/block-rmrf.sh
input=$(cat)
cmd=$(echo "$input" | jq -r '.tool_input.command // ""')
if echo "$cmd" | grep -q 'rm -rf'; then
cat <<EOF
{
"decision": "block",
"reason": "rm -rf is blocked by project policy. Use a more specific cleanup command."
}
EOF
exit 0
fi
# 批准(或直接 exit 0 不输出任何东西,让它通过)
exit 0
在 settings.json 里接上:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{
"type": "command",
"command": "bash $CLAUDE_PROJECT_DIR/.claude/hooks/block-rmrf.sh"
}
]
}
]
}
}
现在每次 Bash 工具调用都会先经过这个脚本。如果脚本返回 {"decision": "block", ...},这次调用会被阻止,原因会展示给 Claude 让它调整。如果它什么都不返回,或返回 {"decision": "approve"},调用继续。PreToolUse hook 也可以用 exit 2 作为阻止的简写。Hooks 在权限规则之前运行,所以一个阻止型 hook 即使面对 allow 规则也优先——这是双保险地执行策略的方式。
一个 PostToolUse 格式化器
PostToolUse hook 很适合「事后」自动化。经典例子:把 Claude 写的每个文件重新格式化,这样模型永远不会给你没格式化的代码。matcher 针对 Edit 和 Write,命令在受影响的文件上跑你的格式化器:
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "npx prettier --write \"$(echo $0)\" 2>/dev/null; exit 0"
}
]
}
]
}
}
PostToolUse hook 还可以返回 JSON 把信息反馈给 Claude。返回 {"decision": "block", "reason": "..."} 不会撤销编辑,但会用原因提示 Claude,让它反应——适合「这个文件现在过不了类型检查,请修一下」这种反馈循环。「编辑 → hook 跑 linter → hook 把错误反馈回去 → Claude 修复」这个模式,是在不逐个监督改动的情况下保持质量最可靠的方式之一。
Hook 的坑
有几件事会坑到人:
- 格式错误的 JSON 输出会静默失败。 如果你的 hook 在本该发决策时往 stdout 打印了不是合法 JSON 的东西,Host 会忽略它。诊断信息走 stderr,决策走 stdout,绝不要往 stdout 上
echo调试噪音。 - 退出码是有含义的。 exit 0 表示成功;exit 2 表示阻止(对 PreToolUse);其他非零码会作为 hook 错误抛出。一个崩溃的 hook 可能卡住整个会话。
- Hooks 默认不受沙箱限制。 它们以你的完整权限运行。像对待任何你要运行的脚本一样对待 hook 命令——尤其从网上抄来的,要审查。
- 长时间运行的 hook 会拖慢每次工具调用。 一个跑两秒的 PreToolUse hook 会让 Claude 显得迟钝。保持 hooks 快;把慢活儿推到 PostToolUse 或 Stop。
Subagents 是做什么的
一个 subagent 是一个专门的 Claude Code Agent,拥有自己的系统提示词、自己的允许工具、自己的上下文窗口,由主 Agent 通过 Task 工具拉起。主 Agent 把一块有边界的工作委托出去,subagent 在隔离环境里做完,返回一个浓缩的结果。有两点让这很强大:
- 上下文隔离。 一个 subagent 的阅读和推理不会污染主线程的上下文窗口。如果你需要读 20 个文件来回答一个问题,在 subagent 里做就能让主线程保持干净。
- 并行。 主 Agent 可以在一次响应里发起多个 Task 工具调用,subagent 会并行运行——非常适合独立的研究或编码任务。
Subagent 适合「扇出,再综合」的工作:并行调研三种可能的方案、同时审查代码库的不同部分,或跑独立的实验。它不太适合主线程需要看到每个中间步骤的紧耦合工作。
定义一个 subagent
一个 subagent 是一个带 YAML frontmatter 的 Markdown 文件,放在 .claude/agents/(项目级,提交到 git)或 ~/.claude/agents/(用户级):
.claude/agents/
└── code-reviewer.md
.claude/agents/code-reviewer.md:
---
name: code-reviewer
description: Reviews staged changes for bugs, security issues, and style. Use proactively before opening a PR or when the user asks for a review.
tools: ["Read", "Grep", "Bash(git diff:*)", "Bash(git log:*)"]
---
You are a meticulous code reviewer. When given a set of changes:
1. Read the full diff against the base branch.
2. Check for: unhandled error paths, secret leakage in logs, missing tests,
naming that breaks the surrounding module's conventions.
3. Report findings grouped by file. End with one of: LGTM, Minor fixes, Block.
Do not edit files. You are read-only.
frontmatter 字段:
name—— subagent 的标识符,主 Agent 调用它时用作subagent_type。description—— subagent 做什么、何时用。主 Agent 读它来决定是否委托,所以它同时是触发器。tools—— subagent 可用的工具集。省略则继承会话默认值;限制它能让 subagent 聚焦且安全(一个只读的审查者不会意外重写代码)。
文件一旦存在,主 Agent 就可以通过 Task 工具以 subagent_type: "code-reviewer" 拉起它。你也可以直接对 Claude 说:「用 code-reviewer subagent 审一下我暂存的改动。」
一个并行工作流
Subagent 的回报是并行。假设你想调研三个独立的问题——「那个偶发失败的测试是什么原因?」「有没有做 X 的库?」「我们的鉴权流程跟新规范比怎么样?」。让 Claude 把每个都委托给一个 subagent:
Investigate these three questions in parallel using subagents:
1. Find the root cause of the failing test in tests/auth.spec.ts
2. Research whether there's a maintained library for parsing RFC 8989
3. Summarize how our current auth flow differs from the spec in docs/auth.md
主 Agent 发出三个 Task 工具调用,subagent 并发运行,你拿回三份浓缩报告——中间过程的文件阅读一丁点都不会落到你的主上下文里。这比把所有东西读进一个线程快得多、也便宜得多,还能让主 Agent 的注意力放在综合而不是探索上。
常见问题
Claude Code 的 hook 和权限规则有什么区别?
权限规则决定一次工具调用是否被允许进行(allow、deny,或询问)。Hook 是在生命周期事件上运行的脚本,可以做任意工作——格式化文件、发通知、阻止调用、把上下文反馈给 Claude。Hooks 在权限规则之前运行,所以一个阻止型 PreToolUse hook 即使面对 allow 规则也优先。规则用于「这该不该被允许」;hooks 用于「每次发生这个时该做什么」。
怎么用 PreToolUse hook 阻止危险命令?
写一个 hook 脚本:从 stdin 读 JSON 载荷,检查 tool_input.command,当命令匹配你的黑名单时,往 stdout 打印 {"decision": "block", "reason": "..."}。把它接到 hooks.PreToolUse 下,matcher 设为 "Bash"。Host 会在每次 Bash 工具调用前跑这个脚本;如果它返回 block 决策,调用会被阻止,原因会展示给 Claude。
什么是 Claude Code subagent,怎么创建?
一个 subagent 是一个专门的 Claude Code Agent,有自己的系统提示词、允许工具和上下文窗口,由主 Agent 通过 Task 工具拉起。创建方法是:往 .claude/agents/ 里加一个带 YAML frontmatter(name、description、tools)的 Markdown 文件。主 Agent 读 description 来决定何时委托,然后用它的 name 作为 subagent_type 拉起它。
Claude Code 的 subagent 能并行运行吗?
能。主 Agent 可以在一次响应里发出多个 Task 工具调用,subagent 会在隔离的上下文里并发运行。这非常适合独立的研究或编码任务——同时调研三种方案、同时审查代码库的不同部分——并让主线程聚焦在综合而不是探索上。
官方参考资料
- Claude Code hooks 参考
- Claude Code hooks 指南
- Claude Code subagents(自定义 agent)
- Claude Code 设置与权限
- Anthropic 工程博客 — Claude Code
本文基于截至 2026 年 7 月的公开信息,相关 API 可能演进。