Kai Zhou

如何驾驭 Claude Code ?

Aug 25

本文根据 Anthropic 的《Steering Claude Code: when to use CLAUDE.md, skills, hooks, and subagents》重述而成。

指令应该放在哪里

Claude Code 可以被定制,但“把要求写进某个 Markdown 文件”并不是唯一答案。当前有七种主要方式可以影响它的行为:CLAUDE.md、Rules、Skills、Subagents、Hooks、Output styles,以及启动时追加的 system prompt。

它们真正的区别,不只是文件名不同,而是四个问题的答案不同:

  • 什么时候加载到上下文?
  • 长对话发生压缩(compaction)后,它还在不在?
  • 会持续占用多少上下文空间?
  • 这条要求究竟是给模型的建议,还是系统层面的确定性约束?

可以先用下面这张表建立全局认识:

机制加载时机长对话压缩后的行为上下文成本更适合放什么
根目录 CLAUDE.md会话开始时加载,并持续存在会话压缩后重新读取高:每一行都可能影响每次任务构建命令、目录结构、团队约定
子目录 CLAUDE.mdClaude 读取该目录下的文件时按需加载目录再次被触及时才重新出现低:只在相关目录工作时消耗某个模块的局部约定
Rules用户级规则在会话开始加载;路径规则在匹配文件被触及时加载会重新注入跨文件的约束、特定路径的规范
Skills会话开始只加载名称和描述;调用后才加载正文已调用的 Skill 按共享预算重新注入低:正文按需进入可复用的操作流程和检查清单
Subagents会话开始加载名称、描述和工具列表;被调用时才加载正文主会话只收到最终摘要低:拥有独立上下文并行搜索、日志分析、依赖审计
Hooks在生命周期事件发生时触发不受压缩影响低:配置在主上下文之外执行确定性自动化、拦截和通知
Output styles会话开始注入 system prompt不会被压缩改变 Claude 的整体角色和表达方式
追加 system prompt本次启动时传入不会被压缩,只作用于这次调用临时的语气、格式或领域要求

这张表背后的原则很简单:事实放在长期可见的位置,流程放进可调用的 Skill,必须发生的动作交给 Hook,需要隔离的工作派给 Subagent。

CLAUDE.md:项目的总说明书

根目录的 CLAUDE.md 会在会话开始时进入上下文,并在整个会话中持续生效。构建命令、代码库布局、monorepo 的边界、编码规范和团队约定,都适合写在这里。

它更像一本项目地图,而不是一份厚重的操作手册。比如:

# 项目约定

- 使用 pnpm 安装依赖。
- 前端开发服务器运行 `pnpm dev`
- 修改 API handler 后运行 `pnpm test`
- 不要直接编辑生成目录 `dist/`

根目录文件的便利也正是它的代价:无论当前任务是修复 API、调整文档,还是改一个图标,每一行都有可能被加载。文件越长,越容易出现上下文浪费和重要规则被稀释的问题。

一个实用的经验是:让根目录 CLAUDE.md 保持在两百行以内,明确维护者,并像审查代码一样审查它的变更。项目共享的内容写在仓库里,个人偏好则放到用户级配置中,不要把“我个人总是喜欢这样做”变成全团队都必须承担的上下文成本。

在 monorepo 中,可以给不同团队的目录配置自己的 CLAUDE.md。它们不会在会话开始时全部加载,而是在 Claude 真正读取对应目录中的文件时进入上下文。这种按目录延迟加载,能让局部知识只在需要时出现。

Rules:把约束绑定到路径

Rules 通常放在 .claude/rules/ 中,用来表达更具体的约束或规范。它们和 CLAUDE.md 很像,但更适合做路径范围的匹配。

例如,只有 API 代码才需要遵守输入校验规则,就可以写成:

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

所有 API handler 在处理业务逻辑前,必须使用 Zod 校验输入。

路径规则的价值在于,它不会让一次纯文档任务背上 API 规范的上下文成本。只要规则涉及一个横跨多个目录、但并非所有任务都需要的文件模式,优先考虑 paths,而不是继续往根目录 CLAUDE.md 里堆内容。

不过,Rules 仍然主要是给模型的指令。它适合表达“应该遵守什么”,却不等于“无论如何都绝不会发生”。如果某个动作必须被可靠地阻止,就不应只依赖文字规则。

