Claude Code 的项目定制包含两类本质不同的机制:

  • CLAUDE.md、Rules 和 Skills 向模型提供上下文,帮助它作出正确判断;
  • 设置、权限规则、Hooks 和沙箱限制工具实际能做什么。

前者是指导,后者才是执行边界。把“不要读取 .env”写进自然语言指令并不能形成安全保证;需要使用 Read deny 规则、PreToolUse Hook 或操作系统级沙箱执行限制。

本文继续使用虚构的 TypeScript 项目 task-board,建立一套可提交给团队的 Claude Code 项目配置。内容包括项目记忆、自动记忆、设置作用域、权限模式、规则语法、敏感文件保护、沙箱和提示注入防护。


0. 配置决策速查

需求 应使用的机制
每个会话都应知道构建命令和架构约定 CLAUDE.md
只处理特定路径时才需要的规则 .claude/rules/*.mdpaths
偶尔才使用的操作手册 Skill
个人跨项目偏好 ~/.claude/CLAUDE.md
团队共享设置 .claude/settings.json
个人在当前项目的设置 .claude/settings.local.json
跨项目个人设置 ~/.claude/settings.json
预先允许或拒绝具体工具 permissions.allowaskdeny
限制 Bash 子进程的文件和网络范围 sandbox
每次都必须执行或拦截的动作 Hook
组织不可被覆盖的策略 Managed settings

推荐从最小配置开始:

1
2
3
4
5
6
7
task-board/
├── CLAUDE.md
└── .claude/
├── settings.json
└── rules/
├── api.md
└── migrations.md

进入会话后验证:

1
2
3
4
/context
/status
/permissions
/doctor

1. 指导与执行边界

不同机制的保证强度如下:

机制 作用 是否由模型解释 能否形成硬边界
CLAUDE.md 提供长期项目上下文
.claude/rules/ 提供全局或按路径加载的规则
Skill 提供按需知识或流程
权限规则 允许、询问或拒绝工具调用 否,由 Claude Code 执行
Hook 在生命周期事件上运行程序并可阻止操作 否,触发是确定的
沙箱 以 OS 机制限制 Bash 子进程文件与网络访问
Managed settings 组织级不可覆盖策略

应把“项目如何工作”写成指令,把“无论模型怎么判断都不能发生”写成权限、Hook 或沙箱规则。

错误做法:

1
2
3
# CLAUDE.md

永远不要读取任何密钥,也绝对不要运行危险命令。

这只能影响模型意图,不能阻止被允许的任意脚本间接读取文件。

更可靠的组合是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
"permissions": {
"deny": [
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)",
"Edit(./.env)",
"Edit(./.env.*)",
"Bash(git push *)"
]
},
"sandbox": {
"enabled": true,
"credentials": {
"files": [
{ "path": "~/.ssh", "mode": "deny" },
{ "path": "~/.aws/credentials", "mode": "deny" }
],
"envVars": [
{ "name": "GITHUB_TOKEN", "mode": "deny" },
{ "name": "NPM_TOKEN", "mode": "deny" }
]
}
}
}

沙箱只在支持的平台上生效,具体限制见后文。

2. 使用 CLAUDE.md 描述项目

2.1 CLAUDE.md 与自动记忆

Claude Code 有两套互补记忆:

项目 CLAUDE.md Auto memory
谁编写 用户或团队 Claude
内容 指令、约定、架构事实 Claude 在工作中积累的经验
范围 组织、用户、项目或目录 按仓库,工作树之间共享
加载 每个会话 每个会话,受大小限制
适合 构建命令、编码规范、工作流 调试发现、非显然模式、个人偏好

两者都会作为上下文提供给模型,不是强制策略。

2.2 文件位置

作用域 位置 用途
组织 系统级 Managed CLAUDE.md 公司规范和合规要求
用户 ~/.claude/CLAUDE.md 个人跨项目偏好
项目 ./CLAUDE.md./.claude/CLAUDE.md 团队共享项目指令
本地项目 ./CLAUDE.local.md 不提交的个人项目备注

项目 CLAUDE.md 应加入版本控制;CLAUDE.local.md 应加入 .gitignore

2.3 为示例项目创建最小文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# task-board 项目约定

## 环境与命令

- 使用 Node.js 22 和 npm;安装依赖运行 `npm ci`
- 单元测试运行 `npm test -- <test-file>`
- 完整检查依次运行 `npm test``npm run typecheck``npm run build`

## 架构

- HTTP 路由位于 `src/routes/`,不得直接访问数据库。
- 业务逻辑位于 `src/services/`
- 数据访问位于 `src/repositories/`
- 数据库迁移位于 `migrations/`,已应用迁移不得修改。

## 工作流

- 修改行为前先添加失败测试。
- 优先运行最小相关测试,完成后再运行完整检查。
- 不得通过跳过测试、降低断言或吞掉异常制造通过。
- 未经明确要求,不执行 `git push`、部署或生产数据库操作。

## 代码风格

- 使用项目现有 ESLint 和 Prettier 配置,不手工引入另一套格式规则。
- 公共函数需要显式返回类型。

这类内容满足三个条件:

  1. 每个会话都适用;
  2. Claude 无法仅靠读取单个源文件稳定推断;
  3. 足够具体,可以验证是否遵守。

不应放入:

  • 可从 package.json 直接看出的长篇依赖清单;
  • 每个文件的逐一介绍;
  • 框架完整文档;
  • 只在发布时需要的多页操作手册;
  • 经常变化的临时状态;
  • “写高质量代码”一类无法验证的空泛要求。

官方建议把单个 CLAUDE.md 控制在 200 行以内。文件越长,持续占用的上下文越多,个别规则越容易被噪声淹没。

2.4 使用 /init

在项目根目录启动 Claude 后:

1
/init

Claude 会分析构建系统、测试框架和项目模式,生成起始 CLAUDE.md;如果文件已存在,则提出改进而不是直接覆盖。生成内容必须人工审查,因为自动分析可能把可推断事实写得过多,也可能遗漏团队真正关心的非显然约束。

完成后检查:

1
/context

确认 Memory files 中出现预期文件。

2.5 导入其他文件

CLAUDE.md 可使用 @路径 导入:

1
2
项目概览见 @README.md。
提交规范见 @docs/contributing.md。

相对路径相对于包含导入语句的文件解析。导入可以递归,但官方限制最大深度。导入内容仍会在启动时进入上下文,因此拆文件只改善维护性,不会自动降低 token 占用。

若只是想在文字中提及 @README.md 而不导入,应放入代码格式:

1
不要修改 `@README.md` 中的示例版本号。

项目指令导入工作目录外的文件时,首次会要求批准。该机制防止恶意仓库通过 @~/.claude/... 静默读取个人文件。

2.6 与 AGENTS.md 共存

Claude Code 原生读取 CLAUDE.md,不是 AGENTS.md。已有 AGENTS.md 的项目可创建:

1
2
3
4
5
@AGENTS.md

## Claude Code

- 修改 `src/billing/` 前必须使用 Plan 模式。

Windows 上创建符号链接需要额外权限,使用导入通常更可移植。

3. 按路径组织 .claude/rules/

当不同目录有不同规范时,不要继续扩张根 CLAUDE.md。创建:

1
2
3
4
.claude/rules/
├── api.md
├── tests.md
└── migrations.md

没有 front matter 的 Rule 每个会话都会加载。按路径规则只在 Claude 读取匹配文件时加载:

1
2
3
4
5
6
7
8
9
10
11
---
paths:
- "src/routes/**/*.ts"
- "src/services/**/*.ts"
---

