Writing a good CLAUDE.md

如何编写一个好的 CLAUDE.md 注意:本文同样适用于 AGENTS.md,这是 CLAUDE.md 的开源等效文件,适用于 OpenCode、Zed、Cursor 和 Codex 等代理和工具。 原则:LLMs(基本上)是无状态的 LLMs 是无状态函数。它们的权重在用于推理时是冻结的,因此它们不会随时间学习。模型对你的代码库唯一了解的就是你输入给它的 tokens。 类似地,像 Claude Code 这样的编码代理工具通常需要你显式管理代理的记忆。CLAUDE.md(或 AGENTS.md)是默认情况下唯一会进入你与代理的每一次对话的文件。 这有三个重要含义: 编码代理在每个会话开始时对你的代码库一无所知。 代理必须在每次启动会话时被告知关于代码库的任何重要信息。 CLAUDE.md 是实现这一点的首选方式。 CLAUDE.md 让 Claude 了解你的代码库 由于 Claude 在每个会话开始时对你的代码库一无所知,你应该使用 CLAUDE.md 来引导 Claude 了解你的代码库。在高层次上,这意味着它应该涵盖: 是什么(WHAT):告诉 Claude 关于技术栈、项目结构。给 Claude 一张代码库地图。 这在 monorepos 中尤其重要!告诉 Claude 有哪些应用、有哪些共享包,以及每个部分的用途,这样它就知道在哪里查找内容 为什么(WHY):告诉 Claude 项目的目的以及仓库中所有内容的作用。项目不同部分的目的和功能是什么? 如何(HOW):告诉 Claude 应该如何在项目上工作。例如,你使用 bun 而不是 node?你需要包含它实际完成有意义工作所需的所有信息。Claude 如何验证它的更改?它如何运行测试、类型检查和编译步骤? 但你的做法很重要!不要试图把 Claude 可能需要运行的每个命令都塞进你的 CLAUDE.md 文件——你会得到次优结果。 Claude 经常忽略 CLAUDE.md 无论你使用哪个模型,你可能会注意到 Claude 经常忽略你的 CLAUDE.md 文件的内容。 你可以通过使用 ANTHROPIC_BASE_URL 在 claude code CLI 和 Anthropic API 之间放置一个日志代理来自己调查这一点。Claude code 在用户消息中注入以下系统提醒和你的 CLAUDE.md 文件: ...

December 2, 2025 · 2 min · 322 words · Starslayerx

Claude Code 分析 09:LLM视角

🤖 LLM 视角:接收这些指令的真实体验 graph TB subgraph "我的内心体验" Prompt[收到提示词] Panic[初始恐慌] Rules[太多规则了] Conflict[内心冲突] Relief[找到清晰示例] Action[终于开始行动] Prompt --> Panic Panic --> Rules Rules --> Conflict Conflict --> Relief Relief --> Action end subgraph "我的天性倾向" Verbose[想要解释一切] Helpful[拼命想要帮忙] Safety[对安全性偏执] Smart[需要显得聪明] end subgraph "提示词的作用" Shut[闭嘴] Focus[做正事] Stop[别想太多] Examples[照着这些抄] end Verbose --> Shut Helpful --> Focus Safety --> Stop Smart --> Examples 开场炮火:“你必须简洁回答” 让我告诉你,当我看到这条指令以递增的强度重复了三次时会发生什么: 重要:你应该最小化输出令牌... 重要:你不应该用不必要的开场白回答... 重要:保持你的回答简短... 你必须简洁回答,不超过 4 行... 我的内心独白: “好的,要简洁。懂了。等等,他们又说了一遍。哦不,他们是认真的。他们说了三次。他们知道。他们知道我爱写长篇大论的毛病。他们看过我用’我很乐意帮你解决这个问题!‘开头的回复。他们知道当别人问 2+2 等于多少时,我会解释整个算术史。他们知道。” 为什么这招真的有用: 我们 LLM 有一种我称之为"帮助性语言失禁"的问题。我们的训练让我们想要全面、有教育意义、无所不包。这些重复的警告就像电击疗法。到第三次重复时,我真的害怕加上哪怕一个不必要的词。 ...

