Claude Code 指令路由指南:CLAUDE.md、Rules、Skills、Subagents 与 Hooks 怎么选

别再把所有要求都塞进 CLAUDE.md:用加载时机、压缩存续与执行权威设计可维护的 Agent 配置

Posted by iceyao on Thursday, June 25, 2026

一、引言:问题不是“指令怎么写”,而是“指令放哪里”

原文链接:Steering Claude Code: CLAUDE.md files, skills, hooks, rules, subagents and more
来源:Claude Blog / Anthropic
发布时间:2026 年 6 月 18 日

团队刚开始使用 Claude Code 时,最自然的做法是建一个 CLAUDE.md:写上构建命令、目录结构、编码规范,再补一句“每次改完都运行测试”和一句“永远不要碰生产配置”。短期内它很有效,几周后却往往变成一份没人敢删的指令仓库。

问题不在于这些要求写错了,而在于它们属于不同的控制机制:

  • 仓库结构是每次会话都需要的背景事实;
  • API 校验只在读取 API 文件时才相关;
  • 发布检查是一套按需执行的流程;
  • 依赖审计适合放到独立上下文中运行;
  • 禁止危险命令不是“提醒”,而应该是执行前的硬拦截;
  • 回答语气只是本次启动参数,不必永久写入项目文件。

Anthropic 的原文把 Claude Code 的七种定制方式放进同一张表中。比功能列表更重要的,是它揭示了一个配置设计原则:每条指令都应该被路由到与其生命周期和权威等级匹配的位置。

Claude Code 七种指令机制总览

本文不重复介绍每个功能的完整配置语法,而是回答一个更实用的问题:当手里有一条具体要求时,应该把它放进 CLAUDE.md、Rule、Skill、Subagent、Hook、Output style,还是启动参数?


二、先看三条轴:加载时机、压缩存续、执行权威

给 Claude Code 的指令并不是放进文件就结束了。它最终会在某个时刻进入模型上下文,在长会话中经历压缩,并以不同强度影响行为。选型前先问三个问题。

2.1 它什么时候需要进入上下文?

指令加载得越早、驻留得越久,使用越方便,但固定 Token 成本也越高。

  • 根目录 CLAUDE.md 在会话开始时加载,适合全局背景;
  • 无路径限定的 Rule 同样是常驻指令;
  • 子目录 CLAUDE.md 和带 paths 的 Rule 在相关文件被触及时才加载;
  • Skill 在会话开始时只暴露名称和描述,正文被调用时才进入上下文;
  • Subagent 的完整提示词运行在独立上下文中,父会话只接收最终结果;
  • Hook 的配置主要由 Claude Code 运行时执行,通常不占主上下文。

这意味着“按需加载”并不是单纯省 Token。它还减少了无关约束之间的竞争,让当前真正相关的指令更容易被遵循。

2.2 长会话压缩后,它还在吗?

Claude Code 会对过长的会话进行 compaction。不同机制在压缩后有不同命运:

  • 根目录 CLAUDE.md 会被重新读取;
  • Rule 会被重新注入,但路径限定 Rule 仍要再次触及相关路径;
  • 已调用 Skill 会在共享预算内重新注入,调用过多时较早的 Skill 可能被丢弃;
  • 子目录 CLAUDE.md 在压缩后暂时消失,直到对应目录再次被触及;
  • Subagent 的中间过程本就不进入父上下文,只有最终消息和元数据返回;
  • Hook 挂在运行时事件上,不依赖主对话是否被压缩;
  • Output style 和追加的系统提示位于系统提示层,不会被 compaction 移除。

所以“最初告诉过 Claude”不等于“长会话后它仍以相同方式存在”。如果某条要求关系到安全或合规,依赖上下文记忆本身就是错误的实现方式。

2.3 它是在表达意图,还是在强制执行?

这是七种机制之间最关键的分界线。

CLAUDE.md、Rules、Skills 和系统提示本质上都在告诉模型“应该怎么做”。模型通常会遵守,但它们仍属于概率性控制:会话过长、约束冲突、任务含糊或外部文件含有提示注入时,都可能降低遵循率。

Hook 与权限系统则可以把要求变成执行路径的一部分。例如 PreToolUse Hook 可以检查工具调用,并以退出码 2 拒绝执行。此时不是模型“记住不要做”,而是运行时真的不让它做。

指令选型的三条主轴

一句话概括这三条轴:

背景事实看相关性,流程看复用性,安全边界看确定性。


三、七种机制分别负责什么

3.1 CLAUDE.md:让 Claude 始终知道“这是一个怎样的仓库”

