内容来源:MCP.Directory。https://mcp.directory/blog/claude-code-skills-vs-subagents-vs-plugins-vs-hooks-2026
原题:Claude Code Skills vs Subagents vs Plugins vs Hooks (2026)
原发布时间:2026-05-11

Claude Code 有四种扩展基础机制。本文比较 Skills、子智能体、Plugins 与 Hooks,解释每种机制的用途,提供真实配置示例,并给出选择决策树。

编辑插图:午夜蓝背景上,四个明亮的青绿色扩展机制图标横向排列——Skill 的 SKILL.md 徽章、子智能体的分叉箭头、Plugin 的拼图块和 Hook 的生命周期弧线,并由泛着微光的生命周期箭头连接。

太长不看 + 决策树

如果你想让 Claude 学会一套流程——例如工作流、编码约定,或一份应在相关场景中启用的检查清单——请编写 Skill。在 .claude/skills/<name>/ 下创建文件夹并放入 SKILL.md;当对话与 Frontmatter 中的描述匹配时,它就会自动载入。
如果你想把探索性或嘈杂的工作与主上下文隔离——例如代码审查、深度文件扫描或资料研究——请启动子智能体.claude/agents/ 下的一份 Markdown 文件会定义一个子 Claude,并为其指定独立的系统提示词、工具白名单与上下文窗口。
如果你想把团队工具一次性分发出去——将斜杠命令、Hooks、Skills 与 MCP 服务器配置打成一个包——请发布 Plugin。队友只需运行一次 /plugin install,整套工具就会出现。
如果你想以确定性方式强制执行策略——例如阻止 rm -rf、在会话启动时注入上下文、记录每次文件编辑,或在写入生产环境前要求确认——请编写 Hook。在 settings.json 中注册后,它会在生命周期事件发生时运行 Bash 命令,并能阻止或修改 Claude 接下来的行为。

这四种机制并非互斥,也不能互相替代。它们位于同一个智能体运行时的不同层面,几乎每套成熟的 Claude Code 配置都会使用其中至少三种。本文接下来会逐一介绍它们,给出可直接粘贴的真实配置,并展示我们见过的组合模式。

Claude Code 的扩展体系如何运作

在逐一讲解每种基础机制前,不妨先把运行时想象成一套具有四个正交插槽的堆栈,每个插槽回答一个不同的问题。

Skills 回答“模型知道该做什么吗?” 它们以带 YAML Frontmatter 的 Markdown 流程文档存放在磁盘上。运行时,模型会扫描所有可用 Skill 的描述——包括 .claude/skills/ 下的本地 Skill、~/.claude/skills/ 下的用户级 Skill,以及随已安装 Plugin 提供的 Skill——然后载入当前轮次可能需要的 Skill 正文。触发依据是内容匹配:如果对话涉及生成 PDF,同时存在名为 pdf-generation 且描述中提到 PDF 的 Skill,那么该 Skill 的正文就会进入上下文。

子智能体回答“现在由谁完成工作?” 主对话可以通过 Task 工具启动一个子智能体,交给它目标,然后等待摘要。子智能体使用全新的独立上下文窗口、自己的系统提示词、自己的工具白名单,还可以选择不同的底层模型。完成后,只有摘要返回父智能体;父智能体不会看到子智能体产生的日志、文件转储或草稿推理。Claude Code 正是通过这种方式读取上万行代码,而不会让主上下文充满以后再也用不到的文件内容。

Plugins 回答“这些工具如何分发?” Plugin 是一个工具包,由清单以及一组斜杠命令、Hooks、子智能体、Skills 和 MCP 服务器配置组成。用户可以通过 /plugin 命令,从市场、Git URL 或本地路径安装。对于“如何用一条命令让整个团队采用相同配置”这个问题,答案就是 Plugin。从模型在运行时的视角看,Plugin 中的 Skill 与手写的本地 Skill 没有区别;打包工作发生在安装阶段。

Hooks 回答“智能体循环前后有什么事情必须确定执行?” Hooks 不是由模型调用的,模型也无法拒绝触发。它们注册在 settings.json 顶层的 hooks 键下;每个 Hook 都绑定一个生命周期事件,例如 PreToolUse、PostToolUse、UserPromptSubmit、SessionStart、SubagentStop、PreCompact,以及另外约二十种事件。事件发生时,Hook 会运行 Bash 命令、HTTP 请求、Prompt、Agent,甚至 MCP 工具。你可以通过 Hooks 强制执行策略、完整记录审计日志、注入必须始终存在的上下文,并在不依赖模型遵守指令的情况下重定向或阻止模型。

这一点很重要,因为:每种基础机制关注的问题都不同。 一旦选错,结果就会显得脆弱。把编码约定放进 Hook 的 SessionStart 注入中,起初一周看起来很巧妙,可当约定需要根据正在编辑的文件有条件地启用时,方案就会失效——而 Skill 原生就能处理这种情况。把危险命令的阻断规则放进 Skill 更像是在演戏:模型会载入 Skill、确认已理解指令,却可能在三轮对话后准备编写测试时将其忽略。不能信任模型自行遵守的事情应交给 Hooks;模型需要掌握的知识则应交给 Skills。

这些机制的演进速度也不同。Skills 与 Plugins 已经相对稳定、文档完善,而且越来越容易跨智能体移植(Cursor、Codex、Cline 与 Gemini CLI 都能解析 SKILL.md)。子智能体与 Hooks 则更具 Claude Code 专属性,几乎每次 Claude Code 发布新版本都会增加事件或能力。如果你重视跨编辑器移植性,请优先采用 Skills,把其他机制视为 Claude Code 的本地胶水。我们在跨智能体 Skills 移植性一文中详细讨论过这个话题。

横向比较矩阵

四种基础机制,五个比较维度。表中每一格都基于截至 2026 年 5 月的 Claude Code 官方文档;特殊情况与边缘行为会在后面各机制的专门章节中介绍。