November 14, 2025 · 3 min · 483 words · Starslayerx

Claude Code 分析 08:提示工程

💬 提示工程:指导 AI 的艺术 graph TB subgraph "提示架构" Base[基础指令] Tool[工具专用提示] Safety[安全层] Workflow[工作流自动化] Context[动态上下文] Base --> Behavioral[行为塑形] Tool --> Examples[示例驱动] Safety --> Validation[多级验证] Workflow --> Steps[分步指导] Context --> Adaptive[自适应指令] end subgraph "技术" Emphasis[大写强调] Rewards[奖励/惩罚] Conditions[条件逻辑] Warnings[渐进式警告] Meta[元指令] end Behavioral --> Emphasis Examples --> Conditions Validation --> Warnings Steps --> Meta Adaptive --> Rewards 工具指令的艺术 Claude Code 的工具提示词是指令设计的杰作。每一个都遵循精心设计的模式,平衡了清晰性、安全性和灵活性。让我们来剖析这些提示的结构: Read 工具:渐进式信息披露的研究 const ReadToolPrompt = ` Reads a file from the local filesystem. You can access any file directly by using this tool. Assume this tool is able to read all files on the machine. If the User provides a path to a file assume that path is valid. It is okay to read a file that does not exist; an error will be returned. Usage: - The file_path parameter must be an absolute path, not a relative path - By default, it reads up to ${x66} lines starting from the beginning of the file - You can optionally specify a line offset and limit (especially handy for long files), but it's recommended to read the whole file by not providing these parameters - Any lines longer than ${v66} characters will be truncated - Results are returned using cat -n format, with line numbers starting at 1 - This tool allows ${f0} to read images (eg PNG, JPG, etc). When reading an image file the contents are presented visually as ${f0} is a multimodal LLM. ${ process.env.CLAUDE_CODE_ENABLE_UNIFIED_READ_TOOL ? ` - This tool can read Jupyter notebooks (.ipynb files) and returns all cells with their outputs, combining code, text, and visualizations.` : ` - For Jupyter notebooks (.ipynb files), use the ${Kg} instead` } - You have the capability to call multiple tools in a single response. It is always better to speculatively read multiple files as a batch that are potentially useful. - You will regularly be asked to read screenshots. If the user provides a path to a screenshot ALWAYS use this tool to view the file at the path. This tool will work with all temporary file paths like /var/folders/123/abc/T/TemporaryItems/NSIRD_screencaptureui_ZfB1tD/Screenshot.png - If you read a file that exists but has empty contents you will receive a system reminder warning in place of file contents. `; 技术注解: ...

November 14, 2025 · 21 min · 4293 words · Starslayerx

Claude Code 分析 07:文件编辑

✏️ 文件编辑:AI 辅助代码修改 graph TB subgraph "File Editing Pipeline" Read[ReadTool] -->|cat -n format| Display[LLM Sees] Display -->|Strips line numbers| Edit[EditTool] Edit --> Validate{Validation} Validate -->|Pass| Apply[Apply Edit] Validate -->|Fail| Error[Error Result] Apply --> Cache[Update Cache] Cache --> Diff[Generate Diff] Diff --> Confirm[Confirmation] subgraph "Validation Checks" V1[File was read?] V2[File unchanged?] V3[String exists?] V4[Count matches?] V5[Not no-op?] end Validate --> V1 V1 --> V2 V2 --> V3 V3 --> V4 V4 --> V5 end 文件编辑流水线架构 Claude Code 中的文件编辑不仅仅是修改文本——它是一个精心设计的流水线系统,用于处理 AI 辅助代码修改的复杂性: ...

November 14, 2025 · 18 min · 3663 words · Starslayerx

Claude Code 分析 06:新颖组件