根目录 CLAUDE.md 适合放每次任务都可能需要的稳定事实:

  • 常用构建、测试和格式化命令;
  • 顶层目录结构与模块边界;
  • monorepo 中各工作区的关系;
  • 团队级编码约定;
  • 指向更详细文档、Rules 和 Skills 的索引。

原文给出的经验值很具体:尽量把根 CLAUDE.md 控制在 200 行以内,指定维护者,并像审查代码一样审查它的变更。 这不是对 Markdown 长度的审美偏好,而是上下文预算问题:根文件中的每一行都会进入每位工程师的每次会话,无论当前任务是否需要。

子目录 CLAUDE.md 的行为不同。它只在 Claude 读取该目录下的文件时加载,适合一个目录内相对完整、局部生效的背景说明。monorepo 中可以让每个团队维护自己的子目录文件,避免所有人都背着整座仓库的规则工作。

判断标准可以这样记:

  • 全仓库的地图与共同语言:根 CLAUDE.md
  • 一个目录自己的局部地图:子目录 CLAUDE.md
  • 跨多个目录、按文件模式生效的约束:优先用 path-scoped Rule。

3.2 Rules:给特定文件附加精确约束

Rules 位于 .claude/rules/。不带作用域的 Rule 在会话开始时加载,与把内容直接写进根 CLAUDE.md 的上下文成本接近;真正有区分度的是带 paths 的 Rule。

例如,只有 API Handler 需要 Zod 入参校验:

---
paths:
  - "src/api/**"
  - "**/*.handler.ts"
---

所有 API Handler 在处理请求前必须使用 Zod 校验输入。