维度 Skills 子智能体 Plugins Hooks
存放位置 .claude/skills/<name>/SKILL.md .claude/agents/<name>.md ~/.claude/plugins/<name>/ + /plugin 市场 .claude/settings.jsonhooks
激活方式 Frontmatter 描述与对话匹配 通过 Task 工具显式调用 用户运行 /plugin install 生命周期事件触发(PreToolUse 等)
作用范围 流程性知识(工作流、约定) 用于旁路任务的隔离上下文窗口 其他基础机制的分发包 确定性策略与可观测性
组合能力 可载入主智能体或子智能体上下文 可使用任意工具并载入 Skills 将 Skills、子智能体、Hooks 与 MCP 一同分发 围绕任意工具运行,包括子智能体使用的工具
最适合 教授一套应自动激活的流程 并行处理或隔离嘈杂工作 将团队技术栈打包为一次安装 强制执行模型无法选择退出的策略
信任边界 可信代码路径(在智能体上下文中运行) 沙箱化上下文,继承工具白名单 安装时即受信任,采用前需审计 以用户身份运行,可访问完整文件系统
跨智能体移植性 强(Agent Skills 规范、Cursor/Codex/Cline/Gemini) 弱(Claude Code 专用) 弱(Claude Code 专用) 弱(Claude Code 专用)

这里有三点值得记住。第一,只有 Hooks 会确定触发,其他机制都取决于模型是否决定使用。第二,只有 Plugins 负责分发;如果团队需要相同配置,那么 Plugins 是载体,其余机制都是货物。第三,Skills 在不同智能体之间最容易移植,因为它们符合开放的 Agent Skills 规范——编写一次 Skill,Cursor、Codex、Cline 与 Gemini CLI 都能读取。

Skills——自动激活的 Markdown 流程

Skill 是一个包含 SKILL.md 文件的文件夹,文件由 YAML Frontmatter 和 Markdown 正文组成。Frontmatter 告诉 Claude 何时激活这项 Skill,正文则告诉 Claude 应该做什么。最小结构如下:

# .claude/skills/pdf-generation/SKILL.md
---
name: pdf-generation
description: 使用公司的标准封面、页眉、页脚和 Inter 字体,根据 Markdown 生成符合品牌风格的 PDF 报告。只要用户要求生成 PDF、可打印报告或品牌化文档,就使用此 Skill。
model: sonnet
---

# PDF 生成

## 适用场景

用户希望 PDF 遵循公司的品牌规范,包括:

- 季度业务回顾
- 面向客户的报告
- 导出供分享的内部单页文档

## 流程

1. 阅读用户提供的源 Markdown(如果用户只描述了内容,则先生成一份)。
2. 确认封面元数据:标题、日期、作者和受众。
3. 使用 templates/brand.tex.j2 中的模板——绝不要自行发明新模板。
4. 通过 'uv run scripts/render-pdf.py <input.md> <output.pdf>' 渲染。
5. 验证输出能够打开且封面正确呈现。将文件路径告知用户。

## 辅助文件

- templates/brand.tex.j2——LaTeX 模板,未经设计团队批准不得编辑
- scripts/render-pdf.py——包含正确默认值的渲染脚本

## 不应做什么

- 不要临时手写新模板,请使用提供的模板。
- 正文中的公司 Logo 高度不得超过 120px。
- 除非用户要求,否则不要导出受密码保护的 PDF。

最擅长什么

Skills 最擅长那些无需用户记得提及、就应该自行激活的流程。Frontmatter 中的描述就是激活契约:Claude 每轮都会扫描所有可用 Skill 的描述,并载入与当前对话匹配的 Skill 正文。因此,“我们在这里如何完成 X”这类知识最适合放在 Skills 中,例如编码约定、报告模板、审查清单与部署 Runbook。你希望这些知识跨会话得到一致应用,又不想让用户每次都粘贴上下文。

何时应该使用