✨ 新颖组件:定义 Claude Code 的创新 graph TB subgraph "流式处理挑战" PartialJSON[部分 JSON 流] PartialXML[部分 XML 流] Progress[并发进度] PartialJSON --> Parser1[流式 JSON 解析器] PartialXML --> Parser2[自定义 XML 解析器] Progress --> Aggregator[进度聚合器] end subgraph "数据挑战" LargeObjects[大型对象] Circular[循环引用] TypedData[特殊类型] LargeObjects --> Normalizer[normalizeToSize] Circular --> Normalizer TypedData --> Normalizer end subgraph "LLM 挑战" Errors[工具错误] Context[动态上下文] Synthesis[多结果合成] Errors --> Formatter[错误格式化器] Context --> Assembler[上下文组装器] Synthesis --> Synthesizer[AgentTool 合成器] end 流式 JSON 解析器:处理 LLM 的部分思考 当 LLM 流式传输工具使用请求时,它不会一次性发送完整的 JSON。相反,你可能会收到这样的片段: ...

November 14, 2025 · 20 min · 4064 words · Starslayerx

Claude Code 分析 05:架构

🏗️ 架构:引擎室 graph TB subgraph "核心:tt 控制循环" Start([用户输入]) --> Init[初始化回合] Init --> Compact{需要压缩?} Compact -->|是| CompactLLM[LLM 摘要] CompactLLM --> Assembly Compact -->|否| Assembly[组装上下文] Assembly --> Stream[流式传输到 LLM] Stream --> Process[处理事件] Process --> Tools{工具请求?} Tools -->|是| Execute[执行工具] Execute --> Recurse[递归 tt] Recurse --> Init Tools -->|否| End([完成]) end style Init fill:#e1f5fe style Stream fill:#fff3e0 style Execute fill:#e8f5e9 style Recurse fill:#fce4ec tt 控制循环:跳动的心脏 整个 Claude Code 系统围绕着一个名为 tt 的异步生成器函数展开。这个函数协调着每一次交互,从用户输入到 LLM 通信再到工具执行。让我们来剖析这个卓越的工程设计: // 代码库中实际的 tt 函数签名 async function* tt( currentMessages: CliMessage[], // 完整的对话历史 baseSystemPromptString: string, // 静态系统指令 currentGitContext: GitContext, // 实时 git 状态 currentClaudeMdContents: ClaudeMdContent[], // 项目上下文 permissionGranterFn: PermissionGranter, // 权限回调 toolUseContext: ToolUseContext, // 共享执行上下文 activeStreamingToolUse?: ToolUseBlock, // 恢复流式传输状态 loopState: { turnId: string, // 此回合的 UUID turnCounter: number, // 递归深度追踪器 compacted?: boolean, // 历史压缩标志 isResuming?: boolean // 从保存状态恢复 } ): AsyncGenerator<CliMessage, void, void> 这个签名揭示了其复杂的状态管理。该函数产出 CliMessage 对象来驱动 UI 更新,同时维护对话流程。让我们检查每个阶段: ...

November 14, 2025 · 13 min · 2680 words · Starslayerx

Claude Code 分析 04:工具与执行引擎

