☰
Claude Code 在大仓库里总改不该改的文件,多因 CLAUDE.md 缺一句边界声明
2026/10/15 0:34:50 网站建设 项目流程

本文摘要:大仓库里让 AI 修一个模块,git diff 却跨了七个无关目录。把允许改动的路径写进根目录CLAUDE.md,约束才能跨会话生效。

一、问题与结论

环境先交代:macOSzsh+tmux,Claude Code 在仓库根目录启动;内部 monorepo,约 7.3 万行 TypeScript、14 个packages/*子包,带根pnpm-lock.yaml和dist/。

一次任务是「修packages/auth的登录超时」,改完后的git status --short(实际输出):

M packages/auth/src/login.ts M packages/auth/src/http-client.ts M packages/billing/src/invoice.ts M packages/shared/src/retry.ts M pnpm-lock.yaml M tsconfig.json ?? packages/auth/src/login.test.ts

7 个变更里只有 3 个属于任务范围,pnpm-lock.yaml和tsconfig.json完全不该动。另一次它自行执行了git commit,提交落在我当时临时切出的实验分支上,工作区还残留未跟踪文件。

那轮对话里我明确说过「只改 auth」,所以问题不在提示词写得不够细:这句话只活在当轮会话,任务一复杂或换会话就失效。根目录CLAUDE.md只有项目约定、没有边界声明,约束没沉淀成项目基础设施。补一段边界声明,再用.claude/settings.json的permissions.deny兜住 git 写操作,改动范围才稳定收敛。

二、排查与选择依据

三步排查,结论是:约束写错了位置,不是模型能力问题。翻会话历史——提示词里有边界,但只在单次会话生效;看根目录CLAUDE.md——只有编码约定,没有「改哪些、不改哪些」;看.claude/settings.json——没有permissions.deny,文件编辑与 bash 默认全放行,git commit、git push都能直接执行。

判断依据来自官方仓库对它的定位(见参考资料):这是一个agentic coding tool,understands your codebase并handling git workflows——写文件、动 git 是默认行为,没有显式约束时「该动哪些」由模型自行判断。

替代方案与取舍

方案选择条件代价边界
根目录CLAUDE.md边界声明(本文)单团队、路径规则稳定、要求跨会话生效每次会话都会读,靠模型遵守只收窄意图,不阻断执行
.claude/settings.jsondeny规则需要硬阻断特定路径与 git 写命令glob 语法随版本变化,路径变动要维护只挡白名单命令,挡不住「该改没改」
pre-commit hook + CI 检查多人协作、需要机器强制CI 耗时与维护成本事后拦截,文件已被改过
人工git diff后合并低频、高风险仓库每次都要人工依赖审查者熟悉目录职责
cc-switch 等桌面工具多个 AI 编码工具混用、需统一切换配置第三方工具,配置切换与路径边界无关不限制改动范围,不能替代声明

不该用本文方案的两种情况:任务本身就是跨包重构(改packages/shared才正确),边界声明会把正确改动一起拦下;仓库只有几千行、目录职责一眼可见,维护边界声明的成本大于收益。需要硬阻断时(如 lock 文件绝对不能碰),只写CLAUDE.md不够,必须叠deny规则。

三、关键原理

CLAUDE.md是每次会话都会加载的项目上下文,支持多级(仓库根目录、子目录、全局~/.claude/CLAUDE.md)。边界写在根目录这一级才具备跨会话的重复约束力;只写在对话里的边界是一次性的。若放在子目录,从packages/auth里启动会话时不一定能加载到。

官方描述明确它在executing routine tasks,也就是说routine(例行改动)的范围由模型自己划。仓库一大,模型倾向于「顺手保持一致」:改了packages/auth就去看packages/shared的retry.ts,发现依赖没同步就动pnpm-lock.yaml。这不是幻觉,是这类 AI Agent 在无边界时对「理解整个 codebase」的正常发挥——能力与风险是同一个硬币的两面。

四、可运行示例

环境:macOS +zsh、node 20,一个不含真实业务代码的最小 monorepo 复现仓库。

准备(可直接复制):

mkdirdemo-repo&&cddemo-repogitinit-qmkdir-ppackages/auth/src packages/billing/src packages/shared/srcprintf"console.log('auth');\n">packages/auth/src/index.jsprintf"console.log('billing');\n">packages/billing/src/index.jsprintf"console.log('shared');\n">packages/shared/src/util.jsprintf'{"private": true}\n'>package.jsonprintf'lock-v1\n'>package-lock.jsongitadd-A&&gitcommit-qminit

实际输出(准备脚本跑完后的基线):

$ git status --short (无输出,工作区干净)

改前的CLAUDE.md(只有约定,没有边界):

# 项目约定 - 使用 JavaScript - 代码风格遵循 ESLint 默认配置 - 提交信息使用 conventional commits

改后(补上边界段,第一句就是那条关键声明):

# 项目约定 - 使用 JavaScript - 代码风格遵循 ESLint 默认配置 - 提交信息使用 conventional commits # 修改边界(优先级高于上面的约定) - 默认只允许修改 packages/auth/ 下的文件 - 禁止修改 packages/billing/、packages/shared/ 以及根目录 package.json、package-lock.json - 禁止修改 dist/、node_modules/、.github/ 下的任何文件 - 不要执行 git commit、git push、git checkout、git stash;只允许 git diff、git status、git log - 不要运行 npm install、npm ci,依赖由我手动更新 - 如果任务必须改到上述路径,先停下并列出清单问我,不要直接改 - 提交由我来做,你只给建议的 commit message

关键权限配置(对 git 写操作做硬阻断,与CLAUDE.md同目录生效):

cat>.claude/settings.json<<'EOF' { "permissions": { "deny": [ "Bash(git commit:*)", "Bash(git push:*)", "Bash(git checkout:*)", "Edit(package-lock.json)", "Edit(dist/**)" ] } } EOF

字段名与 glob 写法随版本变化,本文未逐条验证,以当前版本官方文档为准;这条命令至少保证配置文件落在正确位置。

跑同一个任务:

claude"给 auth 模块加一个导出"gitstatus--shortgitdiff--stat

预期输出(属预期,未在本机复跑):

$ git diff --stat packages/auth/src/index.js | 1 + 1 file changed, 1 insertion(+)

常见失败及其修复:某次运行后git diff --stat里出现了package-lock.json。原因是边界段只写了路径、没写「不要自己装依赖」,模型把同步 lock 文件当成「保持一致」的一部分。修复方式是在边界段补一行不要运行 npm install / npm ci,依赖由我手动更新,同时把Edit(package-lock.json)加进deny。

五、验证结果与边界

验证方法:同一句任务在改前、改后的CLAUDE.md下各跑一次,跑完立刻看git status --short与git diff --stat,变更文件数从 7 降到 1–2 视为达到预期;再用git log --oneline -1确认 HEAD 没被移动、当前分支没被切走。

能保证的部分:边界声明让每次会话都读到约束,配合deny规则,lock 文件写入与git push这类操作会被硬拦。

不能保证的部分:模型仍可能漏改(该改的没改),deny只挡写入、不挡「少改」;边界路径写错反而会挡住正确改动。上文两次模型运行的git diff对比标注为预期、未验证,只有准备脚本与基线git status是实际跑通的输出。

所以提交前的git diff --stat审查不能省——边界声明负责把误改概率压低,不负责替代 review。

思考

  1. 跨包重构任务里,边界声明该临时放开路径,还是干脆不写死?
  2. CLAUDE.md约束与deny规则冲突时,应以哪一层为准?

参考资料

  • anthropics/claude-code
  • farion1231/cc-switch

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询