• 某套流程会跨会话反复出现,而你每次都在粘贴同样的指令
• 指令足够长(200 字以上),放入 CLAUDE.md 会无谓地增加每轮上下文
• 流程具有条件性——应在部分任务中启动,其他时候则不应干扰
• 你希望在不同编辑器之间共享流程(Cursor、Codex、Cline 与 Gemini 都能解析 SKILL.md

如何发布

只需在文件夹中放置三个文件,无须安装。项目级 Skill 放在 .claude/skills/<name>/,用户级 Skill 放在 ~/.claude/skills/<name>/。最低要求只有前面展示的 SKILL.md;辅助脚本、模板与数据文件可以放在同一目录中,并由 Skill 正文通过相对路径引用。

# 演示最小 Skill 脚手架的 Bash 会话
mkdir -p .claude/skills/code-review

cat > .claude/skills/code-review/SKILL.md <<'EOF'
---
name: code-review
description: 对 Diff 执行团队的代码审查清单。只要用户要求进行代码审查、PR 审查、“发布前”审查,或希望查看未提交的改动,就使用此 Skill。
---

# 代码审查

## 检查清单

针对 Diff 中的每个改动文件:

1. SQL 安全:使用参数化查询,不得用字符串格式化 SQL。
2. LLM 信任边界:任何来自模型输出的值都应视为不可信用户输入。
3. 有条件的副作用:只在用户明确触发的代码路径中产生副作用。
4. 错误处理:错误必须携带上下文向上暴露,不得静默回退。
5. 测试:会改变行为的 PR 至少应有一项测试,哪怕只是冒烟测试。

生成结构化审查:先列出每个文件的问题,再给出包含
“可以发布 / 暂缓发布”建议的摘要。
EOF

git add .claude/skills/code-review
git commit -m "Add code-review skill"

就这么简单。下次团队成员在 Claude Code 中说“审查这个 PR”时,描述会匹配,Skill 随即载入并执行检查清单。无需安装客户端、无需使用市场,而且 Skill 未载入时不会产生 Token 成本。

何时不应使用

• 行为必须得到强制执行,而不只是建议——模型有时会忽略 Skill 指令,这属于 Hook 的职责
• 流程依赖实时外部状态(例如从 API 获取数据)——这属于 MCP 服务器的职责
• 流程只有两句话——直接放入 CLAUDE.md 即可,始终载入的成本可以忽略

子智能体——拥有全新上下文的子 Claude 实例

子智能体通过 .claude/agents/<name>.md 下的 Markdown 文件定义。Frontmatter 会描述其名称、允许调用的工具,以及可选的模型;正文则是系统提示词。当主对话调用指向该子智能体的 Task 工具时,Claude Code 会启动一个拥有独立上下文窗口的新智能体,执行目标,并且只把最终响应返回父智能体。

# .claude/agents/codebase-explorer.md
---
name: codebase-explorer
description: 对代码库进行只读式深度探索。当问题是“X 在哪里定义”或“Y 端到端如何运行”,而答案需要阅读大量文件时,启动此智能体。
tools: Read, Grep, Glob
model: sonnet
---

你是一名代码库探索专家。你的职责是通过全面阅读代码库,
回答“X 在哪里”和“Y 如何运行”之类的问题,并返回简洁的结构化摘要。

## 操作规则

- 你可以读取任意文件,但不得写入或编辑任何文件。
- 优先使用 Grep 查找符号,优先使用 Glob 查找相关文件。
- 只读取能够自信回答问题所需的最少文件,不要读取整个目录。
- 返回结构化报告:
  - **所在位置**:带行号的文件路径
  - **运行方式**:3~5 句话的说明
  - **依赖关系**:调用方、导入方和相关模块
  - **注意事项**:调用方智能体应知道的一切

不要发表评论,不要提出修改建议。你的职责是观察,而不是行动。

最擅长什么

子智能体最擅长完成那些会让主对话充满日志、文件内容或草稿推理,而父智能体以后再也不会用到这些信息的旁路任务。父智能体只需说“使用 codebase-explorer 智能体找出 X 的定义位置”,等待片刻,然后收到一份包含四个要点的摘要。探索者为生成摘要而执行的 50 次文件读取,永远不会进入父智能体上下文。配合严格的工具白名单,子智能体会成为安全并行的优秀基础机制:父智能体可以同时启动三个子智能体,让它们分别探索代码库的不同区域,再合并各自结果。

何时应该使用

• 旁路任务会读取大量文件或产生大量工具输出,而父智能体无须保留这些内容
• 你希望并行处理工作——三个并行子智能体会比一条主循环串行完成同样工作更快
• 你希望旁路任务采用与主对话不同的工具白名单(例如探索任务只读,主循环允许写入)
• 你希望为专业任务使用不同的系统提示词——例如代码审查子智能体、测试编写子智能体或研究总结子智能体

如何发布

只需在 .claude/agents/ 下放置一份 Markdown 文件,不需要额外配置。父智能体通过 Task 工具按名称调用。在实践中,你会在提示词中用自然语言描述子智能体,例如“使用 codebase-explorer 智能体查找身份验证边界的定义位置”,Claude Code 随后会通过 Task 工具派发匹配的智能体。

# 子智能体如何从会话中被调用

# 1. 用户(或主智能体)决定委派任务。
# 2. Claude Code 使用以下参数调用 Task 工具:
{
  "subagent_type": "codebase-explorer",
  "description": "查找身份验证边界的定义位置",
  "prompt": "找出这个代码库中涉及身份验证边界的每个文件。
             我需要知道:边界在哪里定义、哪些文件会调用它、
             哪些测试覆盖它,以及已有注释中是否提及它的安全状况。
             请按照你的操作规则返回结构化报告。"
}

# 3. 启动一个全新的 Claude 实例,并具有:
#    - 系统提示词:codebase-explorer.md 中 Frontmatter 以下的内容
#    - 工具白名单:Read、Grep、Glob(来自 Frontmatter)
#    - 模型:sonnet(来自 Frontmatter)
#    - 空上下文窗口——看不到父智能体的历史
#    - 将第 2 步中的 Prompt 作为首条用户消息
#
# 4. 子智能体运行智能体循环,期间可能调用 30 次工具。
#    这些调用都不会出现在父智能体上下文中。
#
# 5. 子智能体最终的 Assistant 消息作为 Task 工具结果返回父智能体。
#    父智能体只会看到一条消息。

何时不应使用

• 任务很短,启动新上下文的成本高于它原本会产生的噪声
• 父智能体之后需要基于子智能体的中间状态继续追问——父智能体只会看到最终摘要
• 你需要确定性行为——子智能体仍是智能体,其行为同样取决于模型的判断

Plugins——其他一切机制的捆绑分发层

Plugin 是 Claude Code 的分发层。一个软件包就能把斜杠命令、Hooks、子智能体、Skills 和 MCP 服务器配置作为一次安装全部交付。队友只需运行一次 /plugin install,整个工具包就会合并到他们的配置中。Plugin 资源位于 ~/.claude/plugins/<name>/ 下,通过 $CLAUDE_PLUGIN_DIR 相互引用,因此不会污染项目的 .claude/ 文件夹。

# ~/.claude/plugins/team-stack/plugin.json
{
  "name": "team-stack",
  "version": "1.4.2",
  "description": "我们团队的标准 Claude Code 技术栈:
                  包含代码审查与 ADR 编写 Skills、一个部署子智能体、
                  一个阻止危险 Bash 命令的 PreToolUse Hook,
                  以及预先配置好的 Linear MCP 服务器。",
  "author": "Internal Tools",
  "license": "Apache-2.0",
  "components": {
    "skills": ["skills/code-review", "skills/adr-author"],
    "agents": ["agents/deploy-shepherd.md"],
    "hooks": "hooks/hooks.json",
    "mcpServers": "mcp/servers.json",
    "commands": ["commands/ship.md", "commands/rollback.md"]
  }
}

# 目录树:
# ~/.claude/plugins/team-stack/
# +- plugin.json
# +- skills/
# |  +- code-review/SKILL.md
# |  +- adr-author/SKILL.md
# +- agents/
# |  +- deploy-shepherd.md
# +- hooks/
# |  +- hooks.json
# |  +- block-rm.sh
# +- mcp/
# |  +- servers.json
# +- commands/
#    +- ship.md
#    +- rollback.md

最擅长什么

Plugins 用于分发技术栈中的其他部分。Skills、子智能体、Hooks 和 MCP 服务器配置都可以单独分发,但 Plugin 能通过清单将它们组合成一个有版本的软件包。第一大优势是新成员上手:队友安装团队 Plugin 后,只用一条命令就能接好斜杠命令、Hooks、Skills 与 MCP 服务器。第二大优势是版本管理:Plugin 清单包含版本字段,因此你可以发布 v1.4.2;如果某个 Hook 引发问题,也可以回滚。

何时应该使用

• 有两人以上在相同的 Claude Code 环境中工作,而且你希望大家使用同一套配置
• 你已经搭好一套值得开源或公开分享的技术栈——Plugin 是标准的共享单元
• 你希望工具能够版本化、可以回滚,而不是临时复制粘贴 .claude/ 目录
• 你希望采用别人精心调优的技术栈,而不是从头重建

如何发布

先在本地编写软件包,再推送到 Git 仓库,然后通过 /plugin marketplace add + /plugin install 流程安装。Plugin 清单声明包中包含哪些 Skills、Agents、Hooks、MCP 服务器与命令;Claude Code 读取清单并完成接入。

# 作者流程(你的电脑)
mkdir -p team-stack/{skills/code-review,agents,hooks,mcp,commands}

# 创建 plugin.json(清单),然后添加各组件。
$EDITOR team-stack/plugin.json
$EDITOR team-stack/skills/code-review/SKILL.md
$EDITOR team-stack/agents/deploy-shepherd.md
$EDITOR team-stack/hooks/hooks.json
$EDITOR team-stack/hooks/block-rm.sh
chmod +x team-stack/hooks/block-rm.sh
$EDITOR team-stack/mcp/servers.json

git init team-stack
cd team-stack
git add .
git commit -m "team-stack 1.0.0"
git remote add origin [email protected]:acme/team-stack.git
git push -u origin main

# 队友流程(他们的电脑)
# 1. 添加市场(仅需一次)
/plugin marketplace add github:acme/team-stack

# 2. 安装 Plugin
/plugin install team-stack

# 3. 确认
/plugin list
# -> team-stack 1.0.0(已安装)
#    skills: code-review, adr-author
#    agents: deploy-shepherd
#    hooks: PreToolUse(Bash, rm -rf)
#    mcp:   linear
#    commands: /ship, /rollback

何时不应使用

• 只有你一个人使用自己的 .claude/ 目录——本地文件比 Plugin 清单更简单
• 配置每天都在变化——Plugins 是有版本的契约,不是草稿本
• 你需要跨编辑器移植——Plugin 只能安装在 Claude Code 中;里面的 Skills 可以移植,打包格式本身不行

Hooks——确定性的事件处理程序

Hook 是注册在 settings.json 顶层 hooks 键下的 Bash 命令(也可以是 HTTP 请求、Prompt 或 Agent 派发)。每个 Hook 都会绑定一个生命周期事件,例如 PreToolUsePostToolUseUserPromptSubmitSessionStartSubagentStopPreCompact,以及另外约二十种事件,并在该事件发生时确定运行。关键在于,模型无法选择退出:Hooks 属于运行时,而不属于智能体决策。因此,它们是强制执行策略、记录审计日志和注入始终开启的上下文时最合适的基础机制。

# .claude/settings.json
{
  "hooks": {
    "PreToolUse": [
      {
        "matcher": "Bash",
        "hooks": [
          {
            "type": "command",
            "if": "Bash(rm *)",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/block-rm.sh",
            "timeout": 5
          }
        ]
      }
    ],
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/audit-log.sh",
            "timeout": 10
          }
        ]
      }
    ],
    "SessionStart": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "\"$CLAUDE_PROJECT_DIR\"/.claude/hooks/inject-context.sh"
          }
        ]
      }
    ]
  }
}