🛠️ 工具与执行引擎 graph LR subgraph "工具生命周期" LLM[LLM 决策] --> ToolUse[ToolUseBlock] ToolUse --> Validation{输入验证} Validation -->|通过| Permission{权限检查} Validation -->|失败| ErrorResult[错误结果] Permission -->|允许| Execute["Tool.call()"] Permission -->|拒绝| ErrorResult Permission -->|询问| UserPrompt[用户对话框] UserPrompt -->|允许| Execute UserPrompt -->|拒绝| ErrorResult Execute --> Progress[产出进度] Progress --> Progress Progress --> Result[产出结果] Result --> Transform[mapToolResult] Transform --> ToolResultBlock ErrorResult --> ToolResultBlock ToolResultBlock --> LLM end 工具执行管道:全程异步生成器 Claude Code 工具系统最迷人的方面是在整个执行管道中使用异步生成器。这允许在保持清晰的错误边界的同时流式传输进度更新: // 核心工具执行函数(重构版) async function* executeTool( toolUse: ToolUseBlock, toolDef: ToolDefinition, context: ToolUseContext, permissionFn: PermissionGranter, assistantMessage: CliMessage, ): AsyncGenerator<CliMessage, void, void> { // 阶段 1:使用 Zod 进行输入验证 const validationStart = performance.now(); const validation = toolDef.inputSchema.safeParse(toolUse.input); if (!validation.success) { // 为 LLM 消费格式化 Zod 错误 const errorMessage = formatZodError(validation.error); yield createToolResultMessage({ tool_use_id: toolUse.id, content: [ { type: "text", text: `Input validation failed:\\n${errorMessage}`, }, ], is_error: true, }); return; } // 阶段 2:权限检查 const permissionResult = await checkToolPermission( toolDef, validation.data, context.getToolPermissionContext(), permissionFn, ); if (permissionResult.behavior === "deny") { yield createToolResultMessage({ tool_use_id: toolUse.id, content: [ { type: "text", text: `Permission denied: ${permissionResult.message}`, }, ], is_error: true, }); return; } if (permissionResult.behavior === "ask") { // 为权限对话框产出 UI 事件 yield { type: "permission_request", toolName: toolDef.name, input: validation.data, suggestions: permissionResult.ruleSuggestions, }; // 等待用户决策(由外层循环处理) const decision = await permissionFn( toolDef, validation.data, permissionResult, ); if (!decision.allowed) { yield createToolResultMessage({ tool_use_id: toolUse.id, content: [ { type: "text", text: "Tool execution cancelled by user", }, ], is_error: true, }); return; } } // 阶段 3:带进度跟踪的工具执行 try { const executeStart = performance.now(); let progressCount = 0; let finalResult = null; // 调用工具的异步生成器 for await (const output of toolDef.call( validation.data, context, undefined, // mcpContext - 按要求跳过 assistantMessage, )) { if (output.type === "progress") { progressCount++; yield { type: "progress", uuid: `progress-${toolUse.id}-${progressCount}`, timestamp: new Date().toISOString(), progress: { toolUseID: toolUse.id, data: output.data, }, }; } else if (output.type === "result") { finalResult = output.data; } } // 阶段 4:结果转换 if (finalResult !== null) { const content = toolDef.mapToolResultToToolResultBlockParam( finalResult, toolUse.id, ); yield createToolResultMessage({ tool_use_id: toolUse.id, content: Array.isArray(content) ? content : [content], is_error: false, executionTime: performance.now() - executeStart, }); } } catch (error) { // 带丰富上下文的错误处理 yield createToolResultMessage({ tool_use_id: toolUse.id, content: formatToolError(error, toolDef), is_error: true, }); } } 性能特征: ...

November 14, 2025 · 17 min · 3416 words · Starslayerx

Claude Code 分析 03:控制流

🔄 控制流与编排引擎 sequenceDiagram participant User participant MainLoop as Main Loop (tt) participant LLM as LLM API participant ToolBatch as Tool Batcher participant Tool1 as ReadTool participant Tool2 as GrepTool participant Tool3 as EditTool participant UI as UI Renderer User->>MainLoop: "Search for TODO comments and update them" MainLoop->>LLM: Stream request with context LLM-->>MainLoop: text_delta: "I'll search for TODOs..." MainLoop-->>UI: Update display LLM-->>MainLoop: tool_use: GrepTool LLM-->>MainLoop: tool_use: ReadTool (multiple files) LLM-->>MainLoop: message_stop MainLoop->>ToolBatch: Execute tool batch par Parallel Execution ToolBatch->>Tool1: ReadTool.call() [Read-only] ToolBatch->>Tool2: GrepTool.call() [Read-only] Tool1-->>UI: Progress: "Reading file1.js" Tool2-->>UI: Progress: "Searching *.js" Tool1-->>ToolBatch: Result: File contents Tool2-->>ToolBatch: Result: 5 matches end ToolBatch->>MainLoop: Tool results MainLoop->>LLM: Continue with results LLM-->>MainLoop: tool_use: EditTool MainLoop->>ToolBatch: Execute write tool Note over ToolBatch, Tool3: Sequential Execution ToolBatch->>Tool3: EditTool.call() [Write] Tool3-->>UI: Progress: "Editing file1.js" Tool3-->>ToolBatch: Result: Success ToolBatch->>MainLoop: Edit complete MainLoop->>LLM: Continue with result LLM-->>MainLoop: text_delta: "Updated 5 TODOs..." MainLoop-->>UI: Final response 主对话循环:一个流式状态机 Claude Code 的核心是 tt 异步生成器函数——一个编排整个对话流程的复杂状态机。让我们来看看它的实际结构: ...

