
我在刚接触 Claude Code 的前两周里几乎每天都在跟它为什么不听我指挥作斗争。装好后第一次运行它把我项目里不该动的测试文件改了个遍第二次想让它记住我的代码风格结果每次新对话都要重新交代一遍第三次想限制它访问某些目录翻了半天文档才找到正确的配置字段。后来我才意识到Claude Code 的行为控制根本不是靠某个单一配置文件而是由settings.json、CLAUDE.md和memory这三套体系各司其职、共同决定的。这三者之间的关系如果没理清楚后面所有折腾都像是在盲人摸象。这篇文章我就把这三套配置体系的职责分工、加载顺序、编写方法和实际踩坑经验一次讲透。1. 为什么一套配置不够用三套体系的职责边界与协作逻辑1.1 三个配置文件到底各管什么先给一个最直观的类比settings.json是 Claude Code 的运行参数决定它能用什么、不能用什么、以什么身份运行CLAUDE.md是 Claude 的岗位手册告诉它你的工作对象是什么、应该怎么干活memory是 Claude 的私人备忘录记录它在过去对话里学到的关于你个人偏好的零散信息。这三者的定位差异从我实际使用体验来看非常分明配置项控制层面典型问题生效范围settings.json运行时行为能否执行 Bash、能否读写文件、用什么模型用户级 / 项目级CLAUDE.md项目认知项目结构、构建命令、代码风格、禁止事项用户级 / 项目级memory长期记忆你的命名偏好、常用工具链、历史决策全局用户维度很多人搞混CLAUDE.md和memory觉得二者都像是给 Claude 看的说明文字。但关键区别在于CLAUDE.md是你主动编写的显式指令而memory是 Claude 在对话过程中自动沉淀下来的隐式记忆。前者像公司章程后者像员工的个人笔记——章程规定了组织架构和行为准则笔记记录的是上次那个客户喜欢喝美式这种细节。1.2 加载顺序与优先级后加载的会覆盖先加载的吗实际加载顺序并不是简单的谁后加载谁覆盖而是要分维度的。Claude Code 启动时会按以下顺序读取配置用户级~/.claude/settings.json项目级.claude/settings.json在项目根目录下本地开发配置.claude/settings.local.json不入版本库的那个对于权限配置三者是合并的但优先级不同settings.local.json的permissions会覆盖项目级项目级会覆盖用户级。也就是说如果你在用户级把Bash(npm:* )设为allow而在项目级设为deny那么在这个项目里执行 npm 命令仍会被拒绝。而对于CLAUDE.md用户级~/.claude/CLAUDE.md和项目级CLAUDE.md都会被加载二者是叠加关系而非覆盖关系。Claude 的 System Prompt 会同时携带两份内容你把项目专属信息写到项目级、把通用的个人偏好写到用户级是最合理的做法。1.3 一个典型会话里的配置流当你进入项目目录启动claude时实际发生的是这样的流程加载用户级settings.json确定全局权限和模型参数加载项目级settings.json覆盖或追加权限读取用户级CLAUDE.md获取你的通用偏好读取项目级CLAUDE.md获取当前项目的结构说明加载历史memory中的相关片段这些片段最终也会被写入或引用CLAUDE.md这样设计的好处是通用规则写一次全局生效项目规则跟着仓库走、可以多人共享而个人记忆属于个人不污染团队配置。坏处也显而易见——如果你不知道某个配置被哪一层盖住了排查起来非常头疼。后面我会专门讲排查顺序。2. settings.json运行时行为的总开关2.1 配置文件的位置与优先级陷阱settings.json有三个放置位置对应三种作用域这是最容易踩坑的地方~/.claude/settings.json用户级所有项目生效项目根目录.claude/settings.json项目级随仓库分享给团队成员项目根目录.claude/settings.local.json本地专属应该被.gitignore忽略我见过不少团队的坑是有人把个人电脑上的settings.local.json硬提交到了仓库里导致同事拉代码后莫名其妙多了一堆权限拦截或者模型指向错误。这里给个建议凡是跟个人环境相关的内容比如 API endpoint、个人 token、本地路径统统放 local 文件凡是团队统一规则比如禁用的命令列表、必须的 hook放项目级文件。一个常见的反面案例是这样团队在项目级settings.json里设置了permissions: { deny: [Bash(git push:* )] }防止 AI 乱推送代码但某个成员自己在 local 文件里写了permissions: { allow: [Bash(git push:* )] }结果这个保护就形同虚设了。2.2 权限模型allow / deny / ask 的判定逻辑permissions是settings.json里最核心的字段它控制 Claude 能调用哪些工具。以 Bash 工具为例典型的配置长这样{ permissions: { allow: [ Bash(npm:*), Read(~/projects/**) ], deny: [ Bash(rm -rf:*), Edit(~/secrets/**) ], ask: [ Bash(git push:*), Write(~/projects/jason/*) ] } }判定优先级是denyallowask 默认未配置时默认询问。这意味着哪怕你把某个操作同时写进了 allow 和 deny最终结果也是拒绝——这条规则非常反直觉我曾经困惑了很久。Bash(npm:*)这类语法的匹配逻辑是这样括号里是命令前缀匹配npm:*表示以npm:开头的命令即 npm 子命令而Bash(rm -rf:*)表示精确匹配rm -rf这个前缀。注意Bash(rm:*)并不会匹配rm -rf因为rm: *匹配的是rm后跟任意内容的命令rm -rf显然不匹配rm这个前缀。所以如果想让 Claude 永远不能执行任何形式的rm你得写Bash(rm:*)和Bash(rmdir:*)两条。2.3 hooks在工具调用前后塞入自定义逻辑hooks是settings.json里很有价值但容易被忽视的子体系。它允许你在 Claude Code 调用某些工具的前后执行自定义脚本常用于安全防护、日志记录、格式化增强。官方提供了四种挂钩时机PreToolUse工具执行前触发可以用来拦截危险操作PostToolUse工具执行后触发可以用来校验输出或触发后续动作Notification收到通知时触发UserPromptSubmit用户提交 prompt 时触发一个实用的拦截脚本例子在PreToolUse阶段检查参数里是否包含.env文件路径一旦发现就拒绝执行并给出提示。hooks 配置里关键字段是matcher匹配哪个工具和hooks具体执行的命令命令里可以使用$CLAUDE_PROMPT、$TOOL_NAME、$TOOL_INPUT这些内置变量。{ hooks: { PreToolUse: [ { matcher: Read, hooks: [ { type: command, command: node /path/to/check_read.js } } } ] } }需要说明的是hook 命令执行完的退出码决定了流程走向退出码 0 表示放行非 0 表示拦截。这是实现软性安全检查的核心技巧。注意 hook 本身是同步阻塞的如果脚本写得低效Claude 的响应速度会明显变慢。2.4 模型配置与第三方 API 接入settings.json里还能指定 Claude Code 使用的模型{ model: claude-sonnet-4-20250514, env: { ANTHROPIC_API_KEY: sk-ant-xxx } }这里有个非常实用的技巧如果你不想用 Anthropic 官方 API而是想接第三方兼容接口可以通过设置环境变量来实现。比如很多国产大模型平台提供 Anthropic 兼容的 API 端点你可以在 shell 里设置ANTHROPIC_BASE_URL指向第三方地址ANTHROPIC_AUTH_TOKEN或ANTHROPIC_API_KEY换成第三方密钥。社区里常见的cc switch这个工具本质就是在帮你快速切换不同的ANTHROPIC_BASE_URL和 key 组合它并不修改 Claude Code 本体只是改写你的环境变量配置而已。我自己实测接 DeepSeek 和 Qwen 的 Anthropic 兼容接口时发现Claude Code 的代码生成质量和上下文管理机制仍会保留但部分高级功能比如 Artifacts、特定的工具调用可能与第三方模型不兼容表现为工具调用异常或响应格式错误。如果你遇到Claude Code 能开起来但一问三不知的情况优先检查是不是第三方模型的 System Prompt 处理能力不满足要求。2.5 其他关键字段statusLine、includeCoAuthoredBy 等除了上述核心字段settings.json还有几个容易被忽略但影响体验的选项statusLine: {type: command, command: ...}自定义状态栏显示信息可以放当前分支、函数名、token 统计等。includeCoAuthoredBy: true/false控制提交信息中是否附加 Co-Authored-By 标记。forceLoginMethod: github强制使用 GitHub 账号登录方式。cleanupPeriodDays控制历史会话的清理周期默认值会周期性清理旧会话如果你需要保留长期记忆可以适当调大。2.6 一份可直接套用的 settings.json 基础模板最后给一份我目前生产环境在用的基础模板包含注释的版本供你直接复制改改{ model: claude-sonnet-4-20250514, permissions: { defaultMode: acceptEdits, allow: [ Bash(npm:*), Bash(node:*), Read(~/projects/**) ], deny: [ Bash(rm -rf:*), Bash(git push:*), Read(~/secrets/**) ], ask: [ Bash(git commit:*), Write(~/projects/jason/**) ] }, hooks: { PreToolUse: [ { matcher: Read|Edit|Write, hooks: [ { type: command, command: node ~/.claude/hooks/block_env_files.js } ] } ] }, env: { ANTHROPIC_SMALL_FAST_MODEL: claude-3-5-haiku-20241022 }, includeCoAuthoredBy: false }那个block_env_files.js脚本会在读文件前检查路径是否包含.env或密钥文件一旦命中就输出错误并返回非 0 退出码。这是我在真实项目中专门为安全加固加的因为 AI 读文件太随性遇到.env很容易直接在对话里把密钥贴出来。3. CLAUDE.md让 Claude 真正懂你的项目3.1 用户级与项目级的写作分工CLAUDE.md是 Claude Code 里第二套核心配置体系它的本质是我在这个项目里应该如何工作的说明文档。Claude Code 启动时会自动加载用户级~/.claude/CLAUDE.md和项目级CLAUDE.md如果存在的话把内容合入 System Prompt这相当于给 Claude 提前上课。用户级CLAUDE.md适合放跨项目通用的个人偏好比如所有回答使用中文代码注释使用英文第三方请求需要先给出构建命令再执行不要编辑 lockfile项目级CLAUDE.md适合放当前仓库专属的上下文比如项目技术栈、目录结构说明、构建/测试命令、代码风格约定、以及哪些文件绝对不要动。3.2 一段高质量 CLAUDE.md 长什么样我手头一个真实项目的CLAUDE.md大致长这样你可以感受下结构# Project Guidelines ## Tech Stack - Node.js 20 TypeScript 5.x - Backend: Express Prisma - Frontend: React Vite ## Commands - Install: npm install - Dev: npm run dev - Build: npm run build - Test: npm test - Lint: npm run lint ## Architecture - src/api/ contains REST endpoints - src/services/ contains business logic - src/models/ Prisma schema and types ## Code Style - Use async/await, no callbacks - Use 2 spaces for indentation - Export named functions, not default exports unless required - All API responses should use the ApiResponse wrapper ## Critical Rules - NEVER modify prisma/schema.prisma without asking - NEVER commit to main branch directly - ALWAYS run npm test before claiming a task complete - Do not edit package-lock.json manually这种写法的重点在于信息密度高、边界清晰、命令可复制。Claude 是语言模型不是预言机你给它越明确的规则它的行为偏差越小。尤其Always run npm test before claiming a task complete这种表述比尽量测试一下有效得多。3.3 编写技巧如何让 Claude 真正读进去这里有几个实战心得是常规文档不会告诉你的第一用肯定句式多于否定句式。Claude 在遵从ALWAYS do X的能力强于NEVER do Y因为否定句式需要模型先枚举所有可能行为再逐一排除而肯定句式是直接约束行为。第二把最关键的规则放在文件前 1/3。System Prompt 里的内容存在注意力窗口效应靠后的内容被模型遗忘的概率更高。我的CLAUDE.md把Critical Rules放在开头而把技术栈明细放后面。第三尽量具体到命令级。不是写请保证代码质量而是写使用npm run lint检查修复所有 error 级别问题后再提交。命令明确的指令Claude 会当作硬约束执行模糊的目标则可能被它自由裁量。第四一次会话聚焦一个主要目标。如果你在CLAUDE.md里塞了二十条规则模型可能只会提取最相关的一部分。最好把规则控制在 10 条以内并且每条之间尽量不要语义重叠。3.4 常见错误写法与修改日志的价值反面教材则是很多新手常犯的错误我贴两个典型错误一写了太多情绪化指令。请好好处理错误不要让用户生气——这类表述除了占用 token 没有任何约束力。错误二文件内容陈旧半年不更新。Claude 会信任CLAUDE.md里的命令路径如果你改了构建工具但没更新文档它就会执行不存在的命令然后一直报错。这里建议在CLAUDE.md文件头部维护一个简单的更新时间戳和变更说明提醒自己在重大项目变更时同步修改文档# Project Guidelines _last_updated: 2025-06-10 _changed: [2025-06-10] switched build tool from webpack to vite修改日志看起来多此一举但在 Claude Code 这种每次对话都重新读文档的工具里它是保证文档可信度的关键细节。4. memoryClaude 的长期记忆体系4.1 自动记忆的触发与沉淀过程Claude Code 的memory体系和前两者完全不同——它是动态的、由对话自动驱动的。在对话过程中Claude 会判断哪些信息值得长期保留并写入记忆。这些内容通常在会话结束时被整理成一条条记忆碎片Jason 使用 2 空格缩进Jason 不喜欢自动修改 lockfile该项目使用 pnpm 而非 npm这些记忆最终会出现在~/.claude/目录下的记忆存储文件中不同版本路径可能略有不同并且在后续会话中被自动加载。这个机制是 Claude Code 真正越用越懂你的原因。4.2 /memory 命令与显式记忆管理如果你想主动干预记忆内容可以用/memory命令调出记忆管理界面。它支持三种操作查看当前所有记忆片段手动新增一条由你指定的记忆删除或编辑已有记忆手动新增记忆的典型场景是当你做了某个一次性操作比如决定项目使用 pnpm 替代 npm你会希望这个决策被长期记住但又不想写进团队的CLAUDE.md因为只代表你个人习惯。这时/memory命令就派上了用场可以直接说记住这个项目使用 pnpm 安装依赖Claude 就会把它作为一条持久化的用户偏好记录。4.3 与 CLAUDE.md 的关系内存最终要落盘根据实测经验memory和CLAUDE.md之间存在联动在合适的时机Claude 会把你反复强调的偏好提议升级为CLAUDE.md中的正式条目。例如你三次在会话里说测试用 vitest 别用 jest第三次时 Claude 可能会主动问要不要把这个偏好写入项目的 CLAUDE.md 如果同意它就会直接修改文件。反过来的联动也有如果你的CLAUDE.md里写了一些跟当前会话冲突的内容Claude 的记忆碎片可能会保留旧版本结果表现为改完 CLAUDE.md 后它还是按老规矩办事。遇到这种情况直接删掉或编辑对应的记忆碎片往往比反复修改CLAUDE.md更有效。4.4 什么该进 memory什么该进 CLAUDE.md这是个很实际的问题我的取舍标准是这样的场景写入位置理由团队所有成员都应遵守的规则项目级CLAUDE.md随仓库分发团队共享只属于你个人的工作习惯/memory或用户级CLAUDE.md不污染团队配置临时性决策只影响本次开发都不写直接在会话里说写多了反而干扰项目架构的核心说明项目级CLAUDE.md需要团队共享且是新成员入职时的上下文极少用但重要的的常识类偏好/memory单独存放让CLAUDE.md保持精简一个常见的反模式是把所有偏好全塞进CLAUDE.md结果文件膨胀到 50 行以后模型反而不太遵守后面的规则了。保持写进 CLAUDE.md 的是团队规则写进 memory 的是个人习惯这个分工能让两个体系都保持高可用性。4.5 记忆机制的局限性不是数据库关于memory体系必须有一个清醒的认识它的容量和可靠性有限。Claude Code 的记忆并不等同于传统数据库那样精确更像是一个启发式的摘记系统。如果你向它要求记住 API 文档里第三页第二个表格的全部内容它大概率会记成摘要而不是原样复制。所以我的经验是关键信息必须写进CLAUDE.md或代码注释memory 只用来存放偏好类信息。项目里重要的接口调用方式、密钥存放位置、部署流程这些都不应该依赖 memory 去记忆因为一旦记忆碎片在自动整理过程中被截断或合并后续会话就可能丢失关键细节。5. 配置实测中的高频坑与排查顺序5.1 装了跑不起来平台可用性检查与 Node 版本热搜里有个词条是 note: claude code might not be available in your country这确实是安装阶段最常见的问题。Claude Code 对运行地区有限制如果你的网络出口属于不支持的区域安装后的首次登录会直接提示不可用。遇到这种情况第一件事不是找特殊渠道而是确认你的网络环境是否被官方支持。另一个高频原因是 Node.js 版本不满足要求。Claude Code 需要 Node 18 以上的版本我实测 Node 16 会直接报语法错误或安装失败。排查顺序是这样先确认node -v是否大于 18确认npm -v正常在项目目录执行claude --version看版本号是否打印如果版本号正常再排查登录状态claude启动后是否跳转到浏览器授权5.2 VS Code 集成插件装的顺序与配置生效条件很多人问 VS Code 里怎么接 Claude Code。其实 Oscar 最新的插件Claude Code for VS Code 扩展本质上是启动一个内置终端来跑claude命令。也就是说VS Code 插件能用不取决于插件本身而取决于你系统里claude命令是否能正常跑。插件只是个壳。最容易踩的坑是在 VS Code 的集成终端里claude命令可用但插件却报command not found。原因几乎都是 PATH 环境变量没有被图形界面应用加载到尤其是用 nvm 管理 Node 的场景。解决方法是把 Node 的 bin 目录同时写入 shell 配置文件.zshrc/.bashrc之外还要确保 VS Code 重启后能加载到。我实际测试里最稳妥的方案是在 VS Code 的settings.json里显式设置终端 PATH{ terminal.integrated.env.linux: { PATH: /Users/jason/.nvm/versions/node/v20.11.0/bin:${env:PATH} } }5.3 登录与不登录的差异以及第三方模型接入的坑关于注册账号与不注册的区别不登录时 Claude Code 基本上处于受限状态很多智能功能记忆功能、联网搜索、项目管理能力都不可用只能作为普通对话界面。而登录后尤其是付费账号才能解锁全部工具调用能力和自定义配置。第三方模型接入则要注意一个特殊点很多兼容接口只实现了 Chat Completions 的文本能力没有实现 Claude Code 特有的工具调用协议。你可以在settings.json里把model指向第三方模型但如果它不支持 tool_useClaude Code 的 Bash、Edit、Read 工具就会全部失效表现为AI 只会回答文字但从不动手干活。所以接第三方模型前一定要确认该服务商是否支持 Anthropic 的 tool use 协议。cc switch 这类工具能帮你快速验证多组 endpoint但如果换了模型后工具链失效问题往往在端点能力上不在 Claude Code 配置上。5.4 权限配置不生效的十大排查思路最后分享我总结的配置排查链路按优先级排确认配置文件在正确的层级你改了用户级~/.claude/settings.json但项目级.claude/settings.json存在同名配置项目级会覆盖用户级。确认文件是否是合法的 JSONsettings.json里多加一个尾逗号会导致整个文件加载失败Claude Code 会静默回退到默认配置不报任何错误。这是最隐蔽的坑——你改了配置但好像什么都没发生先检查 JSON 语法。确认CLAUDE.md路径正确项目级文件必须在项目根目录名字严格是CLAUDE.md全大写无扩展名变体如果你用claude.md或CLAUDE.MD会被直接忽略。确认权限语法精确匹配Bash(npm:*)不等于Bash(npm install:*)前者允许所有 npm 子命令后者只允许npm install这一个具体命令。确认是否存在 shell alias 干扰如果你的 shell 给git设置了 aliasClaude Code 匹配权限时用的是 alias 展开后的命令。这个很反直觉我排查过一次。确认 hooks 是否误伤PreToolUse钩子如果逻辑写错会导致所有工具调用被拦截。测试 hook 时建议先注释掉确认问题确实由 hook 引起。确认环境变量没有被覆盖多个配置文件里如果都设置了env后加载的会覆盖先加载的同名变量而不是合并。比如 local 文件里的 API key 是空字符串可能导致认证失败。确认 memory 中没有旧规则残留改配置没用时用/memory查看是否有历史记忆碎片在起冲突。确认 Claude Code 版本已更新旧版本对某些配置字段的支持不完整如果新旧版本字段变化可能静默忽略。执行claude update更新到最新版再试。确认进程重启过配置文件在会话启动时加载一次如果你改了配置但没重启 Claude Code新配置不会生效。这听起来像废话但确实是我最常犯的错。5.5 一个完整的排查案例去年我遇到过一个问题我给项目CLAUDE.md写了NEVER usenpmonly usepnpm重启后 Claude 依然执行npm install。起初以为规则写得不到位后来一步步排查才发现这个项目的.claude/settings.json里有人配置了一个 hook会自动把npm转换成pnpm转换动作发生在 Claude 执行 Bash 之前的工具调用预处理阶段。Claude 本身看到的命令自然是npm install但实际执行已经变成pnpm install了。这个案例让我明白配置不起作用时不能只盯文本层面还要考虑 hooks 这类暗箱操作。如果按常规排查顺序走这种问题会非常难发现因为你检查CLAUDE.md内容完全正确、检查 shell 也没发现 alias、检查权限也正常。只有当你把整个工具链从头到尾捋一遍——从CLAUDE.md到settings.json到hooks到 shell 环境才会在最不起眼的地方抓到真凶。这也是为什么我建议每个用 Claude Code 的人都应该建立自己的配置排查清单而不是等到出了诡异问题再临时翻文档。从settings.json的权限模型到CLAUDE.md的写作规范再到memory的记忆管理这三套体系本质上是在回答同一个问题如何让一个通用大模型在特定环境里成为一个守规矩、懂背景、有记忆的协作者。配置的每一项改动都是在塑造这个协作者的行为边界和提高它的上下文感知能力。希望这篇文章能帮你从AI 乱飞的沮丧中走出来真正把 Claude Code 调教成得心应手的开发伙伴。