# .claude/hooks/block-rm.sh
#!/bin/bash
COMMAND=$(jq -r '.tool_input.command')

if echo "$COMMAND" | grep -qE 'rm[[:space:]]+-rf|rm[[:space:]]+-fr'; then
  jq -n '{
    hookSpecificOutput: {
      hookEventName: "PreToolUse",
      permissionDecision: "deny",
      permissionDecisionReason: "rm -rf 已被 .claude/hooks/block-rm.sh 阻止——请使用 git clean 或明确指定文件"
    }
  }'
else
  exit 0
fi

最擅长什么

Hooks 最擅长为智能体循环提供“信任,但要验证”的外围层。模型善于理解意图,却不擅长保持一致;Hooks 可以补上这个缺口。绑定 Bash 的 PreToolUse Hook 一旦阻止 rm -rf,模型就无法讨价还价——即便模型写出了命令,运行时也会调用 Hook,Hook 返回 deny 后,命令便不会执行。同一基础机制还能提供可观测性:绑定 Edit 与 Write 的 PostToolUse Hook 可以在模型每次编辑文件时向审计日志写入一行记录。它也支持注入始终开启的上下文:SessionStart Hook 可以取得当前 Jira 工单,并在用户开始第一轮对话前将其加入上下文。

何时应该使用

• 无论模型作何决定,你都需要强制执行某项策略——阻止危险命令、要求批准生产环境写入,或拒绝访问未获批准的网络主机
• 你需要一条独立于模型输出的审计轨迹——将每次文件编辑、Shell 命令和 MCP 调用记录到磁盘或远程收集器
• 你需要在每次会话启动时可靠注入上下文——当前 Git 分支、当前工单或当前值班安排
• 你需要重定向或改写模型即将进行的操作——例如为指向特定目录的每条 Bash 命令注入沙箱前缀