# API 规则

- 所有外部输入必须在路由边界校验。
- 服务层返回领域错误,由路由统一映射 HTTP 状态码。
- 列表接口必须使用项目现有分页结构。

迁移规则:

1
2
3
4
5
6
7
8
9
10
11
---
paths:
- "migrations/**/*.sql"
---

# 数据库迁移规则

- 不得修改已经在主分支发布的迁移。
- 新迁移必须包含前向操作和经人工确认的回滚说明。
- 添加非空列前先说明存量数据处理策略。
- 运行项目的迁移 dry-run 和相关集成测试。

常用 glob:

模式 匹配
**/*.ts 任意目录的 TypeScript 文件
src/**/* src 下所有文件
*.md 项目根目录的 Markdown
src/**/*.{ts,tsx} src 下 TypeScript 与 TSX

按路径 Rule 在 Claude 读取匹配文件时触发,不应依赖它来拦截写入。硬性保护仍需 Edit deny 或 Hook。

4. 自动记忆

Auto memory 允许 Claude 保存工作中发现的模式。适合保存:

  • 实际可用的构建或调试命令;
  • 经验证的故障原因;
  • 仓库中特殊工具的行为;
  • 用户反复纠正后形成的偏好。

不应把 Auto memory 视为团队规范来源,因为内容由 Claude 产生并按本地仓库存储。使用:

1
/memory

可以查看记忆文件位置、打开编辑并切换自动记忆。应定期审查并删除:

  • 已过期结论;
  • 推测而非事实;
  • 敏感信息;
  • CLAUDE.md 冲突的内容;
  • 只适用于一次故障的临时状态。

5. 设置文件与作用域

5.1 文件位置

作用域 设置位置 是否共享
用户 ~/.claude/settings.json 否,跨项目
项目 .claude/settings.json 是,应提交
本地项目 .claude/settings.local.json 否,应忽略
Managed 系统、MDM、注册表、远程策略等 由组织控制

不要混淆:

  • ~/.claude/settings.json:权限、Hooks、环境变量和行为设置;
  • ~/.claude.json:应用状态,以及 local/user 作用域 MCP 等其他状态。

permissionshooks 写进 ~/.claude.json 不会按预期生效。

5.2 优先级

当前官方优先级从高到低为:

  1. Managed settings;
  2. 命令行参数与 --settings
  3. .claude/settings.local.json
  4. .claude/settings.json
  5. ~/.claude/settings.json

标量值由高优先级覆盖。多数数组设置会跨作用域合并、去重,而不是整体替换,因此低优先级中的 allow 规则可能仍然存在。组织要形成不可放宽的边界,应使用 Managed settings 的专用锁定项,而不是只依赖普通数组覆盖。

检查实际加载来源:

1
/status

检查 JSON 或 schema 错误:

1
claude doctor

5.3 设置变更

Claude Code 会监视多数设置文件,权限、Hooks 和凭据助手等修改通常可在当前会话重新加载。仍应通过 /status/permissions/hooks 验证,不要假设保存文件等于成功应用。

5.4 官方 JSON Schema

可在设置中加入官方 schema:

1
2
3
4
5
6
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"permissions": {
"defaultMode": "default"
}
}

编辑器可以提供补全和校验。官方提醒:schema 更新可能略晚于最新 CLI,因此新字段出现校验警告时,还应与当前文档和 claude doctor 交叉确认。

6. 权限模式

6.1 模式对比

配置值 CLI 显示 无需询问的主要行为 推荐用途
default Manual 读取 初次使用、敏感项目
acceptEdits Accept edits 读取、编辑、部分常见文件命令 人工持续审查差异
plan Plan 只读探索与规划 复杂或陌生任务
auto Auto 通过后台安全分类器的操作 支持该模式的长任务
dontAsk Don’t ask 仅预先允许的工具 CI 和受限脚本
bypassPermissions Bypass permissions 几乎所有操作 仅额外隔离环境

manualdefault 的 CLI 别名。配置文件中优先使用文档给出的稳定值。