Skills:把经验写成可复用流程

Skill 存放在 .claude/skills/ 中,通常包含一个 SKILL.md,也可以带上脚本、参考资料和其他资源。

Skill 的加载方式体现了渐进式披露:会话开始时 Claude 只知道 Skill 的名称和描述;只有任务匹配并真正调用它时,完整正文才会进入上下文。因此,Skill 很适合承载部署流程、发布检查、代码审查、报告生成等“知道步骤还不够,还要按顺序执行”的工作。

一个 Skill 的入口可以这样写:

---
name: release-check
description: Check a release candidate before deployment. Use for release review, deployment readiness, or pre-release verification.
---

正文中写核心流程,长篇 API 说明和指标定义放到 references/,确定性的检查则放进 scripts/。这样,Skill 既不会变成一份大而全的知识库,也不会把“请认真检查”这种模糊要求当成质量保证。

一个简单的判断方法是:

  • 如果内容是“项目一直是什么样”,写进 CLAUDE.md
  • 如果内容是“每次遇到这类任务,按这些步骤完成”,写成 Skill。
  • 如果内容是“这条命令执行前必须满足某个条件”,考虑 Hook 或权限控制。

Skill 的优势是可复用、可组合,而且过程发生在主会话中。用户可以看到每一步,也可以在执行过程中调整方向;这也是它与 Subagent 的重要区别。

Subagents:把旁支工作隔离出去

Subagent 是存放在 .claude/agents/ 中的独立助手定义。它们也会在会话开始时暴露名称、描述和工具列表,但详细指令只有在主 Agent 通过 Agent 工具调用它时才加载。

它最重要的特性不是“多一个助手”,而是独立上下文。Subagent 在自己的上下文窗口中完成工作,主会话最终只收到它的摘要和元数据,中间搜索结果、日志和尝试过程不会全部挤进主上下文。

这让 Subagent 很适合处理:

  • 深度搜索一个大型代码库;
  • 分析一批构建或生产日志;
  • 独立做一次依赖或安全审计;
  • 把多个互不依赖的目录并行检查一遍。

选择 Skill 还是 Subagent,可以看你是否希望过程留在眼前:

需求更适合
希望主会话展示并引导每个步骤Skill
希望旁支任务独立完成,只返回结论Subagent
需要并行处理多个互不依赖的任务Subagent
需要把一套流程做成团队可重复使用的操作手册Skill

Subagent 不是无限扩张上下文的办法。它仍然会消耗模型调用和 token,只是把中间过程隔离开了。对于需要人类在每一步做决定的探索性任务,也不要把它当成无人值守的替代品。

Hooks:把“应该做”变成“必定执行”

Hooks 是在 Claude Code 生命周期事件发生时触发的用户定义动作,可以是命令、HTTP endpoint、MCP 工具调用,也可以是 prompt 或 agent 类型的处理器。它们通常注册在 settings.json、托管策略配置,或 Skill/Subagent 的 frontmatter 中。

Hooks 与前面几种机制最大的区别是:它们由运行时在事件发生时触发,而不是等待模型记住一条指令再自行决定是否执行。

因此,下面这些需求适合交给 Hook:

  • 文件修改后自动运行 lint;
  • 会话结束后向 Slack 发送通知;
  • 某类危险命令执行前进行检查;
  • 在上下文压缩前备份聊天记录。

例如,PreToolUse hook 可以检查即将执行的工具调用;如果发现不允许的操作,以退出码 2 拒绝这次调用,并把原因反馈给 Claude。这样,“不要删除生产数据”就不再只是一句可能被遗忘的提醒,而变成了一个真正的执行边界。

这里需要区分两种可靠性:命令、HTTP 和 MCP 类型的 Hook 可以确定性地执行;prompt 和 agent 类型的 Hook 仍然需要模型判断输出内容。后两者比普通提示更结构化,但不能把它们误认为完全等价于程序规则。

Hook 的另一个特点是上下文成本很低。大多数执行结果不会自动进入主上下文,只有阻止调用时的错误信息等必要输出才会返回。因此,如果 Hook 在 PreCompact 时把历史保存到某个文件,Claude 并不会自动知道这个文件的路径;需要显式把信息返回,或者在其他规则中告诉它去哪里找。

