Claude Code 规则到底怎么工作
“Claude Code rules” 这个说法经常被宽泛使用。有时它指 CLAUDE.md。有时指 slash command definitions。有时指 hook configurations。有时指 MCP server permissions 或 tool restrictions。这些部分会以不明显的方式互相影响。一条在某一层能工作的规则,可能会被另一层悄悄覆盖。这篇会梳理真实 loading order、每一层能做什么和不能做什么,以及最常见的困惑来自哪里。
Claude Code 里的 “rules” 指什么
到 2026 年初,Claude Code 至少有六个可以放规则的地方。每一层影响 agent 的方式不同,有自己的 loading semantics,也会以特定方式和其他层互动。
第一层是 CLAUDE.md,包括 user-global 的那份(~/.claude/CLAUDE.md 或 ~/CLAUDE.md)和 project-local 的那份。它们是 markdown prose,会在会话开始时加载进 agent 的 context。它们建立操作 context 和行为规范。
第二层是 settings.json,同样分 user-global 和 project-local。hooks、permissions、environment variables、plugin configuration 都住在这里。Settings.json 是 config,不是 prose。agent 不读它;harness 读它,并执行它写的东西。
第三层是 hooks。它们是 lifecycle events(SessionStart、PreToolUse、PostToolUse、PreCompact、Stop)触发的 shell scripts。Hooks 在 settings.json 里配置,由 Claude Code runtime 执行。它们可以把 text 注入会话、拦截 tool calls、跑 validations,或者发 notifications。
第四层是 slash commands。它们是 ~/.claude/skills/ 或 .claude/skills/ 里的 markdown files,文件名是 invocation triggers。当你输入 /handoff 或 /review,你是在调用一个 skill。Skills 可以规定 workflow、限制 tool access,或要求特定输出。
第五层是 MCP server permissions。它们是 settings.json 里的 entries,用来 allow 或 deny MCP servers 上的具体 tools。这是最细粒度的 access control。
第六层是 environment-level constraints。包括 environment variables、permission modes(auto、plan、bypassPermissions)和 runtime flags。这些通常由启动它的 shell 或 Claude Code CLI 自己设置。
Loading order
会话开始时,harness 按下面顺序加载。理解这个顺序,决定了一条规则能工作,还是被悄悄覆盖。
第一步:environment-level constraints 先加载。 Permission mode 被设置,environment variables 被绑定,working directory 被确定。会话内部的任何东西都不能改变它们。
第二步:settings.json 加载。 user-global 和 project-local 都会加载。project-local settings 叠在 user-global 上面。Hooks 被注册,MCP servers 被连接,plugin lists 被解析。
第三步:SessionStart hooks 触发。 每个注册的 SessionStart hook 都作为 shell command 运行。它们的 stdout 会作为 system-reminder messages 注入会话。这一层可以动态注入 context;它也是最容易带来惊讶的一层,因为 hook output 在 agent 实际收到之前是不可见的。
第四步:CLAUDE.md 加载。 先 user-global,再 project-local。内容被加进 session context。CLAUDE.md 不能 override settings.json 或 hooks;它只能在这些层设定的约束里描述行为规范。
第五步:agent 的第一轮开始。 用户第一条消息到达。agent 的回应被上面加载的所有东西塑造。
当某件事看起来“不对”时,比如规则没被遵守、tool 不可用、hook 没触发,debug protocol 是沿 loading order 往回走,逐层检查。
CLAUDE.md 能做什么,不能做什么
CLAUDE.md 是 prose。它能描述规范、编码决定、解释 reasoning。它不能执行。
它可以说 “All changes go through PR.” 它不能阻止 agent 直接调用 git push 到 main。如果 harness 允许,push 就会发生;只有 git push 上的 PreToolUse hook 才能真正拦住它。
它可以说 “Run lint before commit.” 它不能运行 lint。只有 pre-commit hook(Husky 或类似工具)能运行 lint。
它可以说 “Use TypeScript strict mode.” 它不能让 tsc 变 strict。只有 tsconfig.json 能。
这是最大的困惑。作者写了一条 CLAUDE.md 规则,看 agent 遵守了一周,就以为规则被执行了。然后 agent 换了一个会话:不同 context、不同注意力压力、不同 temperature,规则就被悄悄违反了。教训是:每条重要规则,都需要 CLAUDE.md 下方的一层来做实际 enforcement。
hooks 能做哪些 CLAUDE.md 做不了的事
hooks 是真正执行的地方。常见有三种模式。
阻止 tool invocations。 Bash 上的 PreToolUse hook 可以检查即将运行的 command,并用 non-zero exit 拦截它。很多 setup 里的 push-gate hook 会拦住从非 main branch 执行的 git push origin main,除非 review step 已经跑过。
动态注入 context。 SessionStart hook 可以跑一个 script,拿到当前 branch、recent commits、open PRs,并把一行 summary 注入会话。有些团队就是这样每次会话都给 agent 一份新 briefing,同时不把 CLAUDE.md 写胖。
行动后验证。 Edit 或 Write 上的 PostToolUse hook 可以对修改过的文件跑 linter 或 typecheck,并注入结果。agent 会把 validation output 当作 system-reminder 看到,并且能在同一轮里反应。
hooks 的问题是:它们跑在用户机器、用户 shell、用户 environment 里。一个 hook script 如果假设某个 tool 在 PATH 上、某个 directory 存在、某个 environment variable 已设置,在不同条件下就会悄悄失败。稳的模式是给 hook scripts 加明确 checks 和 fallbacks。
Slash commands 是带范围的 rule sets
Slash commands(skills)是把规则限定到具体 workflows 的地方。一个 skill 是带 frontmatter 和 body 的 markdown file。frontmatter 声明 triggers 和 constraints。body 会在 skill 被调用时读进 agent 的 context。
这就是你表达“只在 handoff workflow 里,文件格式必须遵守 Schema A 或 B”的方式,而不用把 CLAUDE.md 塞满 handoff-specific 规则。skill 只在 workflow 发生时激活。其他时候,skill 里的规则是 dormant,不消耗 context budget。
2026 年的趋势,是把 workflow-specific rules 从 CLAUDE.md 移到 skills。CLAUDE.md 变成 always-loaded、project-wide 的 rule set;skills 变成 workflow-loaded、scoped rule sets。这样 CLAUDE.md 保持短,而具体 workflow 仍然可以有更丰富的规则,并且不用每个会话都付成本。
困惑从哪里来
大多数 “rules don't work” 投诉来自三种模式。
把 CLAUDE.md 和 enforcement 混为一谈。 上面已经讲过。CLAUDE.md 描述;harness 执行。如果规则下面没有 hook 或 CI check,它就是 advisory。
分层 override 不清楚。 user-global CLAUDE.md 里的一条规则,被 project-local CLAUDE.md 里一条冲突规则覆盖,但这个 override 不一定是有意的。agent 会读两份文件;如果它们冲突,agent 可能根据措辞选择任意一条。修法是:project-local 规则在 override 时明确写 “overrides ~/CLAUDE.md § X”。
hook scripts 悄悄失败。 SessionStart hook 出错不会让 session crash。它只是没有注入本来该注入的内容。会话继续,但缺了 context。这会制造 “agent didn't know X” 这类很难诊断的 bug,因为表面上什么都没失败。修法是把 hook failures 记录到持久 log,并在行为奇怪时检查 log。
合在一起看
能把层次理清的 mental model 是:CLAUDE.md 是 agent 的阅读材料;settings.json + hooks 是 agent 的环境;skills 是 scoped briefings;environment constraints 是 agent 的硬限制。规则要放在有合适牙齿的层。带硬后果的流程规则放 hooks。workflow-specific rules 放 skills。行为规范放 CLAUDE.md。硬 access controls 放 MCP permissions。试图从错误层执行规则,就会产生让很多刚用 Claude Code 的团队很挫败的 silent failure。
如果你在给新项目设置 rules,顺序是:写 ~/CLAUDE.md 放 global norms,写 project CLAUDE.md 放 project-specific decisions,写 hooks 执行 process rules,写 skills 放 workflow-scoped rule sets,设置 MCP permissions 控 tool access。用 AgentLint 保持 CLAUDE.md files 诚实。这个系统看起来复杂,但分层是一致的。一旦你理解分层,“Claude Code rules” 就不再是模糊短语,而是一个可以 debug 的具体 architecture。