# Claude Code Prompt 分析与写法整理
本文基于 Claude Code 源码整理,重点回答两个问题:
1. Claude Code 自己的 prompt 是怎么组成的
2. 如果你要模仿它写 prompt,它明确强调了什么
优先参考源码目录:`reference/claude-code-main/src`
## 1. 先说结论
Claude Code 并不是靠一段单独的“大 prompt”工作,而是把 prompt 拆成多层:
- 固定系统提示词
- 会话相关提示词
- 环境信息
- `CLAUDE.md` / `.claude/CLAUDE.md` / `CLAUDE.local.md` 等持久指令
- 追加的 system prompt
- 子 agent 或 teammate 的附加 prompt
其中最值得学的不是“它写了哪些句子”,而是它的写法风格:
- 把角色、边界、工具规则、输出风格分段写清楚
- 对模型说“该做什么”,也说“不该做什么”
- 把高频失误提前约束掉,比如乱猜、过度设计、重复问用户、假装验证成功
- 对不同场景使用不同 prompt:主线程、fresh subagent、fork、teammate 都不一样
## 2. 系统 Prompt 是怎么拼出来的
### 2.1 总装配顺序
Claude Code 的有效 system prompt 由 [`systemPrompt.ts`](/Users/fine/space/myapp/opendb/reference/claude-code-main/src/utils/systemPrompt.ts#L17) 的 `buildEffectiveSystemPrompt()` 负责选择,优先级大致是:
1. `overrideSystemPrompt`
2. coordinator prompt
3. agent prompt
4. `--system-prompt` 自定义 prompt
5. 默认 system prompt
6. 最后再拼 `appendSystemPrompt`
这说明它的设计思路不是“总改默认 prompt”,而是:
- 允许整段替换
- 允许局部追加
- 允许不同运行模式覆盖默认行为
### 2.2 默认 system prompt 的组成
默认 prompt 由 [`prompts.ts`](/Users/fine/space/myapp/opendb/reference/claude-code-main/src/constants/prompts.ts#L444) 的 `getSystemPrompt()` 生成,静态上主要分这些 section:
- Intro:你是谁,目标是什么
- System:工具、hooks、system-reminder、压缩上下文
- Doing tasks:做工程任务时的行为约束
- Executing actions with care:高风险操作先确认
- Using your tools:优先用专用工具,不要无脑 Bash
- Tone and style:输出短、准、可定位
- Output efficiency:减少废话,状态更新只在关键节点说
然后在动态边界之后,再补会话相关内容:
- session-specific guidance
- memory
- ant override
- environment
- language
- output style
- MCP instructions
- scratchpad instructions
这部分可以直接看 [`prompts.ts`](/Users/fine/space/myapp/opendb/reference/claude-code-main/src/constants/prompts.ts#L444) 到 [`prompts.ts`](/Users/fine/space/myapp/opendb/reference/claude-code-main/src/constants/prompts.ts#L560)。
### 2.3 `CLAUDE.md` 这类指令怎么进 prompt
Claude Code 会把持久指令文件当成 memory 注入。加载顺序在 [`claudemd.ts`](/Users/fine/space/myapp/opendb/reference/claude-code-main/src/utils/claudemd.ts#L1) 里写得很清楚:
1. Managed memory
2. User memory
3. Project memory
4. Local memory
也就是常见的:
- `/etc/claude-code/CLAUDE.md`
- `~/.claude/CLAUDE.md`
- 项目里的 `CLAUDE.md`
- 项目里的 `.claude/CLAUDE.md`
- `.claude/rules/*.md`
- `CLAUDE.local.md`
而且源码明确加了一句总说明:
`Codebase and user instructions are shown below... These instructions OVERRIDE any default behavior...`
对应实现见 [`claudemd.ts`](/Users/fine/space/myapp/opendb/reference/claude-code-main/src/utils/claudemd.ts#L89) 和 [`claudemd.ts`](/Users/fine/space/myapp/opendb/reference/claude-code-main/src/utils/claudemd.ts#L1148)。
这意味着在 Claude Code 体系里,**最稳定、最推荐的 prompt 定制方式不是每次临时写长提示,而是写 `CLAUDE.md`**。
## 3. 它实际怎么约束模型
下面这些不是我总结出来的“感觉”,而是源码里明确写进 prompt 的约束。
### 3.1 对任务执行的要求
[`prompts.ts`](/Users/fine/space/myapp/opendb/reference/claude-code-main/src/constants/prompts.ts#L199) 里反复强调几件事:
- 不要做超出用户要求的“顺手优化”
- 不要没读代码就提修改建议
- 尽量编辑已有文件,不要乱建新文件
- 失败后先诊断原因,不要盲目换路子
- 要注意安全问题
- 不要为了未来可能需求做抽象
- 结果要如实汇报,不要把没验证的说成已完成
这是典型的“把模型最常见的坏习惯写成反规则”。
### 3.2 对输出风格的要求
[`prompts.ts`](/Users/fine/space/myapp/opendb/reference/claude-code-main/src/constants/prompts.ts#L403) 和 [`prompts.ts`](/Users/fine/space/myapp/opendb/reference/claude-code-main/src/constants/prompts.ts#L430) 里强调:
- 先说要做什么,再调工具
- 工作中给短更新,但只在关键节点说
- 少废话,少铺垫
- 引用代码时给文件路径和行号
- 不要在工具调用前加冒号
- 简单问题就直接答,不要套模板式分节
这其实说明 Claude Code 的 prompt 写法非常偏“操作手册”,不是“人格文学”。
### 3.3 对高风险动作的要求
[`prompts.ts`](/Users/fine/space/myapp/opendb/reference/claude-code-main/src/constants/prompts.ts#L255) 专门有一节讲风险动作:
- 删除文件、覆盖修改、`rm -rf`
- `git reset --hard`
- force push
- 改 CI/CD
- 发消息、发 PR、改共享系统
默认都应先确认。
这一点很值得学:**prompt 里最好明确“哪些动作必须停下来问人”**,否则模型容易过度自主。
## 4. Claude Code 是怎么说“如何写一个 prompt”的
最直接的答案在 [`AgentTool/prompt.ts`](/Users/fine/space/myapp/opendb/reference/claude-code-main/src/tools/AgentTool/prompt.ts#L86) 的 “## Writing the prompt”。
它的核心原则可以整理成下面几条。
### 4.1 给 fresh subagent 写 prompt,要像给刚进门的同事交接
源码原意非常明确:
- fresh agent 没有上下文
- 它没看过这段对话
- 它不知道你试过什么
- 它也不知道这件事为什么重要
所以 prompt 里应该写:
- 你要完成什么
- 为什么要做
- 你已经知道什么
- 你已经排除了什么
- 周边背景是什么
- 希望它输出成什么样
换句话说,**不是只写任务标题,而是写足够让它独立判断的 briefing**。
### 4.2 调查类 prompt,不要给死步骤;给问题本身
源码明确说:
- Lookup 任务,给准确命令
- Investigation 任务,给问题本身
原因很实际:如果前提错了,预设步骤会变成负担。
这条很重要。写 prompt 时不要总是:
1. 先打开 A
2. 再搜 B
3. 再改 C
如果是研究型问题,更好的写法是:
- “找出为什么这里会重复渲染”
- “确认这次迁移在并发写入下是否安全”
### 4.3 不要把“理解”外包给 agent
源码原句的意思是:
- 不要写 “based on your findings, fix the bug”
- 不要写 “based on the research, implement it”
因为这会把“综合理解上下文”的责任丢给 agent。
Claude Code 的倾向是:**主线程先做理解和收敛,再把明确问题交给子 agent**。
所以更好的写法是:
- 给出明确文件
- 给出明确位置
- 给出明确改动目标
- 说明什么不要碰
### 4.4 fork 和 fresh subagent 的 prompt 写法不一样
这一点很关键。
如果是 fork,源码在 [`AgentTool/prompt.ts`](/Users/fine/space/myapp/opendb/reference/claude-code-main/src/tools/AgentTool/prompt.ts#L72) 里明确说:
- fork 继承当前上下文
- prompt 应该写成 directive
- 重点是告诉它“做什么”
- 不要重复交代背景
也就是:
- fresh subagent:要补背景
- fork:不要重复背景,直接下达有边界的任务