Output styles 与追加 system prompt:改变整体语气的两把工具

Output style 存放在 .claude/output-styles/ 中,会在会话开始时注入 system prompt,并且不会被压缩。由于它处在系统提示层,约束力度较高,也会持续占据上下文空间。

它适合做比较大的角色调整,比如把编码助手变成教学助手,或者让输出长期采用某种报告风格。但要留意:自定义 output style 默认可能替换 Claude Code 原有的编码指令,包括改动范围、安全注意事项和测试习惯。除非明确保留编码指令,否则你可能得到一个“会写代码、却忘了自己应该怎样安全地改代码”的通用助手。

如果只想临时增加要求,启动时追加 system prompt 往往更合适。它是附加的,不会替换默认角色,而且只对本次调用生效:

claude --append-system-prompt "所有回答先给出结论,再给出最小必要的验证步骤。"

它的缺点也很明确:每次启动都要传入,且指令越多,模型越容易在多个要求之间分散注意力。临时格式要求、特定领域背景和一次性的编码规范适合放在这里;需要跨会话稳定存在的内容,则应该回到项目文件或可复用机制中。

常见的错位

“每次都要自动运行”写进 CLAUDE.md

如果目标是每次编辑后都运行格式化工具,那么让 Claude“记得去运行”不如配置一个 Hook。模型选择执行和运行时自动执行,是两种不同的可靠性。

“绝对不能做”只写成一句提示

面对删除、支付、安全和生产环境等高风险动作,文字指令不应是唯一防线。应该结合 Hook、权限配置,必要时使用组织级托管设置。托管设置由管理员部署,用户本地配置不能覆盖,才适合承载组织范围的确定性护栏。

把三十行操作流程塞进 CLAUDE.md

CLAUDE.md 应该告诉 Claude 项目是什么样,Skill 才应该告诉它如何完成一套流程。把发布手册、事故响应和安全审查清单全部常驻,会让每一次无关任务都付出上下文代价。

没有路径范围的 API 规则

只对 src/api/** 生效的约定,不应在所有会话里无条件加载。给 Rule 加上路径范围,既减少干扰,也让规则的适用边界更加可读。

把个人偏好写进项目配置

“我喜欢语义化提交信息”是个人偏好;“团队所有提交都必须遵守某种格式”才是项目规范。前者应该放在用户级配置,后者才进入共享仓库。

选型口诀

当你不知道某条指令该放在哪里时,可以按下面的顺序判断:

  1. 它是项目的稳定事实吗?是的话,放根目录 CLAUDE.md
  2. 它只对某个目录或文件类型有效吗?是的话,使用路径范围的 Rule 或子目录 CLAUDE.md
  3. 它是一套需要复用的操作步骤吗?是的话,写成 Skill。
  4. 它是旁支任务,且中间结果不值得污染主会话吗?是的话,派给 Subagent。
  5. 它必须在某个事件发生时自动执行,或必须阻止某种行为吗?是的话,使用 Hook 和权限控制。
  6. 它只想改变这次会话的角色、语气或格式吗?使用追加 system prompt;如果是长期的整体角色变化,再考虑 Output style。

这些机制不是彼此竞争的七个“高级提示词入口”,而是一套分层系统:上下文负责提供事实,规则负责表达约束,Skill 负责组织流程,Subagent 负责隔离工作,Hook 负责确定性执行,Output style 和 system prompt 负责调整全局行为。

少写常驻提示,多做正确分层

Claude Code 的可定制性越强,越容易把所有经验都塞进同一个 CLAUDE.md。但真正成熟的配置,通常不是“写得更多”,而是“放得更对”。

可以把这套分工压缩成一句话:长期事实放在 CLAUDE.md,局部约束放在 Rules,可复用流程放在 Skills,隔离任务交给 Subagents,确定性动作交给 Hooks,临时全局要求使用 system prompt。

当这些机制各司其职,Claude Code 获得的就不只是一份更长的提示,而是一套更节省上下文、更容易维护、也更可靠的工作环境。

原文:Michael Segner,Anthropic,2026 年 6 月 18 日,Steering Claude Code: when to use CLAUDE.md, skills, hooks, and subagents


>