如何发布

settings.json 中注册 Hook、指向一份脚本,再赋予脚本执行权限。Hook 配置块可以声明 if 匹配条件(让脚本只在你关心的调用中触发)、以秒为单位的 timeout,以及 typecommandpromptagenthttpmcp)。脚本从标准输入读取 JSON 格式的工具调用载荷,然后以 0 退出(允许)、以 2 退出(阻止,并把标准错误作为提示消息),或以 0 退出并在标准输出中返回结构化 JSON 载荷。

# 根据 Claude Code 文档,Hook 处理程序有两种阻断方式。
#
# (1) 退出码 2——标准错误会成为面向用户的原因。
#     这是快速方式,适合单行脚本。
#
# (2) 以退出码 0 结束,并向标准输出写入结构化 JSON——Claude 会读取
#     permissionDecisionReason 并调整计划。除简单的快速拒绝外,
#     其他情况最好采用这种方式。

# 快速阻断示例(退出码 2):
#!/bin/bash
COMMAND=$(jq -r '.tool_input.command' < /dev/stdin)
if [[ "$COMMAND" == *"DROP TABLE"* ]]; then
  echo "已阻止:检测到 DROP TABLE" >&2
  exit 2
fi
exit 0

# 结构化阻断示例(退出码 0 + JSON):
#!/bin/bash
COMMAND=$(jq -r '.tool_input.command' < /dev/stdin)
if [[ "$COMMAND" == *"DROP TABLE"* ]]; then
  jq -n '{
    hookSpecificOutput: {
      hookEventName: "PreToolUse",
      permissionDecision: "deny",
      permissionDecisionReason: "迁移流程之外禁止执行 DROP TABLE。请在 db/migrations/ 下创建带编号的迁移文件,并通过 migrate 命令运行。"
    }
  }'
  exit 0
fi
exit 0

何时不应使用

• 行为只是“最好有”,而非“必须强制执行”——Skills 更适合温和引导,Hooks 用于硬性规则
• 检查速度很慢(超过约 100 毫秒),而且每次调用工具时都会触发——这是模型每轮都要付出的延迟成本
• 决策确实依赖 Hook 看不到的对话上下文——Hooks 获得的是工具载荷,而不是对话历史

组合模式

这四种基础机制叠加使用时最为强大。将它们投入生产后,我们总会反复回到下面几种组合。如果你刚开始使用 Claude Code,可以先照着这些模式搭建,再考虑发明自己的方案。

模式一:Plugin 同时分发 Skill 与 Hook

一个名为 brand-pdf 的 Plugin 同时提供 pdf-generation Skill(生成公司品牌 PDF 所需的流程知识)与 PostToolUse Hook;后者会在每次 PDF 渲染后运行,把文件路径和大小记录到 brand-pdf.log。Skill 是教学层(“这是制作 PDF 的方法”),Hook 是可观测层(“列出本季度生成的每一份 PDF”)。将两者放进同一个 Plugin,队友只需安装一次就能获得两种行为。如果分开发布,三名队友中很可能有两人只安装其中一项,导致可观测数据不完整。

模式二:子智能体为专业任务载入 Skill

.claude/agents/ 下的 code-reviewer 子智能体拥有严格的系统提示词(“你负责审查代码”)和工具白名单(Read, Grep, Glob)。父智能体调用它后,由于 Skill 描述与当前对话匹配,子智能体会从 .claude/skills/code-review/ 载入 code-review Skill。随后,它逐个文件执行 Skill 中的五项检查清单,并向父智能体返回结构化报告。父智能体不会看到文件读取过程,只会收到报告。同一项 Skill 也可以在主对话中使用;子智能体只是为它提供一间干净的工作室。

模式三:SessionStart Hook 为 Skills 预置上下文

SessionStart Hook 会取得当前 Git 分支、当前 Jira 工单和值班工程师姓名,再以系统消息形式将它们注入上下文。稍后当某项 Skill 在会话中激活时(例如 deploy-runbook Skill),它便能访问这些上下文,直接引用“当前工单”,模型无须再调用工具查询具体是哪张工单。Hook 负责确定性地获取环境信息,Skill 负责执行工作流。两者结合时体验顺畅;分开使用则每次会话都需要人工提示。

模式四:PreToolUse Hook 加固子智能体

子智能体会继承 Frontmatter 中的工具白名单,也会继承父智能体的 Hook 配置。这意味着,settings.json 中阻止危险 Bash 操作的 PreToolUse Hook,会自动应用于主智能体启动的每个子智能体。因此,你可以放心启动研究型子智能体,相信它不会意外清空某个目录,即使它的系统提示词很短、安全推理也不够充分。Hook 是最后一道防线,而且默认覆盖整棵智能体树。

模式五:Plugin 分发精选 MCP 集合与 Hook

一个名为 linear-stack 的 Plugin 提供 Linear MCP 服务器配置,以及一个 UserPromptSubmit Hook。后者会扫描用户提示词中的 Linear Issue Key(例如 ENG-1234),通过 Linear MCP 预先获取这些 Issue,并把取得的 Issue 正文注入上下文。Hook 负责确定性获取,MCP 服务器负责经过身份验证的网络操作。模型无须记得“哦,我应该查一下那张工单”——用户提到工单的同一轮,它就已经进入上下文。这种模式可以推广:只要某个 MCP 服务器能根据标识符返回丰富上下文,就可以配一个 UserPromptSubmit Hook,预先获取提示词中出现的标识符。

模式六:Skill 解释 Plugin 提供的斜杠命令