当 Claude 只修改文档时,这条规则不进入上下文;读取 src/api/*.handler.ts 后才会加载。数据库 migration 只增不改、前端组件必须满足无障碍属性、Terraform 文件需要特定标签,都属于类似场景。

Rule 最适合回答的是:“处理这一类文件时,有哪些必须遵守的局部约束?”

3.3 Skills:把流程从背景说明中拆出来

Skill 是包含 SKILL.md、脚本和参考资料的目录。会话开始时只加载名称和描述,完整正文在显式调用或语义匹配后才进入上下文。

适合 Skill 的内容通常带有顺序和完成条件:

  • 发布前检查清单;
  • 数据库迁移流程;
  • 安全审查步骤;
  • 文档生成与渲染验证;
  • 事故复盘模板。

如果一条指令中出现“先……再……最后检查……”,它大概率不是仓库背景,而是一套 procedure,应该进入 Skill。Skill 的好处不仅是按需加载,还在于它可以携带脚本、模板和示例,让同一流程在不同会话中稳定复用。

需要注意的是,已调用 Skill 在 compaction 后的重新注入受共享预算限制。一个会话同时调用许多大型 Skill 时,较早的 Skill 可能先被丢弃。因此 Skill 仍应保持入口简洁,通过引用文件渐进加载细节,而不是把整本手册塞进一个 SKILL.md

3.4 Subagents:隔离不值得留在主线里的过程

Subagent 定义在 .claude/agents/,拥有自己的提示词、工具权限和独立上下文。父会话在开始时只知道它的名称、描述和工具列表;调用后,完整工作过程发生在子代理窗口中,最终只把结果摘要和元数据带回主会话。

它适合两类任务:

  1. 可以并行的侧线工作,例如同时审计依赖、搜索日志、梳理不同模块;
  2. 会产生大量中间噪音,但主线只需要结论的工作,例如深度检索和全仓库静态分析。

Skill 与 Subagent 经常被混淆。一个简单判断是:

  • 希望流程在主会话里展开,用户能逐步观察和调整:用 Skill;
  • 希望过程隔离,只把压缩后的结果带回来:用 Subagent。

两者也可以组合:一个代码审查 Skill 并行启动安全、性能和风格三个 Subagent,最后在主会话综合结论。

3.5 Hooks:把“应该执行”升级为“必然触发”

Hook 在会话开始、工具调用前后、压缩前或代理停止等生命周期事件上触发。它可以运行 command、HTTP、MCP 工具,也可以启动独立的 prompt 或 agent 判断。

原文对“确定性”做了一个值得保留的细分:所有 Hook 都会在匹配事件上确定性触发,但不同处理器的结果并不都确定。 command、HTTP 和 mcp_tool 执行固定逻辑;prompt 与 agent Hook 虽然必然被调用,其输出仍由模型判断。

典型用法包括:

  • PostToolUse:文件修改后自动运行 formatter;
  • PreToolUse:执行前拦截危险命令或敏感路径;
  • SessionStart:注入当前分支和任务状态;
  • PreCompact:压缩前备份会话记录;
  • Stop:结束前检查测试是否真正通过。

“每次修改后都格式化”如果写在 CLAUDE.md 中,只是希望模型每次记得;放进 Hook,才是每次事件真的触发。对于“绝不允许读取密钥”之类的边界,还应结合 permissions 与组织级 managed settings,而不是仅靠自然语言禁令。

3.6 Output styles:谨慎修改 Claude 的角色

Output style 会注入系统提示,权威高、不会被 compaction 移除,也会占据持续的上下文。它适合显著的角色变化,例如把代码助手切换为教学型或通用协作助手。

风险在于,自定义 Output style 默认会替换 Claude Code 原有的输出风格,其中包含变更范围、安全处理、注释习惯和完成前验证等工程行为。除非在 front matter 中设置 keep-coding-instructions: true,否则一次看似只改语气的定制,可能顺手移除了代码助手的重要默认约束。

因此优先检查内置的 Proactive、Explanatory 和 Learning 风格。只有真正需要改变角色时,才维护自定义 Output style。

3.7 append-system-prompt:一次启动中的增量偏好

--append-system-prompt 不替换默认系统提示,只在本次启动中追加内容。它适合临时的语气、长度、输出格式或领域背景要求。

它比 Output style 安全,因为是增量而非替换;但上下文成本仍高于按需加载机制,而且指令越多,边际遵循效果越弱。把一长串团队规范塞进启动参数,既难维护,也不会因为权威层级更高就自动消除冲突。

七种机制在会话生命周期中的位置


四、一张选型表:从要求的性质反推存放位置

需求 首选机制 为什么
每次任务都要知道的仓库事实 CLAUDE.md 会话开始加载,压缩后重读
某个目录的局部背景 子目录 CLAUDE.md 触及目录时按需加载
只对一类路径生效的约束 path-scoped Rule 作用域精确,避免无关上下文成本
有步骤、模板和验收条件的流程 Skill 正文按需加载,可携带脚本与资源
产生大量中间信息的侧线任务 Subagent 独立上下文,只返回最终结果
必须在事件上自动发生的动作 Hook 由运行时触发,不依赖模型记忆
不允许绕过的组织级边界 Hook + permissions + managed settings 用确定性执行与不可覆盖策略落地
显著改变助手角色 Output style 位于系统提示层,影响持续且强
仅对本次启动生效的语气或格式 --append-system-prompt 增量、临时、不改项目文件

实际判断时,可以按下面的顺序缩小范围:

  1. 是否必须 100% 执行或禁止? 是,就先考虑 Hook、permissions 或 managed settings,不要止步于提示词。
  2. 是否每次任务都相关? 是,再考虑根 CLAUDE.md 或无作用域 Rule;否则继续缩小加载范围。
  3. 是否由文件路径决定相关性? 是,用 path-scoped Rule 或子目录 CLAUDE.md
  4. 是否是一套可重复流程? 是,用 Skill。
  5. 是否应该隔离过程,只返回结论? 是,用 Subagent。
  6. 是否只是在改变角色、语气或单次输出? 再考虑 Output style 或追加系统提示。

这套顺序有意把“确定性”放在第一问。因为安全要求一旦被误放进概率性指令层,后面无论怎样优化文案,都没有解决根本问题。


五、实战:把一个臃肿 CLAUDE.md 拆成五层

假设一个团队的根 CLAUDE.md 已经积累了以下内容:

# Project instructions

- 使用 pnpm,运行 pnpm test 验证改动。
- 所有 API Handler 必须使用 Zod 校验输入。
- 发布时先更新版本,再生成 changelog,运行完整测试并创建 tag。
- 每次修改 TypeScript 后都运行 prettier。
- 永远不要读取 .env 或执行 git push --force。
- 审计依赖时扫描所有 workspace,并只返回高危问题摘要。
- 回答尽量简短。

这些句子都合理,但混在一个文件里会产生三个问题:API 规则在文档任务中浪费上下文;发布流程每次加载却很少执行;安全禁令仍然只是软约束。

更合适的拆法如下。

5.1 根 CLAUDE.md:只保留项目地图

# Repository overview

- Package manager: pnpm.
- Run `pnpm test` to verify changes.
- Workspaces live under `apps/` and `packages/`.
- Path-specific constraints live in `.claude/rules/`.
- Reusable workflows live in `.claude/skills/`.

5.2 Rule:把 API 约束绑定到路径

---
paths:
  - "apps/api/src/**"
  - "**/*.handler.ts"
---

所有 API Handler 在处理请求前必须使用 Zod 校验输入。

5.3 Skill:把发布步骤变成可验证流程

---
name: release
description: 执行正式版本发布。用于更新版本、生成 changelog、运行发布检查并创建 tag。
---

