ClaudeMap

·技能与命令

如何在 Claude Code 生命周期事件上用 hooks(PreToolUse、PostToolUse、Stop)跑脚本,以及如何用 subagents 拉起专门的并行 agent——附真实配置和经得起日常使用的模式。

Claude Code Hooks 与 Subagents:确定性自动化与并行工作

有两个特性让 Claude Code 从一个聪明的聊天工具,变成你可以依赖它做可复现工作的工具:hookssubagents。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_idtimestampcwd。工具事件额外有 tool_nametool_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 针对 EditWrite,命令在受影响的文件上跑你的格式化器:

{
  "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 在隔离环境里做完,返回一个浓缩的结果。有两点让这很强大:

  1. 上下文隔离。 一个 subagent 的阅读和推理不会污染主线程的上下文窗口。如果你需要读 20 个文件来回答一个问题,在 subagent 里做就能让主线程保持干净。
  2. 并行。 主 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 会在隔离的上下文里并发运行。这非常适合独立的研究或编码任务——同时调研三种方案、同时审查代码库的不同部分——并让主线程聚焦在综合而不是探索上。

官方参考资料

本文基于截至 2026 年 7 月的公开信息,相关 API 可能演进。