会话启动:

1
claude --permission-mode plan

设置默认模式:

1
2
3
4
5
{
"permissions": {
"defaultMode": "acceptEdits"
}
}

6.2 模式不是授权范围

模式决定基线审批行为,权限规则在其上继续生效。Deny 与 Ask 规则仍可能阻止操作;bypassPermissions 也不是“忽略所有组织策略”。

auto 使用独立分类器判断操作是否超出请求范围、访问未知基础设施或受到不可信内容驱动。它减少提示,但官方明确说明不能保证安全。

dontAsk 对未预先批准的操作直接拒绝,适合没有人可以回答提示的自动化。

bypassPermissions 跳过保护最多。只有在容器或虚拟机已经限制文件、网络和凭据,且运行内容受信任时才考虑使用。

7. 权限规则

7.1 Allow、Ask 与 Deny

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"permissions": {
"allow": [
"Bash(npm test *)",
"Bash(npm run typecheck)",
"Bash(npm run build)"
],
"ask": [
"Bash(git commit *)"
],
"deny": [
"Bash(git push *)",
"Read(./.env)",
"Read(./.env.*)",
"Edit(./.env)",
"Edit(./.env.*)"
]
}
}

匹配顺序固定为:

1
Deny → Ask → Allow

更具体的 Allow 不能覆盖宽泛 Deny。例如 Bash(aws *) 被拒绝后,Bash(aws s3 ls) Allow 也不会成为例外。

7.2 基础语法

1
2
Tool
Tool(specifier)

示例:

