配置实战------settings.json 权限 + CLAUDE.md + Rules 懒加载
前两篇讲了"怎么操作 Claude Code"和"怎么编排工作流"。这篇讲怎么配置它------让 Claude Code 一启动就懂你的项目、只做你允许的事、在 monorepo 里不乱加载无关规则。
素材来自 shanraisshan/claude-code-best-practice 仓库的真实配置。
Part 1: settings.json 权限------allow / deny / ask 三区模型
权限系统是 settings.json 的核心。每次 Claude Code 调用工具(Bash、Write、WebFetch 等),都要过这道门禁:
json
{
"permissions": {
"allow": ["Bash(npm test:*)", "Bash(npm run lint:*)", "Read(*)"],
"deny": ["Bash(curl:*)", "Bash(rm -rf:*)", "Bash(git push --force:*)"],
"ask": ["WebFetch(*)", "Bash(npm install:*)"]
}
}
三个区域的语义:
| 区域 | 行为 | 用途 |
|---|---|---|
| allow | 自动放行,不弹窗 | 你每次都同意的安全操作(跑测试、读文件) |
| deny | 直接拒绝,模型看不到这个选项 | 绝对不能做的操作(删库、强制推送) |
| ask | 弹窗问你 | 需要你判断的操作(装依赖、调外部 API) |
优先级:deny > ask > allow。 如果一个操作同时匹配 deny 和 allow,deny 赢。这条规则至关重要------你不会因为 allow 规则太宽而意外放行危险操作。
实战配置:一个生产可用的权限模板
json
{
"permissions": {
"allow": [
"Read(*)",
"Edit(*)",
"Bash(npm test:*)",
"Bash(npm run lint:*)",
"Bash(npm run build:*)",
"Bash(npx tsc:*)",
"Bash(git status:*)",
"Bash(git diff:*)",
"Bash(git log:*)",
"Bash(git branch:*)",
"Bash(git add:*)",
"Bash(git commit:*)"
],
"deny": [
"Bash(rm -rf:*)",
"Bash(git push --force:*)",
"Bash(git reset --hard:*)",
"Bash(curl:*)",
"Bash(wget:*)"
],
"ask": [
"WebFetch(*)",
"Bash(npm install:*)",
"Bash
(git push:*)",
"Bash(git pull:*)",
"Bash(npm publish:*)"
]
}
}
几个设计原则:
allow 不是越宽越好。 "Bash(*)" 放 allow 里等于没设权限。每个 allow 规则应该精确到你确认安全的命令。
deny 放操作后果不可逆的命令。 rm -rf、push --force、reset --hard------这些操作即使你误点了 allow,也来不及后悔。
ask 放需要你判断上下文的操作。 WebFetch 调外部 API 可能泄露代码、npm install 可能引入恶意包------你需要在每次触发时看一眼。
连接第 2 篇:跨层权限收窄模式
第 2 篇展示了 Command → Agent → Skill 三层编排中工具白名单逐层收窄的安全设计:
css
Command 层: Agent, Skill(不能直接 Bash、WebFetch)
Agent 层: Read, Skill(不能直接 Bash)
Skill 层: WebFetch(*) 或 Write(*)(权限精确到单个操作)
这个模式在 settings.json 的权限配置里同样生效------你可以给不同 agent 配置不同的 allowed-tools,确保它们只能做设计范围内的操作。settings.json 的 deny 列表则是全局底线------无论哪一层都不能越过。
Part 2: CLAUDE.md------让 Claude Code 一启动就懂你的项目
它应该写什么
CLAUDE.md 是 Claude Code 启动时加载的指令文件。它可以有多个(从祖先目录往下),但项目根目录那个是核心。一个好的 CLAUDE.md 不超过 200 行,只写三样东西:
1. Claude 不知道但需要知道的。 技术栈、命令、项目约定------这些是你项目特有的,Claude 的训练数据里没有。
2. Claude 知道但可能搞错的。 比如你说"用 named export 不用 default export"------Claude 两种都会写,但你的项目只要一种。这是纠正默认行为,不是教它基础知识。
3. 绝对不能做的。 .env 不能 commit、database schema 不能随便改、依赖不能随便加------这些是项目的"宪法"。
它不应该写什么
- 基础知识("React 组件应该用 hooks"------Claude 本来就知道)
- 模糊建议("写出高质量的代码"------这句话没有任何约束力)
- 太长(超过 200 行 Claude 开始忽略后面的内容)
实战模板:一个 60 行的 CLAUDE.md
markdown
# 项目:[你的项目名]
## 技术栈
- Frontend: React 18, TypeScript 5, Vite
- Backend: Node.js 22, Express, PostgreSQL, Prisma
## 命令
- Build: `npm run build`
- Test: `npm test -- --coverage`(必须 0 failure)
-
Lint: `npm run lint --fix`
- Type check: `npx tsc --noEmit`
## 代码约定
- 函数组件 + hooks,不用 class
- named export,不用 default export
- 测试和源文件同级:Button.tsx → Button.test.tsx
- commit message 格式:`type(scope): description`
## 边界
- 永远不 commit .env 或 secrets
- 加依赖前先检查 bundle size
- 改 database schema、CI 配置前先问我
- commit 前必须跑测试和 lint
## 当前项目状态
- 正在做的功能:用户认证重构(auth-v2 分支)
- 已知坑:auth.ts 里有一段旧的 JWT 逻辑,本次重构不碰它
注意"当前项目状态"那段------这是 CLAUDE.md 里最容易被忽略但最有价值的部分。它告诉 Claude "我们在做什么、有什么坑",避免它在你不在的时候自创方案。
Monorepo 场景:祖先加载 + 后代加载
Claude Code 会沿着目录树加载 CLAUDE.md:
bash
你从 /monorepo/ 启动 Claude:
自动加载:
~/.claude/CLAUDE.md ← 全局规则
/monorepo/CLAUDE.md ← 项目根(shared 规则:git 约定、CI 流程)
按需加载(碰到对应目录的文件时才加载):
/monorepo/packages/frontend/CLAUDE.md ← 前端规则
/monorepo/packages/backend/CLAUDE.md ← 后端规则
实战策略: 根目录 CLAUDE.md 放跨项目的共享约定。子目录 CLAUDE.md 放各模块特有的技术栈和 patterns。Claude 处理前端代码时自动带上前端规则,处理后端时自动带上后端规则,互不污染。
Part 3: .claude/rules/------更细粒度的指令控制
CLAUDE.md 的问题是不能按文件类型控制加载。你在 monorepo 里可能希望"TypeScript 文件有统一规范,但不影响其他文件"。
.claude/rules/ 目录 + paths: frontmatter 解决了这个问题:
markdown
# .claude/rules/typescript.md
---
paths:
- "src/**/*.ts"
- "src/**/*.tsx"
---
## TypeScript 规范
- 优先使用 interface 而非 type(除非需要 union/intersection)
- 函数参数超过 3 个时使用对象参数
- 异步函数返回值始终用 Promise<T>
这个文件只在 Claude 读取 src/**/*.ts 文件时才加载。处理 Go、Python、配置文件时完全不占用 context。
什么时候用 Rules 而不是 CLAUDE.md: 当一条规则只对特定文件类型或目录生效时。全局规则放 CLAUDE.md,文件级规则放 Rules。
实战落地:你能直接拿走的东西
完整的 settings.json 模板
把下面内容保存到 .claude/settings.json:
json
{
"permissions": {
"allow": [
"Read(*)", "Edit(*)",
"Bash(npm test:*)", "Bash(npm run lint:*)", "Bash(npm run build:*)",
"Bash(git:status,diff,log,branch,add,commit:*)(!push !reset !rebase)"
],
"deny": [
"Bash(rm -rf:*)", "Bash(git push --force:*)", "Bash(curl:*)"
],
"ask": [
"WebFetch(*)", "Bash(npm install:*)", "Bash(npm publish:*)"
]
},
"attribution": {
"commit": ""
}
}
完整的 CLAUDE.md 模板
把上面的 60 行模板保存到项目根目录 CLAUDE.md。
Rules 文件模板
bash
mkdir -p .claude/rules
markdown
# .claude/rules/typescript.md
---
paths:
- "src/**/*.ts"
- "src/**/*.tsx"
---
## TypeScript 规范
[你的规范]
验证配置生效
bash
# 1. 检查 settings.json 有无语法错误
cat .claude/settings.json | python3 -m json.tool > /dev/null && echo "JSON valid"
# 2. 重启 Claude Code
claude
# 3. 验证 CLAUDE.md 被加载(Claude 应该知道你的项目命令和约定)
# 让它跑一下 npm test------如果不需要你解释怎么跑,说明 CLAUDE.md 生效了
⚠️ CLAUDE.md 需要持续维护。项目加了新模块、换了新技术栈、改了测试命令------这些变更要同步到 CLAUDE.md。如果你发现 Claude 频繁写出不符合约定的代码,第一反应不该是"这模型不行",而是"我的 CLAUDE.md 是不是过时了"。settings.json 的权限列表同理------新加的命令如果反复弹 ask,就加到 allow 里;新发现的危险命令加到 deny 里。