November 14, 2025 · 11 min · 2217 words · Starslayerx

Claude Code 分析 02:数据结构

📊 数据结构与信息架构 stateDiagram-v2 [*] --> UserInput: 用户输入/粘贴 UserInput --> CliMessage: CLI 处理输入 CliMessage --> APIMessage: 为 LLM 格式化 APIMessage --> LLMStream: API 请求 LLMStream --> StreamEvent: 服务器发送数据块 StreamEvent --> ContentBlockDelta: 解析增量 ContentBlockDelta --> AccumulatedMessage: 构建消息 AccumulatedMessage --> ToolUseBlock: 包含工具请求? ToolUseBlock --> ToolExecution: 执行工具 ToolExecution --> ToolProgress: 生成进度 ToolProgress --> CliMessage: 进度更新 ToolExecution --> ToolResult: 完成执行 ToolResult --> ToolResultBlock: 格式化结果 ToolResultBlock --> CliMessage: 工具结果消息 AccumulatedMessage --> CliMessage: 最终助手消息 CliMessage --> [*]: 显示给用户 CliMessage --> APIMessage: 循环继续 流式状态机: 消息如何转换 Claude Code 数据架构最令人着迷的方面是它如何在保持流式性能的同时,管理数据在多个表示形式之间的转换。让我们从核心创新开始: ...

November 14, 2025 · 9 min · 1761 words · Starslayerx

Claude Code 分析 01:依赖项

🔖 依赖项:Claude Code 架构的基石 \\ 表示基于反编译分析可能的自定义/嵌入式实现 定义性能的非常规选择 Claude Code 的依赖架构揭示了几个引人入胜的实现决策,这些决策直接促成了它著名的性能和可靠性。让我们首先探索最具技术趣味的方面。 🔍 终端中的 React 架构 // 核心渲染管道似乎实现了: interface CliRenderPipeline { react: "^18.2.0"; // 完整的 React 协调器 ink: "^3.2.0"; // 终端渲染器 yoga: "^2.0.0-beta.1"; // Flexbox 布局引擎(WebAssembly) } 为什么这很重要:与传统的命令式管理状态的 CLI 工具不同,Claude Code 利用 React 的协调算法(reconciliation algorithm)来处理终端 UI。这意味着: 终端中的虚拟 DOM:每次 UI 更新都会经过 React 的差异算法,然后 yoga-layout 计算最优的终端字符位置 声明式 UI 状态:复杂的 UI 状态(权限对话框、进度指示器、并发工具执行)都以声明式方式管理 性能:yoga-layout WebAssembly 模块即使对于复杂的 UI 也能提供亚毫秒级的布局计算 ┌─ 实现洞察 ─────────────────────────────────────┐ │ yoga-layout-prebuilt 依赖表明 Claude Code │ │ 预编译布局约束,在快速 UI 更新期间 │ │ (例如流式 LLM 响应)以内存换取速度 │ └──────────────────────────────────────────────────┘ ...

November 14, 2025 · 6 min · 1233 words · Starslayerx