Plugins 可以通过 Markdown 文件提供斜杠命令。像 /ship 这样的命令可能是一份 200 行脚本。把文档写在命令 Markdown 中,方便快速查看;再把它写成 Skill(例如 ship-command,描述为“用户正在使用 /ship 命令或询问其工作方式”),模型就能解释、调试这个命令,并在出现故障时调整它。Plugin 负责提供命令,Skill 负责提供有关命令的知识。两者都位于同一个 Plugin 软件包中。

决策流程图

五个问题,四种基础机制。从上到下依次回答;在第一个“是”处停下,几乎每次都能选到正确机制。

1、即使模型决定不做,这件事也必须发生吗?

是 → Hook。Hooks 会在生命周期事件发生时确定触发,模型无法拒绝。策略强制执行、审计日志和始终开启的上下文注入都属于这里。

2、这个旁路任务是否会产生父智能体无须保留的输出?

是 → 子智能体。启动全新上下文,让子智能体完成嘈杂工作,只取回摘要。代码审查、深度文件扫描与研究总结都能从中受益。

3、这项行为是否要教会模型一套在相关场景中自动激活的工作流?

是 → Skill。编写 SKILL.md,在描述中说明模型应匹配的对话场景。编码约定、报告模板、审查清单与 Runbook 都属于这里。

4、是否需要让多人安装整套技术栈,而且支持版本管理与回滚?

是 → Plugin。把 Skills、子智能体、Hooks 与 MCP 服务器配置打成一个包,通过市场或 Git URL 发布,再用 /plugin install 安装。

5、以上都不是?

那么它可能只适合写成 CLAUDE.md 中的一行说明;如果任务需要经过身份验证才能访问实时外部系统,也可能需要 MCP 服务器。关于 MCP 与 Skill 的决策矩阵,请参阅我们的深度文章 Skills、MCP、子智能体与 CLI 对比

这套流程图之所以按此顺序工作,是因为强制执行是最强约束(Hook 无法被选择退出),隔离是第二强约束(子智能体保证拥有干净上下文),教学排在第三(Skills 依赖模型识别相关性),而分发与前三者彼此正交。如果跳过这个顺序,在本该使用 Hook 的场景中选择 Skill,你很可能一周内就会把它重写成 Hook。

我们在生产环境中见过的陷阱

Skills 的描述模糊,导致始终无法激活

模型通过比较对话与 Skill 的 Frontmatter description 来决定是否载入 Skill。“对代码相关任务很有用”这样的描述既匹配一切,又什么都匹配不到,于是模型只能依据其他信号作选择,你的 Skill 也就被忽略了。请像向新员工解释何时使用某项 Skill 那样编写描述:列出症状(“用户要求 PDF、可打印文档或品牌化报告”),而不是能力。60 个词的激活契约总比 10 个词的描述更有效。

PreToolUse Hooks 报错后把你锁在门外

如果 PreToolUse Hook 脚本崩溃(存在拼写错误、缺少 jq,或文件权限不正确),其失败方式可能会彻底阻止匹配的工具。本来只想阻止 rm -rf 的 Hook 如果反而阻止了所有 Bash,就很难调试,因为模型无法运行任何诊断命令。请始终先在 .claude/settings.local.json 中测试 Hooks——该文件会被 Git 忽略,因此损坏的 Hook 只会影响你自己的会话。先测试 chmod +x,再分别测试有意触发和有意不触发的输入。全部通过后,才能迁移到 settings.json 并提交。

忘记设置子智能体工具白名单

如果省略子智能体 Frontmatter 中的 tools 字段,它会继承一套默认白名单,而范围往往比你想象的更广——包括 Bash 与写入工具。为只读工作命名的子智能体(如 codebase-explorerresearch-summarizer)应明确只列出 Read, Grep, Glob,不要包含其他工具。“子智能体无法写入”这项安全属性必须由你主动声明。

Plugins 分发了未经测试的 Hooks

Plugin 中的 Hooks 会以每位队友的文件系统权限在其电脑上运行。某个 Hook 可能在作者的 Mac 上正常工作(Bash 5、GNU jq),却在队友的 Linux 电脑或旧版 Shell 上出现异常。请把 Plugin Hooks 当作生产脚本:发布 Plugin 前至少在两种环境中测试;能固定工具版本时就固定;Hook 语义改变时提升 Plugin 版本。Plugin 清单中的 version 字段就是你的回滚杠杆。

Skills 互相争抢激活机会

安装超过五六项 Skills 后,它们的描述就会开始争抢模型注意力。描述相似的两项 Skills(例如 code-reviewpr-review)可能导致行为不一致:有时激活一项,有时激活另一项,有时两项同时激活。请为每类任务选定一个规范名称,并删除重复项。还要记住:每轮都会扫描每项 Skill 的描述(而非正文),因此 20 段冗长描述确实会消耗 Token。描述应保持精炼。

Hook 超时掩盖真实故障

未设置 timeout 字段的 Hook,如果脚本始终不退出,就可能无限挂起——智能体也会一直等待。更糟的是,即使设置了超时,悄然超时的 Hook 也不会发出 deny 决策,工具仍会照常运行。请始终设置严格的 timeout(多数检查给 5~10 秒已经很宽裕),并让脚本在超时时自行干净退出,不要依赖运行时清理。如果 Hook 中运行了缓慢操作(例如网络请求),请将其改为异步执行并写入磁盘,不要阻塞智能体循环。

把 Plugin 当作私有的可变存储

Plugins 位于 ~/.claude/plugins/,看起来就像本地文件,因此有人会直接在自己电脑上编辑它们——修改 Skill 正文或 Hook 脚本。下一次 /plugin update 会覆盖这些改动。如果想在本地定制 Plugin 行为,请覆盖它:创建一项与 Plugin Skill 同名的本地 Skill(本地文件优先),或添加一个在 Plugin Hook 之后运行的本地 Hook。绝不要直接编辑 Plugin 文件。

常见问题

Claude Code 中的 Skills、子智能体、Plugins 与 Hooks 有什么区别?