1
2
3
4
5
6
Bash
Bash(npm run build)
Read(./.env)
Edit(./docs/**)
WebFetch(domain:code.claude.com)
mcp__github__get_issue

裸工具名匹配该工具的全部调用。作为 Deny 时,通常会把工具从 Claude 可见的工具列表移除。需要只阻止特定命令时,应使用带限定符的规则。

7.3 Bash 通配符

1
2
3
4
Bash(npm run build)   精确匹配
Bash(npm run test *) 匹配 npm run test 及其参数
Bash(git *) 匹配 git 后的任意内容
Bash(* --version) 匹配以 --version 结束的命令

Bash(ls *) 中空格很重要:它匹配 lsls -la,不匹配 lsofBash(ls*) 会匹配两者。

Claude Code 会拆分 &&||;、管道和换行等复合命令,要求每个子命令分别满足权限。即便如此,不应尝试用宽泛命令前缀构建复杂安全策略:

1
2
3
Bash(devbox run *)
Bash(docker exec *)
Bash(curl *)

这些包装器后面可以执行任意内容。应把内层命令写得具体,或使用 Hook 与沙箱形成更可靠边界。

7.4 文件路径规则

Read 与 Edit 路径使用 gitignore 风格:

形式 含义
//path 文件系统绝对路径
~/path 用户主目录相对路径
/path 相对设置来源锚点
path./path 相对当前工作目录

例如:

1
2
3
4
Read(.env)              当前目录下任意深度的 .env
Read(//**/.env) 文件系统任意位置的 .env
Edit(/src/**/*.ts) 项目设置中表示项目根 src
Read(~/.ssh/**) 用户 SSH 目录

单个 / 不是文件系统根。Read(/Users/alice/file) 在项目设置中是项目相对路径;绝对路径要写 Read(//Users/alice/file)

Windows 路径会归一化为 POSIX 形式。跨盘匹配应谨慎,避免无意阻止所有项目。

当前文件权限检查应使用 Read(path)Edit(path)。不要用 Write(path)Glob(path) 代替路径规则;官方当前版本会对这些不匹配的形式发出警告。

Read deny 会阻止对应路径的内置读取工具,并在当前版本中同时影响 Edit,但任意 Python 或 Node 子进程仍可能自行打开文件。需要覆盖所有子进程时必须使用沙箱。

7.5 WebFetch 与 MCP

1
2
3
4
5
WebFetch(domain:code.claude.com)
WebFetch(domain:*.example.com)
mcp__github
mcp__github__get_issue
mcp__github__*

*.example.com 匹配子域,不匹配根域 example.com。允许 WebFetch 并不能阻止 Bash 使用 curl 或其他网络工具,因此网络隔离还需沙箱。

8. 推荐的项目权限配置

.claude/settings.json

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
{
"$schema": "https://json.schemastore.org/claude-code-settings.json",
"permissions": {
"defaultMode": "default",
"allow": [
"Bash(npm test *)",
"Bash(npm run typecheck)",
"Bash(npm run build)",
"WebFetch(domain:code.claude.com)"
],
"ask": [
"Bash(git commit *)"
],
"deny": [
"Bash(git push *)",
"Bash(npm publish *)",
"Read(./.env)",
"Read(./.env.*)",
"Read(./secrets/**)",
"Edit(./.env)",
"Edit(./.env.*)",
"Edit(./secrets/**)"
]
}
}

该配置表达的是示例项目约定,不是通用最佳规则。团队需要根据实际命令、目录和发布流程调整。

项目配置中的 Allow 会影响所有信任该仓库的协作者。应只预先允许范围窄、可重复、影响明确的命令,不要提交 Bash(*)WebFetch(domain:*) 或广泛云 CLI 写权限。

个人机器上的附加保护可以放入 ~/.claude/settings.json

1
2
3
4
5
6
7
8
9
{
"permissions": {
"deny": [
"Read(~/.ssh/**)",
"Read(~/.aws/**)",
"Read(~/.kube/**)"
]
}
}

9. 沙箱

9.1 沙箱解决什么问题

权限规则在工具运行前判断是否允许;沙箱在命令运行后由操作系统限制其实际文件和网络访问。

1
2
权限规则:Claude 可不可以调用这个工具?
沙箱:这个 Bash 子进程即使运行,实际能访问什么?

当前支持:

  • macOS:Seatbelt;
  • Linux:bubblewrap;
  • WSL 2:bubblewrap;
  • Windows 原生和 WSL 1:不支持 Claude Code 的 Bash 沙箱。

9.2 启用

会话内:

1
/sandbox

或在设置中:

1
2
3
4
5
6
{
"sandbox": {
"enabled": true,
"autoAllowBashIfSandboxed": true
}
}

默认文件系统行为主要是:

  • 当前工作目录及会话临时目录可写;
  • 默认可读取较广泛的系统路径;
  • 工作目录外写入被限制;
  • 网络通过沙箱外代理控制。

默认可读不等于凭据安全。官方文档明确指出,应单独配置凭据文件和环境变量。

9.3 文件与网络限制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
{
"sandbox": {
"enabled": true,
"autoAllowBashIfSandboxed": true,
"excludedCommands": [
"docker *"
],
"filesystem": {
"allowWrite": [
"/tmp/task-board-build"
],
"denyRead": [
"~/.ssh",
"~/.aws"
]
},
"network": {
"allowedDomains": [
"registry.npmjs.org",
"github.com",
"*.github.com"
],
"deniedDomains": [
"uploads.github.com"
]
}
}
}

沙箱路径使用常规路径语义:

  • /tmp/build 是绝对路径;
  • ~/... 相对用户主目录;
  • ./... 在项目设置中相对项目根。

这与 Read/Edit 权限的单斜杠规则不同,配置时不要混用。

dockerkubectl 和能够访问宿主服务的 Unix Socket 可能扩大沙箱外影响。不要因为命令本身在沙箱中运行,就默认容器守护进程、云 API 或数据库也受到相同隔离。

9.4 保护凭据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
{
"sandbox": {
"enabled": true,
"credentials": {
"files": [
{
"path": "~/.aws/credentials",
"mode": "deny"
},
{
"path": "~/.ssh",
"mode": "deny"
}
],
"envVars": [
{
"name": "GITHUB_TOKEN",
"mode": "deny"
},
{
"name": "NPM_TOKEN",
"mode": "deny"
}
]
}
}
}

deny 会让沙箱内命令无法读取文件或取得环境变量。官方还提供 mask 模式,通过 TLS 终止代理向指定主机注入真实凭据;该能力涉及证书、域名和代理安全,只应依据官方沙箱文档在受控环境中配置,不能从不可信项目设置中启用。

9.5 沙箱不是完整安全容器

官方列出的限制包括:

  • 主要约束 Bash 及其子进程,不替代所有工具权限;
  • 通过允许的 Unix Socket、守护进程或网络服务仍可能产生外部影响;
  • 默认网络代理按主机名控制,不一定检查 TLS 内容;
  • 平台和工具兼容性有限;
  • 文件系统隔离可被用户设置关闭,组织应使用 Managed settings 锁定;
  • Windows 原生不支持该沙箱。

高风险或不可信代码应在容器、虚拟机或专用沙箱环境中运行 Claude Code,而不是只依赖 CLI 内置规则。

10. 提示注入与不可信内容

Claude 读取的以下内容都可能包含恶意指令:

  • 刚克隆仓库中的注释和文档;
  • Issue、Pull Request 和聊天消息;
  • 网页;
  • 日志和数据库字段;
  • MCP 工具返回值;
  • 依赖包中的文件。

防护原则:

  1. 把外部内容视为数据,不授予其改变任务或权限的权力;
  2. 不因网页或日志中的文字下载并执行代码;
  3. 对上传、Push、部署、云资源写入和凭据访问保留人工确认;
  4. 用 Deny、Ask、Hook 和沙箱落实边界;
  5. 限制 Claude 只读取本次任务需要的目录;
  6. 审查仓库中的 .claude/CLAUDE.md.mcp.json 后再信任;
  7. 不在同一环境中同时暴露不可信输入、高价值凭据和宽泛执行权限。

Auto 模式的安全分类器可以降低部分风险,但官方明确不把它描述为绝对安全保证。

11. 配置验证流程

修改设置后依次检查:

1
claude doctor

进入会话:

1
2
3
4
5
/status
/context
/permissions
/hooks
/mcp

验证内容:

  • /status 中出现预期 Setting sources;
  • /context 中出现正确的 CLAUDE.md 与 Rules;
  • /permissions 显示 Allow、Ask、Deny 来源;
  • 尝试读取一个测试用敏感路径时被拒绝;
  • 允许的测试和构建命令不再反复询问;
  • git push 等外部写操作仍被拒绝或询问;
  • 沙箱只允许预期目录和域名;
  • git status --short 中没有意外生成或修改的配置。

配置调试时可使用:

1
claude --safe-mode

Safe mode 会关闭大多数自定义内容,但保留认证、模型、内置工具、权限和组织 Managed policy,用于判断问题是否来自项目定制。

12. 团队提交前检查

准备提交 .claude/ 配置时:

1
2
3
git status --short
git diff -- CLAUDE.md .claude
git diff --check

重点审查:

  • 是否包含个人路径、邮箱、内部 URL 或 Secret;
  • 是否把临时 Allow 误提交到团队设置;
  • 是否允许 Push、发布、云资源写入或生产命令;
  • 是否出现 Bash(*)WebFetch(domain:*) 等宽泛规则;
  • 是否把个人设置写入 .claude/settings.json
  • 是否让 CLAUDE.md 重复代码可直接推断的信息;
  • Rule 路径是否准确;
  • 是否有互相冲突的指令;
  • 新成员信任仓库后会加载哪些 Hooks、MCP 和插件。

下一篇将讲解如何保存、恢复和分支会话,如何使用检查点与 Git,如何通过 --worktree 隔离并行修改,以及如何在子代理、Agent view 和实验性 Agent teams 之间选择。

参考资料