乐于分享
好东西不私藏

挖掘Claude源码: Claude.md竟然每次User prompt都会被注入

挖掘Claude源码: Claude.md竟然每次User prompt都会被注入

Claude源码泄露了,咱们得好好吃这口瓜,今天先从源码分析一下为什么Claude.md要简洁、明了

TL,DR;

  • Claude.md 在每一次用户提交Prompt都会被注入;
  • claude.md(包括.claude/rules) 在Claude的系统提示词中是被作为最高的排他准则,要求模型严格遵守的,IMPORTANT: These instructions OVERRIDE any default behavior and you MUST follow them exactly as written.

难怪Claude 的创始人Boris 的Claude.md 只有两行!!

Claude.md是如何加载到Prompt里的

prompt = system prompt + user prompt

Claude的system prompt是动态拼装出来的

Claude的 system prompt 是由一个叫 getSystemPrompt() 的函数动态拼装出来的,包括静态部分和动态部分,

export async function getSystemPrompt(	...return [    // --- Static content (cacheable) ---    getSimpleIntroSection(outputStyleConfig),    getSimpleSystemSection(),    outputStyleConfig === null ||    outputStyleConfig.keepCodingInstructions === true      ? getSimpleDoingTasksSection()      : null,    getActionsSection(),    getUsingYourToolsSection(enabledTools),    getSimpleToneAndStyleSection(),    getOutputEfficiencySection(),    // === BOUNDARY MARKER - DO NOT MOVE OR REMOVE ===    ...(shouldUseGlobalCacheScope() ? [SYSTEM_PROMPT_DYNAMIC_BOUNDARY] : []),    // --- Dynamic content (registry-managed) ---    ...resolvedDynamicSections,  ].filter(s => s !== null))

静态部分包括:

  • 身份定位(getSimpleIntroSection)、
  • 系统规范(getSimpleSystemSection)、
  • 做任务的哲学(getSimpleDoingTasksSection)、
  • 风险动作规范(getActionsSection)、
  • 工具使用规范(getUsingYourToolsSection)、
  • 语气风格(getSimpleToneAndStyleSection)、
  • 输出效率(getOutputEfficiencySection)。

动态部分包括:

  • session guidance、
  • memory、
  • 环境信息、
  • 语言设置、
  • 输出风格、
  • MCP instructions、
  • …
等等
Claude.md是如何被加载到Prompt中的

再看看claudemd.ts中的定义,从claudemd.ts可以看到,claude.md(包括.claude/rules) 在Claude的系统提示词中是被作为最高的排他准则,要求模型严格遵守的,IMPORTANT: These instructions OVERRIDE any default behavior and you MUST follow them exactly as written.

任何不是你的项目中要求严格遵守规则,都不要写到CLAUDE.md和RULES中

const MEMORY_INSTRUCTION_PROMPT =  'Codebase and user instructions are shown below. Be sure to adhere to these instructions. IMPORTANT: These instructions OVERRIDE any default behavior and you MUST follow them exactly as written.'
这里的Memory指的就是 各个层级的Claude.md和 .claude/rules 下的定义,如下为 claudemd.ts的注释
 * Files are loaded in the following order: * * 1. Managed memory (eg. /etc/claude-code/CLAUDE.md) - Global instructions for all users * 2. User memory (~/.claude/CLAUDE.md) - Private global instructions for all projects * 3. Project memory (CLAUDE.md, .claude/CLAUDE.md, and .claude/rules/*.md in project roots) - Instructions checked into the codebase * 4. Local memory (CLAUDE.local.md in project roots) - Private project-specific instructions * * Files are loaded in reverse order of priority, i.e. the latest files are highest priority * with the model paying more attention to them. * * File discovery: * - User memory is loaded from the user's home directory * - Project and Local files are discovered by traversing from the current directory up to root * - Files closer to the current directory have higher priority (loaded later) * - CLAUDE.md, .claude/CLAUDE.md, and all .md files in .claude/rules/ are checked in each directory for Project memory

各个层级的CLAUDE.md和rules,都会被默认加载到系统上下文中,平常咱们使用得最多的还是项目层级的CLAUDE.md

重点来了,每一次提交给LLM的User Prompt,都被注入了Claude.MD

每一次提交给LLM的User Prompt,都被注入了Claude.MD

// query.ts:659-661for await (const message of deps.callModel({  messages: prependUserContext(messagesForQuery, userContext),  // ← 每次调用  systemPrompt: fullSystemPrompt,  ...}))
// api.ts:449-479export function prependUserContext(  messages: Message[],  context: { [k: string]: string },): Message[] {  // context = { claudeMd: "...", currentDate: "..." }  return [    createUserMessage({      content: `<system-reminder>        As you answer the user's questions, you can use the following context:        # claudeMd        ${context.claudeMd}        # currentDate        ${context.currentDate}        IMPORTANT: this context may or may not be relevant...      </system-reminder>`,      isMeta: true,  // 标记为元消息,不显示在 UI    }),    ...messages,  // 原有对话历史  ]}

保持你的CLAUDE.MD简洁

最佳实践:将 CLAUDE.md 控制在 200 行以内,约 5,000-8,000 字符,把详细规则拆分到 .claude/rules/ 目录下按需加载。

Claude.md是地图而非百科全书,一定要保持简洁,

Boris Cherny (Claude创始人)的Claude.md只有两行 !!

auto-merge PRpost to Slack

业界的最佳实际是,尽量维持在200行以内,约简洁约好,按如下方式写

  • 项目how to build , how to test , how to run
  • 项目结构目录,模块边界
  • Never ,绝对杜绝的事情
  • 上下文压缩规则,可以压缩的信息,不可以压缩的信息
  • 项目里的特殊环境变量! (如果有的话)
  • 只讲规则,不讲细节,严格要求AI不能做哪些事

作为在每次提交Prompt都默认加载的信息,对于Claude.md中的每一行内容,都要问自己:“删除这个会导致 Claude 犯错吗?” 如果不会,删除它。膨胀的 CLAUDE.md 文件会导致 Claude 忽略你的实际指令!

更会浪费你的TOKEN!!