2603 字
约 8 分钟
21
S24-X04 · Claude Code 在项目里放了什么:目录与文件全解

用过一阵 Claude Code 的仓库,git status 里会多出 .claude/;家目录里还躺着一个 ~/.claude/。这两处混着放,常见后果有三种:把个人配置提交进 PR、同事拉下来规则不生效、改了文件却像没改过。搞清楚每个文件的归属,比记命令更重要。

下面按 地图 → 两级关系 → 记忆文件 → 进不进 git → 多仓库 → 排错 拆。


1. 一张地图:项目级与用户级

路径 作用域 进版本控制 内容
.claude/settings.json 项目、团队 是 权限规则、env、hooks、状态栏
.claude/settings.local.json 项目、仅自己 否 个人覆盖、本机路径
.claude/commands/*.md 项目 是 自定义斜杠命令
.claude/agents/*.md 项目 是 子代理定义(frontmatter + 提示词)
.claude/skills/<name>/SKILL.md 项目 是 技能包,按需加载
.claude/hooks/*.sh 项目 是 hook 脚本本体(配置在 settings 里)
CLAUDE.md 项目、团队 是 团队记忆:构建、约定、禁区
CLAUDE.local.md 项目、仅自己 否 个人记忆(已标记废弃,建议改用 import)
.mcp.json 项目 是(不含密钥) 项目级 MCP server 声明
~/.claude/settings.json 用户全局 否 个人默认配置
~/.claude/CLAUDE.md 用户全局 否 跨项目偏好
`~/.claude/commands agents skills` 用户全局
~/.claude.json 用户全局 否 客户端状态(含 MCP、项目历史),别手改

一条容易忽略的:hooks 没有独立配置文件。hooks/ 目录只是放脚本的地方,真正决定"什么时机跑哪个脚本"的是 settings.json 里的 hooks 段。


2. 用户级与项目级:默认值层 + 覆盖层

把用户级想成"默认值",项目级想成"这个仓库的例外"。加载是两层叠加,项目级覆盖同名项;用户级存在的意义是让你在几十个仓库里不用重复写同一套偏好。

需求 该放哪 理由
我习惯用哪个模型 ~/.claude/settings.json 个人偏好,与仓库无关
这个仓库禁止 git push --force 项目 settings.json 团队都要遵守
我本机 SDK 路径 settings.local.json 只对本机有效
团队共用的 /review 命令 项目 commands/review.md 随仓库分发
我自己的 /scratch 草稿命令 ~/.claude/commands/ 不想让别人看到
跨项目都要用的子代理 ~/.claude/agents/ 复用,避免每个仓库复制

同名冲突时要知道的顺序:项目级优先于用户级。这也是"我在用户级改了却没生效"的最常见原因——项目里有一份同名的把它压住了。

ls -la .claude/                      # 项目里到底有什么
ls -la ~/.claude/                    # 用户级有什么
find . -name 'CLAUDE.md' -not -path '*/node_modules/*'   # 记忆文件分布

3. CLAUDE.md 与 CLAUDE.local.md 的分工

文件 归属 写什么 进 git
CLAUDE.md 团队 构建/测试命令、目录约定、禁区 是
CLAUDE.local.md 个人 本机路径、临时偏好 否
~/.claude/CLAUDE.md 个人全局 跨项目习惯(提交信息风格等) 否
子目录 CLAUDE.md 局部 某个模块的额外约定 视情况

CLAUDE.local.md 在当前版本里已被标记为废弃,官方建议的做法是在 CLAUDE.md 里用 import 引入个人文件,而不是继续用 .local.md。迁移前按当前版本核对一次行为,不要只看旧教程。

3.1 怎么写才有效:少而准

记忆文件不是文档仓库。三条经验:

  1. 只写模型猜不到的。 "用 pnpm 不用 npm"、"生成物在 dist/ 不要手改"值得写;"本项目使用 TypeScript"不值得,看一眼就知道。
  2. 约束前置。 长上下文里中段内容更容易被忽略,把"绝对禁止"放在开头,背景说明放后面。
  3. 可验证。 写"改完跑 make test",不写"注意测试"。可执行的指令能被遵守,形容词不能。

3.2 一份能用的骨架

# 项目约定

## 构建与测试
- 安装依赖:`pnpm install`
- 单测:`pnpm test -- --run <path>`
- 类型检查:`pnpm tsc --noEmit`

## 目录
- `apps/web` 前端;`services/api` 后端;`packages/shared` 公共代码
- `dist/`、`generated/` 是生成物,不手改

## 禁区
- 不改 `migrations/` 下已有文件;新增迁移用 `pnpm db:new`
- 不跨模块深层 import,公共逻辑下沉到 `packages/shared`
- 不提交 `.env*`、任何密钥

一屏能读完是实践上的合理上限(不是官方硬限制)。超过一屏,要么精简,要么拆到子目录的 CLAUDE.md,让它在对应目录才被读。

需要复用的段落用 import 引入,不要复制粘贴——改一处就够:

# 团队约定(续)
@docs/testing.md
@.claude/rules/api-style.md

4. 哪些必须进版本控制,哪些必须 ignore

必须进 git 必须 ignore
.claude/settings.json .claude/settings.local.json
.claude/commands/、agents/、skills/ CLAUDE.local.md
.claude/hooks/*.sh .env、.env.*(保留 .env.example)
CLAUDE.md、子目录 CLAUDE.md ~/.claude.json 与整个 ~/.claude/(本就在仓库外)
.mcp.json(只放 server 声明,不放 token) 任何含 token 的 MCP 配置副本
# Claude Code 个人文件
.claude/settings.local.json
.claude/*.local.json
CLAUDE.local.md
# 密钥
.env
.env.*
!.env.example

判据只有一条:这个文件里有没有"只对我成立"或"不该给别人看"的内容。有,就 local 或 ignore;没有,就提交,让团队共享同一套行为。


5. 多仓库与单体仓库怎么放

形态 做法 注意
单包仓库 .claude/ 放根目录 简单,别在子目录再放一份
monorepo 根放团队通用,子包放局部 CLAUDE.md 子目录 settings 是否被读取按当前版本核对,以实测为准
多仓库共享流程 通用命令/子代理放用户级,或打包成插件 别复制粘贴到每个仓库,改一次要改十处
外包/临时项目 个人配置一律 settings.local.json 交付前检查有没有把本地文件提交
多分支并行开发 每个 worktree 有独立工作区,.claude/ 随分支切换 未提交的 local 配置不会跟着走
repo/
├── CLAUDE.md                 # 团队通用约定
├── .claude/
│   ├── settings.json         # 提交
│   ├── settings.local.json   # ignore
│   ├── commands/review.md
│   └── agents/test-fixer.md
├── apps/web/CLAUDE.md        # 前端局部约定
└── services/api/CLAUDE.md    # 后端局部约定

monorepo 里最容易犯的错是"根目录写一份巨长的 CLAUDE.md"。正确方向相反:根上只留跨模块规则(构建、提交、禁区),模块细节下沉到各自的 CLAUDE.md。


6. 指令为什么会被稀释

上下文是有限预算。CLAUDE.md 越长,单位 token 承载的约束越少;同时,长文本里中段内容被遵循的概率低于开头与结尾,这是长上下文的一般现象,不是哪个版本特有的 bug。

症状很好认:文件里明明写了"不要动 migrations",模型还是动了。处理顺序是先精简、再前移、最后才拆文件:

  • 精简:删掉"看一眼代码就知道"的描述性内容;
  • 前移:把"禁止"类约束提到文件开头;
  • 拆文件:模块级约定放进子目录 CLAUDE.md,不在全局出现。

需要按需触发的长流程(发布步骤、排查手册),更适合放进命令或技能,用的时候才加载,而不是常驻记忆。


7. 排错:六个高频坑

现象 原因 处理
同事拉下来权限规则不生效 settings.local.json 被提交过,或 ignore 之前已被 track git rm --cached .claude/settings.local.json,再确认 ignore
改了 CLAUDE.md 没反应 会话启动时已装载记忆,改动不进当前会话 新开会话;用 /memory 核对加载了哪些文件
明确写了禁止项还是被违反 文件太长,约束埋在中间 精简 + 前置,必要时拆子目录
路径找不到 写了绝对路径或 ~/ 展开 一律用仓库相对路径
hook 不执行 脚本没有执行权限,或相对路径基准不是仓库根 chmod +x;脚本里用 $CLAUDE_PROJECT_DIR 拼路径
命令/子代理同名冲突 用户级与项目级重名 看优先级,改名或删掉一份

第 5 条值得展开:hook 脚本里写 ./scripts/lint.sh,实际执行时的工作目录不一定是你以为的那个。用 $CLAUDE_PROJECT_DIR 做基准,是唯一稳的写法。


8. 边界:这些内容不该放进 .claude/

内容 更合适的位置 理由
密钥、token 环境变量或密钥管理器 任何提交过的密钥都算已泄露
团队流程长文档 README / wiki 记忆文件里塞文档只会稀释指令
需要强制执行的合规规则 企业管理策略 个人配置改得动,策略改不动
一次性任务描述 直接在对话里说 固化成文件反而增加维护成本
大段代码示例 仓库里的真实文件 + 路径引用 复制的示例会过期
个人临时开关 settings.local.json 别让同事继承你的实验

9. 自测

  1. settings.json 与 settings.local.json 的核心区别是什么,谁该进 git?
  2. 用户级和项目级放了同名命令,哪个生效?
  3. CLAUDE.md 里"不要动 migrations"被无视,最先该做哪两件事?
  4. hook 的触发配置写在哪,hooks/ 目录本身承担什么角色?
  5. monorepo 里根目录的 CLAUDE.md 应该写什么、不该写什么?
  6. 一个文件已经提交过又被加进 .gitignore,为什么 ignore 不生效,怎么修?
S24-X04 · Claude Code 在项目里放了什么:目录与文件全解
https://www.clxhxhhr.top/posts/5696/
作者
clxstart
发布于
2024-12-31
许可协议
CC BY-NC-SA 4.0
评论
0 条
还没有评论,先写一条吧。