Skills 是 Markdown 流程文档(带 YAML Frontmatter 的 SKILL.md),当对话与描述匹配时,Claude 会将其载入。子智能体是生成的子 Claude 实例,拥有自己的上下文窗口、系统提示词与工具白名单,通过 .claude/agents/ 下的 Markdown 文件定义。Plugins 是通过 /plugin 命令安装的可分发软件包,能够把 Skills、子智能体、Hooks、MCP 服务器与斜杠命令作为一个整体交付。Hooks 是注册在 settings.json 中的确定性事件处理程序,会在 PreToolUse 或 UserPromptSubmit 等生命周期事件中运行 Bash 命令,并能阻止或修改 Claude 的行为。Skills 负责教学,子智能体负责隔离,Plugins 负责分发,Hooks 负责强制执行。

Skills、子智能体、Plugins 与 Hooks 能否一起使用?

可以,它们能够组合。一个 Plugin 可以在同一软件包中提供两项 Skills、一个子智能体与一个 Hook。子智能体可以在任务中途载入 Skill。Hook 可以在 SubagentStop 时运行,把结果写回磁盘。Skill 可以记录 Plugin 安装的某条斜杠命令究竟如何使用。这四种基础机制被刻意设计成彼此正交:Skills 承载指令,子智能体承载隔离上下文,Plugins 承载分发,Hooks 承载确定性的强制执行。使用几个月后,大多数生产级 Claude Code 配置最终都会运行其中至少三种。

什么时候应该编写 Skill,而不是使用子智能体?

当流程属于可复用知识时,请编写 Skill,例如编码约定、工作流、模板或检查清单。主对话会按需载入并直接应用。如果旁路任务会让主上下文充满日志、搜索结果或以后再也不会引用的文件扫描结果,请启动子智能体。子智能体得到全新的上下文窗口,完成工作后只返回摘要。许多配置会将两者结合:使用子智能体完成代码审查,再载入定义审查清单的 Skill。

Hooks 在 Claude Code 的 settings.json 中放在哪里?

Hooks 配置在 settings.json 顶层的 hooks 键下,可以分为三个作用域:~/.claude/settings.json(用户级)、.claude/settings.json(项目级,可通过 Git 共享)和 .claude/settings.local.json(项目级,被 Git 忽略)。Plugins 也可以通过 ~/.claude/plugins/<name>/hooks/hooks.json 提供 Hooks。每种 Hook 事件(PreToolUse、PostToolUse、UserPromptSubmit、Stop、SessionStart、SubagentStop、PreCompact,以及另外二十多种)对应一组 matcher 数组,每个 matcher 组又运行一组 Hook 处理程序(command、prompt、agent、MCP tool 或 HTTP)。它有三层嵌套:事件 → matcher → 处理程序。

Hook 如何阻止危险的工具调用?

有两种机制。PreToolUse Hook 脚本以退出码 2 结束,会直接阻止工具调用;脚本写入标准错误的内容会成为 Claude 看到的消息。结构化替代方案是以 0 退出,同时向标准输出写入 JSON 载荷,把 hookSpecificOutput.permissionDecision 设为 deny(也可以是 allow、ask、defer),并提供 permissionDecisionReason。结构化形式更稳健,因为 Claude 能读取原因并调整计划。一个经典示例是:使用匹配 Bash 的 PreToolUse Hook 检测 rm -rf 并返回 deny。这样无须完全禁用 Bash,也能保护代码库免受智能体导致的数据丢失。

Plugins 只是一种打包格式,还是也有运行时语义?

主要是打包格式,但也有一项运行时特性。Plugin 是斜杠命令、Hooks、子智能体、Skills 与 MCP 服务器配置的集合,可以通过 /plugin 命令从市场或 Git URL 安装。安装后,其中的斜杠命令与 Hooks 会合并到你的配置中,子智能体与 Skills 会和本地定义的内容一起出现,MCP 服务器则像其他服务器一样建立连接。运行时特性在于,Plugin 资源位于 ~/.claude/plugins/<name>/,通过 $CLAUDE_PLUGIN_DIR 互相引用,从而保持项目 .claude/ 文件夹整洁。从模型视角看,已安装 Plugin 中的 Skill 与本地 Skill 没有区别。

编写大量 Hooks 会拖慢 Claude Code 吗?

如果放任不管,会。每个 PreToolUse Hook 都会在每次匹配的工具调用前同步运行,智能体必须等待退出码。一项耗时 200 毫秒的 Hook,如果匹配的工具每轮触发 30 次,就会让模型空等 6 秒。更安全的默认做法是:严格限定 matcher 的范围(例如 matcher: Bash 再配合 if: Bash(rm *),只会在 rm 调用时运行,而非每条 Bash 命令);在 Hook 配置块中设置超时(文档支持 timeout 字段);将高成本分析移至 PostToolUseFailure 或无需阻塞的异步事件。一周后请审计 Hook 耗时——多数团队都会发现,某一个 Hook 占了总延迟的一半。

Skills、子智能体、Plugins 与 Hooks 能否在 Claude Code 之外使用?

情况不一。Skills 的移植性最强——它们是带 YAML Frontmatter 的 Markdown 文档,vercel-labs/skillsmastra-ai/skillsgoogle/skills 都遵循 Claude Code 所解析的同一种 SKILL.md 格式。因此,为 Claude Code 编写的 Skill 通常也能载入 Cursor、Codex、Cline,或任何实现 Agent Skills 规范的智能体。子智能体、Plugins 与 Hooks 则更具 Claude Code 专属性。Cursor 有自己的 Rules 系统,OpenAI Codex 有自己的委派机制,大多数编辑器尚未暴露 Hook 生命周期。如果可移植性是硬性要求,请以 Skills 作为载体,并把 Plugin、Hook 与子智能体逻辑保留为 Claude Code 本地实现。

子智能体能否调用 Hook?

