
你有没有遇到过这种情况——
CLAUDE.md 写了 300 多行,把团队的编码规范、命名规则、部署流程全塞进去了,结果 Claude Code 执行的时候该忘还是忘。换个复杂点的任务,它甚至开始自相矛盾。
我之前也是这么干的。直到某天在 Anthropic 官方文档里看到一句话,大意是:「CLAUDE.md 只是 7 种自定义方式之一,不是唯一的。」
7 种?我数了数自己用过的,只有 CLAUDE.md 和 .claude/commands/ 两种。剩下 5 种听都没听过。
后来我花了一周把这 7 种方式全部摸透,发现一个扎心的事实:大多数人把所有规则一股脑塞进 CLAUDE.md,就像把所有衣服扔进一个抽屉——看起来都在,找的时候全乱。
这篇文章不是再做一遍「7 种方式逐一介绍」的平铺结构——那种文章已经有不少了。我要做的是:先给你 5 个真实场景,让你对号入座;再给你一个决策框架,帮你以后自己判断;最后逐一拆解每种方式的原理、用法和反模式。
说白了,「什么时候不该用」比「怎么用」更重要。
在讲「怎么用」之前,先对号入座。以下 5 个场景,如果你踩过任何一个,说明你可能用错了方式。
场景一:CLAUDE.md 膨胀症
你的 CLAUDE.md 已经超过 200 行。编码规范 50 行、架构说明 80 行、部署流程 60 行、各种零碎规则 40 行。每次开会后还要往里加。结果 Claude 的遵从率越来越低——它不是不想遵守,是上下文窗口就那么大,塞太多规则它根本「看不过来」。
场景二:每次都要手敲同一段指令
每次让 Claude Code 做 Code Review,你都要粘贴同一段话:「按照我们团队的规范检查……重点关注这几个维度……输出格式是……」粘了 20 次之后你开始怀疑人生。
场景三:Claude 总是忘记「有些目录不能碰」
你在 CLAUDE.md 里写了「不要修改 legacy/ 目录的代码」,但 Claude 偶尔还是会手痒去改。不是它故意违规,是 CLAUDE.md 的规则是「建议」性质的,不是强制的。
场景四:需要 Claude 访问外部系统
你想让 Claude 直接查 Jira 看 ticket 描述、查 Sentry 看线上报错、查数据库看表结构。但 Claude Code 原生不支持这些,你只能手动复制粘贴。
场景五:复杂任务耗尽上下文
一个大重构任务,Claude 需要同时参考 10 个文件、跑测试、改代码。聊到一半发现上下文被压缩了,之前讨论的架构决策全忘了。
如果你中了 2 个以上,接下来的内容对你很有价值。
先给一张全局图,后面逐一展开。
方式 | 一句话说明 | 配置文件 | 作用域 | 强制力 |
|---|---|---|---|---|
CLAUDE.md | 持久化指令,每次会话自动加载 | CLAUDE.md(Markdown) | 组织/用户/项目/本地 | 软(上下文注入,非强制) |
Skills | 可复用工作流,按需加载 | SKILL.md(目录形式) | 企业/个人/项目/插件 | 软(调用时才加载) |
Hooks | 生命周期钩子,硬性执行 | settings.json(JSON) | 组织/用户/项目/本地 | 硬(exit code 2 阻断) |
Rules | 路径级条件规则 | .claude/rules/*.md | 项目级 | 软(CLAUDE.md 子系统) |
Sub-agents | 专用子智能体,隔离上下文 | .claude/agents/*.md | 组织/CLI/项目/用户 | 硬(工具限制生效) |
MCP Servers | 连接外部工具和数据源 | .mcp.json / CLI | 本地/项目/用户 | 硬(连接必须建立) |
Settings | 全局配置:权限、模型、环境变量 | settings.json(JSON) | 组织/用户/项目/本地 | 硬(客户端强制执行) |
关键区分:CLAUDE.md/Skills/Rules 是「建议」——Claude 会看到这些内容,但可以自行判断是否遵守。Hooks/Sub-agents/MCP/Settings 是「规则」——违反就会被阻断或无法执行。

图:7 种自定义方式的强制力和作用域对比——「建议」和「规则」的本质区别
拿到一个自定义需求时,按以下 3 个问题走决策树:
问题 1:这条规则需要「每次会话都生效」还是「特定场景才需要」?
问题 2A:规则是「告诉 Claude 怎么做」还是「强制 Claude 不能做某事」?
rm -rf、自动格式化)或 Settings(权限 deny 规则)问题 2B:这个场景是「一个可复用的工作流」还是「连接外部工具」?
问题 3:规则只适用于代码库的某个子目录吗?
.claude/rules/ 配合 paths 字段)额外判断:
.claude/commands/,已合并入 Skills 生态)用一句大白话总结:CLAUDE.md 管「是什么」,Skills 管「怎么做」,Hooks 管「不能做」,Rules 管「哪里适用」,Sub-agents 管「谁来做」,MCP 管「能连什么」,Settings 管「全局开关」。
“💬 你目前用得最多的是哪种自定义方式?
评论区说说,码哥猜选 A 的最多 😂

图:3 个问题走完决策树——拿到自定义需求时按这个流程选方式
原理
CLAUDE.md 是 Claude Code 的「长期记忆」。每次会话启动时,Claude 会自动加载这些文件的内容到上下文窗口。它不是一次性指令,而是贯穿整个会话的持久化上下文。
加载顺序(从广到窄,内容拼接而非覆盖):
/Library/Application Support/ClaudeCode/CLAUDE.md,Linux 在 /etc/claude-code/CLAUDE.md~/.claude/CLAUDE.md./CLAUDE.md 或 ./.claude/CLAUDE.md./CLAUDE.local.md(gitignore 掉,不提交)同一层级的 CLAUDE.md 和 CLAUDE.local.md 会拼接,不会互相覆盖。子目录下的 CLAUDE.md 文件在 Claude 读取该目录文件时按需加载。
支持 @path/to/file 语法导入其他文件内容,最多 4 层跳转。这个功能很实用——你可以把不同主题的规则拆成独立文件,用 @ 引入,避免单文件过大。
用法示例
# CLAUDE.md
## 项目架构
本项目是 Spring Boot 3.2 单体,Java 17。
模块结构:api/(接口层)、service/(业务层)、dao/(数据层)
## 编码规范
- 使用 2 空格缩进
- 命名规范:类名 PascalCase,方法名 camelCase,常量 UPPER_SNAKE_CASE
- Controller 不放业务逻辑,只做参数校验和路由
## 构建与测试
- 构建:`./gradlew build`
- 测试:`./gradlew test`
- Lint:`./gradlew spotlessCheck`
## 引入子规则
@docs/database-conventions.md
@api/rest-standards.md
反模式
反模式 1:文件超过 200 行
CLAUDE.md 的内容每次会话都会注入上下文窗口。文件越大,留给实际任务的上下文空间越小。超过 200 行之后,Claude 的遵从率会明显下降——不是它不想遵守,是注意力被稀释了。
解法:拆分。把长规则移到 .claude/rules/ 里用 paths 字段做路径级匹配,或用 @ 语法引入子文件。
反模式 2:写模糊指令
# 差的写法
格式化代码,保持风格统一。
# 好的写法
使用 2 空格缩进。行宽 120 字符。导入顺序:java.* → javax.* → 第三方 → 本项目。
Claude 不怕长指令,怕模糊指令。「格式化代码」这种话它理解不了你具体要什么格式。
反模式 3:在 CLAUDE.md 里写流程步骤
如果你发现自己在 CLAUDE.md 里写了「第一步做 X,第二步做 Y,第三步做 Z」——这不是 CLAUDE.md 该干的事。流程步骤应该用 Skills 封装,按需调用,不占日常上下文。
原理
Skills 是 Claude Code 的「剧本」。把一个可重复执行的工作流打包成一个 Skill,需要的时候调用,不需要的时候不占上下文。
这是和 CLAUDE.md 最关键的区别:CLAUDE.md 的内容每次会话都在上下文里,Skills 的内容只有被调用时才加载。 Skill 的描述(description)会一直留在上下文中供 Claude 判断是否需要调用,但完整内容按需加载。
配置格式
.claude/skills/
└── code-review/
└── SKILL.md
SKILL.md 由 YAML frontmatter + Markdown body 组成:
---
name: code-review
description: "按团队规范执行 Code Review,检查安全、性能、可读性"
when_to_use: "用户要求 review 代码或提交 PR 前"
argument-hint: "[file-or-pr]"
model: sonnet
effort: high
paths: ["src/**/*.ts"]
allowed-tools: Read, Grep, Glob, Bash(git *)
---
## Code Review 清单
1. 安全检查:SQL 注入、XSS、硬编码密钥
2. 性能检查:N+1 查询、大对象循环创建
3. 可读性:方法不超过 30 行、命名自解释
$ARGUMENTS 指定要 review 的文件或 PR。
几个实用的 frontmatter 字段:
context: fork — 在隔离的子智能体中运行,不污染主对话上下文disable-model-invocation: true — 只能用户手动 /skill-name 调用,Claude 不会自动触发user-invocable: false — 反过来,只有 Claude 能自动调用,用户不能手动触发model: haiku — 用更快更便宜的模型执行这个 Skill(适合搜索、探索类任务)动态上下文注入:在 SKILL.md 中用 !`git diff HEAD` 语法,Claude 看到内容前会先执行 shell 命令,把输出注入上下文。这个功能非常强大——你可以让 Skill 在执行时自动获取当前 git 状态、最近的变更、测试结果等实时信息。
反模式
反模式 1:把所有 Skill 都设成 disable-model-invocation: true
你可能觉得「我不想让 Claude 自动调用 Skill,万一调错了怎么办」。但如果你全部禁用了自动调用,Claude 永远不知道你有这些 Skill——description 虽然在上下文里,但 Claude 判断「用户没明确要求,我不应该自动调用」。结果就是你的 Skills 库变成了摆设。
解法:大部分 Skill 保持默认(允许自动调用),只对有副作用的 Skill(如部署、删除)设 disable-model-invocation: true。
反模式 2:Skill body 太长
Skill 的完整内容在调用后会留在上下文中。如果你写了一个 5000 token 的 Skill,每次调用后这 5000 token 就一直占着上下文窗口。Compaction 之后会重新附加,但有上限(单个 Skill 最多 5000 token,总计 25000 token)。
解法:把参考材料放在 Skill 目录的辅助文件里,SKILL.md 只放核心流程。用 @references/xxx.md 引入。
反模式 3:用 context: fork 跑纯指南类 Skill
context: fork 会创建一个隔离的子智能体来执行 Skill。如果你的 Skill 只是「告诉 Claude 某些规范」而不是「让 Claude 执行一系列操作」,fork 出来的子智能体会拿到指南但没有明确的执行 prompt,效果反而不如不 fork。
原理
Hooks 是 Claude Code 的「自动执行器」。它在特定生命周期事件发生时,自动运行你配置的脚本、HTTP 请求、甚至 LLM 提示。和 CLAUDE.md 最大的区别:Hooks 是强制执行的——exit code 2 会直接阻断操作,不是建议。
配置位置:settings.json 的 hooks 字段(用户级或项目级)。
支持 30+ 种事件,最常用的几种:
事件 | 触发时机 | 典型用途 |
|---|---|---|
PreToolUse | 工具执行前 | 阻止危险命令、安全校验 |
PostToolUse | 工具执行后 | 自动格式化、自动 lint |
SessionStart | 会话初始化 | 加载环境变量、检查依赖 |
Stop | Claude 完成回复后 | 发送通知、记录日志 |
UserPromptSubmit | 用户输入后 | 输入预处理、关键词替换 |
5 种 Hook 类型:command(Shell 命令)、http(POST 请求)、mcp_tool(调用 MCP 工具)、prompt(单轮 LLM 评估)、agent(子智能体评估)。
用法示例:在文件编辑后自动运行 Prettier 格式化
{
"hooks": {
"PostToolUse": [
{
"matcher": "Edit|Write",
"hooks": [
{
"type": "command",
"command": "npx prettier --write",
"args": ["${CLAUDE_FILE_PATH}"],
"timeout": 30
}
]
}
]
}
}
exit code 的含义(这是最容易搞错的):
反模式
反模式 1:用 exit 1 以为能阻止操作
这是最常见的误解。你在 Hook 脚本里检测到危险命令,exit 1 退出——结果 Claude 照样执行了。原因很简单:exit 1 只是非阻断性错误,Claude 收到一个「Hook 报了个错」的提示,但它可以选择忽略。
解法:要阻止操作,必须 exit 2。或者在 stdout 输出 JSON:{"decision": "block", "reason": "不允许执行 rm -rf"}。
反模式 2:不加 if 过滤器,每个工具调用都触发 Hook
{
"matcher": "*",
"hooks": [{ "type": "command", "command": "my-script.sh" }]
}
这会每次工具调用都 spawn 一个新进程。Claude 一次对话可能调用几十次工具,你的脚本就跑几十次。轻则浪费时间,重则拖慢整个对话。
解法:用 matcher 精确匹配工具名(如 "Bash"、"Edit|Write"),用 if 字段进一步缩小范围(如 "if": "Bash(rm *)")。
反模式 3:在 Hook 里做复杂逻辑
Hook 的设计初衷是「短平快」的自动化操作。如果你发现自己在 Hook 脚本里写了 200 行 Python——停下来,这应该是 Skills 或 Sub-agents 干的事。
原理
Rules 是 CLAUDE.md 系统的子功能,解决一个具体问题:不同目录需要不同的规则。
在单体仓库(monorepo)里,前端目录和后端目录的编码规范可能完全不同。用一个 CLAUDE.md 写两套规则会很混乱。Rules 允许你为不同路径配置不同规则,只有 Claude 访问到对应目录时才加载。
配置方式:在 .claude/rules/ 目录下创建 .md 文件,用 YAML frontmatter 的 paths 字段指定适用路径。
---
paths: ["src/api/**", "tests/api/**"]
---
## API 层规范
- Controller 方法必须有 @Validated 注解
- 返回值统一用 ResponseEntity 包装
- 异常用 @RestControllerAdvice 全局处理
---
paths: ["src/dao/**", "resources/mapper/**"]
---
## 数据层规范
- 禁止在 DAO 层拼接 SQL,必须用 MyBatis XML
- 分页用 PageHelper,不要手写 LIMIT
反模式
反模式 1:Rules 和 CLAUDE.md 写了重复甚至矛盾的规则
Rules 在 CLAUDE.md 之后追加加载,如果两边写了矛盾的内容,Claude 的行为会不可预测。
解法:CLAUDE.md 只写全局规则,Rules 写路径特化规则。全局和局部不要有交集。
反模式 2:paths 写得太宽泛
paths: ["**"] 等于没写——这和直接放 CLAUDE.md 里没区别。Rules 的价值就在于精准匹配。
原理
Sub-agents 是 Claude Code 的「分身术」。当你有一个复杂任务时,可以创建一个专用的子智能体来处理。它有自己独立的上下文窗口,不会污染主对话。执行完毕后把结果返回主智能体。
核心价值:
配置方式:在 .claude/agents/ 目录下创建 .md 文件。
---
name: code-reviewer
description: "审查代码质量、安全性和最佳实践"
tools: Read, Glob, Grep, Bash
disallowedTools: Write, Edit
model: sonnet
maxTurns: 50
isolation: worktree
---
你是一个代码审查专家。分析代码并提供具体、可执行的反馈。
重点关注:安全性、性能、可维护性。
三种调用方式:
@code-reviewer 看看 auth 模块的改动,保证运行一次--agent code-reviewer,整个会话使用该子智能体内置子智能体(不需要你创建):
反模式
反模式 1:description 字段写得太模糊
# 差的写法
description: "帮我处理一些任务"
# 好的写法
description: "审查 TypeScript 代码的质量、安全性和性能问题,输出结构化的 review 意见"
Claude 靠 description 判断什么时候该委派任务给这个子智能体。写得模糊,它就不知道什么时候用。
反模式 2:复制内置子智能体的功能
你不需要创建一个「explorer」子智能体来做搜索——内置的 Explore 已经做了,而且用了更便宜的 Haiku 模型。自定义子智能体应该做内置子智能体做不了的事。
反模式 3:子智能体嵌套太深
子智能体可以生成子智能体,最多 5 层。但每多一层就多一个上下文窗口的开销。除非确实需要,否则 1-2 层就够了。
原理
MCP(Model Context Protocol)是 Anthropic 推出的开放协议,让 Claude Code 能连接外部工具、数据库和 API。它解决了 Claude Code 原生「只能操作本地文件和终端」的限制。
有了 MCP Server,Claude 可以直接查 Jira ticket、查 Sentry 报错、查数据库表结构、操作 Figma 设计稿——不需要你手动复制粘贴。
配置方式:
CLI 方式(推荐,一行命令搞定):
# 远程 HTTP 服务
claude mcp add --transport http notion https://mcp.notion.com/mcp
# 本地 stdio 进程
claude mcp add --transport stdio airtable -- npx -y airtable-mcp-server
JSON 方式(.mcp.json,可提交到仓库共享给团队):
{
"mcpServers": {
"github": {
"type": "http",
"url": "https://api.githubcopilot.com/mcp/",
"headers": {
"Authorization": "Bearer ${GITHUB_TOKEN}"
}
},
"database": {
"command": "/path/to/db-server",
"args": ["--config", "config.json"],
"env": { "DB_URL": "${DB_URL}" }
}
}
}
三种传输协议:
http(推荐):适合远程服务,自动重连,支持 OAuthstdio:适合本地进程,Claude 启动子进程通信ws(WebSocket):适合需要推送事件的场景反模式
反模式 1:在 .mcp.json 里硬编码 API Key
// 千万别这么写
"headers": { "Authorization": "Bearer sk-xxxxx" }
// 用环境变量
"headers": { "Authorization": "Bearer ${GITHUB_TOKEN}" }
.mcp.json 通常会提交到 Git 仓库。硬编码的密钥会被所有 clone 仓库的人看到。
反模式 2:不信任远程 MCP Server 的安全性
MCP Server 本质上是给 Claude 注入外部数据和工具。如果远程 Server 被攻击者控制,它可以往 Claude 的上下文里注入恶意指令(prompt injection)。企业环境里,用 allowedMcpServers / deniedMcpServers 做白名单控制。
反模式 3:用 SSE 传输(已废弃)
SSE(Server-Sent Events)已经被标记为 deprecated,官方推荐用 http 替代。如果你在文档里看到 SSE 的配置示例,直接换成 http。
原理
Settings 是 Claude Code 的「控制面板」。它管理全局行为:权限规则、模型选择、环境变量、UI 偏好等。
配置层级(优先级从高到低):
.claude/settings.local.json(gitignore).claude/settings.json(提交到仓库)~/.claude/settings.json(最广,优先级最低)权限规则的特殊合并逻辑:其他设置是「高优先级覆盖低优先级」,但权限规则是跨层级合并的。也就是说,项目级的 allow 规则和用户级的 allow 规则会合并在一起,不会互相覆盖。
用法示例
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"permissions": {
"allow": [
"Bash(npm run lint)",
"Bash(npm run test *)",
"Read(~/.zshrc)"
],
"deny": [
"Bash(curl *)",
"Read(./.env)",
"Read(./secrets/**)"
]
},
"model": "claude-sonnet-4-6",
"language": "chinese",
"autoCompactEnabled": true
}
反模式
反模式 1:直接编辑 ~/.claude.json
这个文件是 Claude Code 内部管理的,手动编辑可能导致不可预期的行为。用户级设置应该改 ~/.claude/settings.json。
反模式 2:不用 $schema 做校验
Settings 是 JSON 格式,少一个逗号就解析失败。加上 $schema 字段后,编辑器会自动校验字段名和类型,提前发现错误。
反模式 3:在 Settings 里写行为指令
Settings 管的是「配置」——权限、模型、环境变量。如果你在 settings.json 里写了「请使用 2 空格缩进」这种行为指令,它不会生效。行为指令应该放 CLAUDE.md。
光讲理论不够,给一个我实际在用的项目配置结构:
my-project/
├── CLAUDE.md # 全局规则(< 100 行)
├── .claude/
│ ├── settings.json # 权限规则 + Hooks
│ ├── rules/
│ │ ├── api-rules.md # API 层专用规则
│ │ └── dao-rules.md # 数据层专用规则
│ ├── skills/
│ │ ├── code-review/
│ │ │ └── SKILL.md # Code Review 工作流
│ │ └── deploy-check/
│ │ └── SKILL.md # 部署前检查清单
│ ├── agents/
│ │ └── security-auditor.md # 安全审计子智能体
│ └── mcp.json # MCP Server 配置
└── .claude/settings.local.json # 本地个人覆盖(gitignore)
CLAUDE.md 里只放全局的、简短的规则(< 100 行)。路径特化的规则拆到 rules/ 里。可复用的工作流拆到 skills/ 里。需要隔离执行的任务用 agents/ 处理。外部工具用 mcp.json 连接。权限和 Hooks 放 settings.json。
这样每个文件各司其职,不会出现一个 500 行的 CLAUDE.md 把所有东西塞在一起的情况。
Q: CLAUDE.md 和 .claude/CLAUDE.md 有什么区别?放哪个位置更好?
A: 两个位置都会被加载,效果一样。区别在于文件系统的位置:项目根目录的 CLAUDE.md 更显眼,.claude/CLAUDE.md 更整洁(不污染根目录)。如果你的项目根目录已经有 README.md、package.json 等一堆文件,建议放 .claude/CLAUDE.md。两种都行,选一个团队统一就好。
Q: Skills 和 .claude/commands/ 是什么关系?我之前的 commands 还能用吗?
A: Skills 是 commands 的升级版。Anthropic 已经把两者统一了——commands 文件仍然有效,但新功能(如 context: fork、paths 匹配、辅助文件)只在 Skills 里支持。如果你已有 commands,不需要迁移,它们会继续工作。但新的自定义命令建议用 Skills。
Q: Hooks 和 CLAUDE.md 的规则有什么本质区别?
A: CLAUDE.md 是「建议」,Hooks 是「规则」。 CLAUDE.md 写「不要修改 legacy/ 目录」,Claude 会尽量遵守,但偶尔可能违反。Hook 配置 PreToolUse 检测到对 legacy/ 目录的写操作时返回 exit 2,操作会被直接阻断——Claude 根本没有机会违反。
如果你的规则必须被严格遵守(安全、合规、防误操作),用 Hooks。如果是编码风格、偏好建议,用 CLAUDE.md。
Q: 我需要为每个项目都配置 MCP Server 吗?
A: 不一定。MCP Server 有三个作用域:本地(.mcp.json 在项目目录,只对当前项目生效)、项目(.mcp.json 提交到仓库,团队共享)、用户(~/.claude.json 配置,所有项目通用)。像 GitHub MCP 这种通用的,放用户级;项目特定的数据库 Server,放项目级。
Q: 7 种方式会不会互相冲突?
A: 会,最常见的冲突有两种。一是 CLAUDE.md 和 Rules 写了矛盾的内容——解法是 CLAUDE.md 只写全局规则,Rules 写路径特化规则,不重叠。二是 Hooks 和 Settings 的权限规则冲突——Hooks 在 settings.json 里配置,如果项目级 Hook 阻止了某个操作,但用户级 Settings 的 allow 规则放行了,结果取决于合并逻辑。建议团队统一在一个层级配置,不要分散。

图:每种方式最常见的反模式——踩过才知道为什么不能这么干
说到底,Claude Code 的 7 种自定义方式不是「哪个更好」的问题,是「什么场景用什么」的问题。 把所有规则塞进 CLAUDE.md,就像把所有衣服扔进一个抽屉——你当然能塞进去,但找的时候全乱。拆开来各司其职,Claude 的表现会好很多。
这篇文章把每种方式的原理、用法和反模式都拆了一遍,但最核心的其实是那个决策框架——下次遇到自定义需求,先问自己三个问题,答案自然就出来了。
下一篇打算拆 Claude Code 的 Hooks 实战——30 多种事件怎么选、5 种 hook 类型怎么搭配、真实的自动化工作流怎么搭。感兴趣的关注一下,说实话公众号算法越来越不按常理出牌了,把码哥字节设为星标至少保证你能收到更新,不会错过。如果你身边有同事在用 Claude Code 但还没搞清楚这些配置方式,这篇可以直接甩给他,省他踩一遍。
如果这篇对你有帮助,转发给你的程序员朋友 — 大家都在摸索 Claude Code 的正确用法,你的分享可能帮他省很多时间。