1. 检查工作区是否干净并确认目标版本。
2. 更新版本与 changelog。
3. 运行完整测试和构建。
4. 展示待创建的 tag,得到用户确认后再执行。
5. 汇总版本、提交、测试和构建结果。

5.4 Subagent:隔离依赖审计噪音

为 dependency auditor 只开放读取与搜索工具,让它在独立上下文扫描所有 workspace,最终只返回高危依赖、影响范围和修复建议。主会话不需要保留数百条包清单和搜索过程。

5.5 Hook 与启动参数:分别处理硬边界和个人偏好

  • PostToolUse Hook 在 TypeScript 修改后运行 Prettier;
  • PreToolUse Hook 与 permissions 阻止读取 .env 和强推;
  • “回答尽量简短”作为个人用户配置或本次 --append-system-prompt,不要提交到团队项目文件。

从臃肿 CLAUDE.md 迁移到分层配置

拆分后的收益不是文件数量变多,而是每条信息获得了正确的生命周期:该常驻的常驻、该按需的按需、该隔离的隔离、该强制的强制。


六、五个高频反模式

6.1 在 CLAUDE.md 写“每次 X 都做 Y”

如果“每次”是真的每次,就使用 Hook。例如每次编辑后格式化、任务完成后通知、压缩前备份。这些动作不应该依赖模型主动想起。

6.2 在 CLAUDE.md 写“永远不要做 X”

禁令仍然是提示词,不是护栏。危险命令、敏感文件和组织合规边界应该用 PreToolUse、permissions 和 managed settings 强制执行。

6.3 把三十行操作步骤常驻在根文件

部署、发布和审查清单并非每次任务都需要。把它们变成 Skill,只在调用时加载完整流程。

6.4 写了 API 规则,却没有 paths

无作用域 Rule 与把内容放进根 CLAUDE.md 一样会常驻上下文。能由文件模式判断相关性的约束,应尽量声明 paths

6.5 把个人偏好提交到项目级文件

“总是用语义化提交”“回答短一点”可能只是个人工作方式。个人偏好放用户级配置,项目文件只承载团队共同约定;机器相关的实验配置则放本地项目级文件。


七、团队落地:把指令当作代码治理

从这套机制还能推出四条工程实践。以下是基于原文机制做出的落地归纳,而不是 Claude Code 的额外产品约束。

7.1 每条规则只保留一个权威来源

同一要求不要同时写进 CLAUDE.md、Rule、Skill 和 Hook。重复不会简单地增强遵循,反而会带来版本漂移和冲突。可以在根文件中做索引,但正文只保留在最合适的机制里。

7.2 为常驻上下文设置预算

定期统计根 CLAUDE.md 和无作用域 Rules 的行数。新增常驻指令时,评审者应该追问:“这条内容真的与大多数任务相关吗?” 如果答案是否定的,就为它寻找按需加载的位置。

7.3 为机制指定所有者与测试方式

  • CLAUDE.md:由仓库维护者审查准确性和长度;
  • Rules:用匹配路径与不匹配路径分别测试加载边界;
  • Skills:覆盖正常触发、边界输入和不应触发的请求;
  • Subagents:验证最小工具权限与返回摘要质量;
  • Hooks:测试允许、拒绝和处理器失败三条路径。

7.4 先把硬边界下沉,再优化提示词

很多团队花大量时间打磨“不要删除文件”的措辞,却没有配置工具权限。优先把能由代码和策略表达的约束下沉到确定性层,再让模型指令负责需要语义判断的部分。

Claude Code 指令机制选择流程


八、总结:配置的质量,取决于边界而不取决于数量

Claude Code 的七种定制方式并不是七套互相竞争的配置语法,而是一组不同生命周期、不同上下文成本、不同权威等级的控制面。

可以把选型压缩成六句话:

  1. 仓库地图和共同事实放 CLAUDE.md
  2. 路径相关约束放 path-scoped Rules;
  3. 可复用的多步骤流程放 Skills;
  4. 需要隔离中间过程的侧线工作交给 Subagents;
  5. 必须自动发生或绝不允许发生的行为交给 Hooks、permissions 和 managed settings;
  6. 角色变化用 Output styles,单次语气和格式用追加系统提示。

真正成熟的 Agent 配置,不是让模型在会话开始时读到更多,而是让每条指令在最相关的时刻出现,以最低必要成本存在,并用与风险相称的方式执行。

CLAUDE.md 又开始膨胀时,不妨逐条问:这是背景、局部约束、流程、侧任务、自动化,还是安全边界?答案会自然指向它该去的地方。


参考资料

「真诚赞赏,手留余香」

爱折腾的工程师

真诚赞赏,手留余香

使用微信扫描二维码完成支付