可以间接调用,即通过子智能体自身触发的事件。子智能体运行时,会在编排层触发 SubagentStart 与 SubagentStop Hook 事件;它自己的工具调用也会像其他智能体循环一样触发 PreToolUse 与 PostToolUse。因此,settings.json 中的 Hook 配置同样适用于子智能体——如果你设置了阻止 rm -rf 的 PreToolUse Hook,子智能体也会继承这层保护。另一个方向(由 Hook 调用子智能体)同样受支持:Hook 处理程序可以使用 type: 'agent',把匹配事件派发给子智能体处理。

如何将 CLAUDE.md 中的指令迁移到 Skills?

只要流程性章节超过约 300 个词,或开始在多个项目中重复,就应该从 CLAUDE.md 中抽离并改成 Skills。CLAUDE.md 每轮都会载入,因此适合存放简短、定义项目的信息(架构、约定、注意事项)。Skills 按需载入,更适合存放无须出现在每条提示词中的较长操作流程。大多数团队最终采用的经验法则是:CLAUDE.md 回答“这是什么项目”,Skills 回答“如何在这个项目中完成 X”。把较长内容改造成 Skills,再在 CLAUDE.md 中用一行引用替代,例如“审查清单请参阅 claude-code-review Skill”。

来源

Claude Code 官方文档

code.claude.com/docs/en/skills——Skills 编写与激活
code.claude.com/docs/en/sub-agents——子智能体、Frontmatter 字段与 Task 工具
code.claude.com/docs/en/plugins——Plugin 清单、市场与安装流程
code.claude.com/docs/en/hooks——完整 Hook 事件清单、settings.json 结构与退出码语义

开放规范与跨厂商资源

github.com/agentskills/agentskills——开放的 SKILL.md 规范(Apache 2.0)
github.com/anthropics/skills——Anthropic 的 Skills 参考实现
github.com/vercel-labs/skills——跨智能体 Skills CLI

本站相关深度文章

/blog/claude-skills-vs-mcp-vs-subagents-vs-cli-2026-decision-matrix——Skills、MCP、子智能体与 CLI 决策矩阵(姊妹篇)
/blog/cross-agent-skills-cursor-codex-cline-antigravity-gemini-mastra-portability——Skills 在不同编辑器之间的移植性
/blog/karpathy-claude-md-annotated-2026——CLAUDE.md:按需 Skills 的始终载入型姊妹机制

内部链接

/skills——Skills 目录
/servers——MCP 服务器目录
/blog——全部深度文章

当前版本准确性说明(检查于 2026-07-21)

• 本文是 MCP.Directory 的独立文章,并非 Anthropic 官方博客。
• Plugin 示例并不符合当前有效的 Plugin 目录结构。清单应位于 .claude-plugin/plugin.jsonskills/agents/commands/hooks/ 位于 Plugin 根目录;MCP 配置则是根目录下的 .mcp.json。原文展示的清单 components 对象和 mcp/servers.json 路径并非当前的发现机制。
• 当前 Plugin 路径使用 ${CLAUDE_PLUGIN_ROOT},而非 $CLAUDE_PLUGIN_DIR。已安装的 Plugin 版本位于 Claude 管理的缓存中,不应直接编辑。
• Plugins 通常通过市场安装。添加任意 Plugin 仓库不等于添加市场清单,安装项的标识形式为 plugin@marketplace。原文简化后的 Git/安装流程可能会失败。
• Plugin Skills 的命名空间形式为 /plugin-name:skill-name,因此与 Plugin Skill 使用相同短名称的本地 Skill,并不会像原文所称的那样直接覆盖它。
• Claude Code 从 v2.1.63 开始将 Task 工具更名为 Agent;Task 在设置与智能体定义中仍作为兼容别名存在。原文使用的是旧名称 Task。
• 并非所有子智能体都从空上下文开始:普通自定义子智能体拥有自己的上下文,分叉子智能体则会继承父对话。自定义子智能体也可以恢复运行、预加载 Skills 或 MCP 服务器、使用记忆,以及启动嵌套智能体。
• 父智能体最初会收到子智能体的最终响应,但“永远只能看到最终摘要”的说法过于绝对,因为可恢复智能体与后续消息能够继续这项工作。
• Skills 并非只能通过描述匹配激活。用户可以显式调用,作者可以禁用模型调用或用户调用,一项 Skill 也可以在分叉上下文中运行。
• Skills 可以捆绑脚本,并使用工具或 MCP 查询实时状态,因此实时外部数据并不绝对排除在 Skill 机制之外。通过 Agent Skills 格式实现可移植,也不能保证它在每个客户端中的行为完全相同。
• Hooks 支持 command、HTTP、MCP-tool、prompt 与 agent 处理程序;当前 MCP 处理程序类型是 mcp_tool,而非 mcp。Prompt 与 agent 处理程序会使用模型,因此虽然事件派发具有确定性,但并非每个 Hook 的结果都具有确定性。
• 未设置超时时间的 Hooks 有文档规定的默认超时,不会无限挂起。超时与失败行为因处理程序和事件而异,应该实际测试。
• Hooks 可以接收对话记录路径,而且若干事件会暴露由对话派生的字段。原文声称 Hook 只能看到工具载荷,是一种过度简化。
• Hook 支持 if 表达式,但文档称 matcher 匹配属于尽力而为。对于硬性安全边界,请使用权限拒绝规则、托管策略、最小权限、沙箱与服务器端控制,不要把正则 Hook 当作绝不可能绕过的机制。
rm -rfDROP TABLE 检查只是示例,并非完整的安全过滤器;其他 Shell 语法、参数、脚本、编码、解释器与非 Bash 工具都可能绕过它们。
CLAUDE.md 会在会话启动时载入上下文,相关文件也可能按层级载入;它并不是每条提示词都会从磁盘重新读取。原文的 300 字和五到六项 Skills 阈值是作者的经验法则,并非 Claude Code 的限制。
• 清单版本号可以支持更新追踪,但仅设置版本并不能自动保证可回滚。能否回滚取决于市场版本固定方式和实际安装/更新流程。