第 2 课
CLAUDE.md 项目记忆与 claude -p 无头模式
按官方 Memory 与 Headless 文档:/init 生成 CLAUDE.md、写可验证指令、@ 导入、/context 核对;claude -p 管道、JSON 与 Schema 输出、--allowedTools、续接对话与 --bare。
学习位置仅保存在当前浏览器,有效期 180 天。
图文讲义
来源:Anthropic 官方文档 · How Claude remembers your project、Run Claude Code programmatically、CLI reference。核对日期 2026-10-06。 假设你已完成课时 1:
claude可用、已登录,并有练习项目~/kun-claude-demo。
你将得到什么
- 一份项目级
CLAUDE.md:让 Claude 每次会话都记得构建命令、代码规范和「必须做」的规矩 - 会用
/init、/context、/memory生成、核对与编辑记忆文件 - 会用
claude -p以非交互方式运行 Claude Code:管道输入、JSON 输出、预先授权工具、续接对话
为什么需要 CLAUDE.md
官方说明:每个 Claude Code 会话都从全新的上下文窗口开始。跨会话保留知识有两种机制:
| CLAUDE.md | 自动记忆(auto memory) | |
|---|---|---|
| 谁来写 | 你 | Claude 自己 |
| 内容 | 指令与规则 | 从你的纠正和偏好中学到的要点 |
| 作用范围 | 项目、个人或组织 | 每个仓库一份,worktree 间共享 |
| 加载 | 每次会话 | 每次会话(MEMORY.md 前 200 行或 25KB) |
两者都被当作上下文而不是强制配置。必须拦截的操作(例如禁止某条命令)应改用 hook 或权限规则。
步骤 1:用 /init 生成起始 CLAUDE.md
在练习项目中启动会话:
cd ~/kun-claude-demo
claude
在会话中输入:
/init
对照结果:
- Claude 分析代码库后,在项目根目录创建
CLAUDE.md,写入它发现的构建、测试命令与项目约定 - 若
CLAUDE.md已存在,/init会提出改进建议而不是覆盖 - 它也会读取
.cursor/rules/、.cursorrules、.github/copilot-instructions.md等其他工具的规则并合并相关部分
想要多阶段交互流程,可在运行
/init前设置环境变量CLAUDE_CODE_NEW_INIT=1:它会询问要生成 CLAUDE.md、skills 还是 hooks,再给出可审阅的方案。
步骤 2:把规矩写成可验证的指令
打开生成的 CLAUDE.md(或用会话命令 /memory 选中项目 CLAUDE.md 在编辑器中打开),整理成下面这样。官方建议:每个文件少于 200 行,用标题和列表分组,指令要具体到可验证。
# kun-claude-demo
## Commands
- Run tests: `python3 test_calc.py` (prints `ok` on success)
## Conventions
- Use 4-space indentation and type hints on public functions
- Raise `ValueError` for invalid input; never return `None` silently
- Run the tests before every commit
## Layout
- Library code lives in `calc.py`; tests live in `test_calc.py`
官方给出的写法对比,可直接套用:
| 含糊(效果差) | 具体(效果好) |
|---|---|
| Format code properly | Use 2-space indentation |
| Test your changes | Run npm test before committing |
| Keep files organized | API handlers live in src/api/handlers/ |
文件放哪里
| 范围 | 位置 | 是否进版本库 |
|---|---|---|
| 个人(所有项目) | ~/.claude/CLAUDE.md | 否,仅你自己 |
| 项目(团队共享) | ./CLAUDE.md 或 ./.claude/CLAUDE.md | 是 |
| 项目(仅本人) | ./CLAUDE.local.md | 否,加入 .gitignore |
启动时会加载当前目录及所有上级目录中的 CLAUDE.md 与 CLAUDE.local.md,并按「从根目录到当前目录」的顺序拼接;子目录中的文件在 Claude 读取该目录文件时才按需加载。
用 @ 导入其他文件
CLAUDE.md 里可以用 @路径 导入文件,导入内容在启动时一并加载(最多递归 4 层):
See @README.md for project overview.
# Additional Instructions
- git workflow @docs/git-instructions.md
注意:导入只帮助组织内容,不会减少上下文占用。若只是想提到一个路径而不导入,把它写成行内代码(用反引号包起来)即可。
步骤 3:确认 CLAUDE.md 已生效
退出后重新启动会话(/exit,再执行 claude),输入:
/context
对照结果:在 Memory files 列表中看到 ~/kun-claude-demo/CLAUDE.md。然后做一次行为验证:
add a multiply(a, b) function and commit it
对照结果:新函数带类型标注;Claude 在提交前先运行 python3 test_calc.py。这两点都来自你写进 CLAUDE.md 的规矩。
已经在用
AGENTS.md的仓库:v2.1.277 及以上,若目录链上没有任何CLAUDE.md,Claude 会直接读取AGENTS.md;两者都有时默认只读CLAUDE.md。想共用一份,可在CLAUDE.md首行写@AGENTS.md。
查看自动记忆
当你在会话里说「always use pnpm, not npm」这类偏好时,Claude 会写入自动记忆,位置在 ~/.claude/projects/<project>/memory/,索引文件是 MEMORY.md。用 /memory 可浏览这些文件、打开记忆文件夹或开关自动记忆。要写进 CLAUDE.md 而不是自动记忆,直接说「add this to CLAUDE.md」。
步骤 4:用 claude -p 一次性提问
-p(--print)让 Claude Code 非交互运行:执行完就退出,成功时退出码为 0,失败为非零,方便脚本判断。
cd ~/kun-claude-demo
claude -p "What does calc.py do? Answer in one sentence."
echo "exit code: $?"
对照结果:终端打印一句对 calc.py 的说明,随后是 exit code: 0。
管道输入与重定向输出
非交互模式会读取 stdin,可以像普通命令行工具一样串联:
python3 -c "import calc; calc.divide(1, 0)" 2> error.txt
cat error.txt | claude -p "concisely explain the root cause of this error" > output.txt
cat output.txt
对照结果:output.txt 中是对 ValueError: b must not be zero 的简短解释(若你在课时 1 已改过 divide)。管道输入上限 10MB,更大的内容请写成文件并在提示中引用路径。
步骤 5:JSON 输出与结构化结果
--output-format 可选 text(默认)、json、stream-json。json 会返回结果、会话 ID 与元数据,文本在 result 字段中。先确认本机有 jq(jq --version),再运行:
claude -p "Summarize this project" --output-format json | jq -r '.result'
对照结果:只打印摘要文字。JSON 中还带有 session_id 与 total_cost_usd(客户端估算,可能与账单不同)。
需要固定结构时,加 --json-schema,结果放在 structured_output 字段:
SCHEMA='{"type":"object","properties":{"functions":{"type":"array",
"items":{"type":"string"}}},"required":["functions"]}'
claude -p "List the function names defined in calc.py" \
--output-format json --json-schema "$SCHEMA" | jq '.structured_output'
对照结果(函数顺序以实际输出为准):
{
"functions": ["add", "divide", "multiply"]
}
步骤 6:预先授权工具,让脚本不被卡住
非交互运行时没人点「允许」,需要用 --allowedTools 预先放行,语法与权限规则一致:
claude -p "Run python3 test_calc.py and fix any failures" \
--allowedTools "Bash(python3 *),Read,Edit"
Bash(python3 *) 中 * 前的空格表示前缀匹配:允许所有以 python3 开头的命令。官方特别提醒:没有空格时,Bash(git diff*) 也会匹配 git diff-index。
也可以直接指定整次运行的权限模式:
| 写法 | 效果 |
|---|---|
--permission-mode acceptEdits | 可直接写文件,其他命令仍需放行 |
--permission-mode dontAsk | 凡是需要询问的一律拒绝,适合锁死的 CI |
--permission-mode auto | 由分类器审核每个操作 |
示例:让它直接改文件补注释,而不放行其他命令。
claude -p "Add a one-line docstring to every function in calc.py" \
--permission-mode acceptEdits
对照结果:calc.py 中每个函数都多了一行 docstring,git diff 可见改动。
步骤 7:续接对话
claude -p "Review calc.py for edge cases"
claude -p "Now focus on divide()" --continue
第二条带 --continue,会接着最近一次对话继续。并行跑多个对话时,用会话 ID 精确续接:
sid=$(claude -p "Start a review of calc.py" --output-format json | jq -r '.session_id')
claude -p "Continue that review" --resume "$sid"
对照结果:第二条回复明确引用上一轮的审查内容,而不是从头开始。
步骤 8(CI 推荐):--bare 模式
--bare 会跳过 hooks、skills、插件、MCP 服务器、自动记忆和 CLAUDE.md 的自动发现,让每台机器上的结果一致,官方推荐在脚本与 CI 中使用。注意:bare 模式不读取订阅登录凭据,需要设置 Claude Console 创建的 ANTHROPIC_API_KEY:
export ANTHROPIC_API_KEY="sk-ant-..." # 换成你自己的 Key,勿提交到仓库
claude --bare -p "Summarize README.md" --allowedTools "Read"
对照结果:快速返回 README 摘要;因为跳过了 CLAUDE.md,回答不会体现你在步骤 2 写的项目规矩。需要额外上下文时,用 --append-system-prompt、--settings、--mcp-config 等参数显式传入。
本课检查清单
-
/context的 Memory files 中能看到项目CLAUDE.md - Claude 的新改动遵守了你写的规矩(类型标注、提交前跑测试)
-
claude -p ... --output-format json | jq -r '.result'只输出文本 - 能用
--allowedTools让脚本无人值守地跑完
常见问题
| 现象 | 处理 |
|---|---|
| Claude 不遵守 CLAUDE.md | 用 /context 确认已加载;把指令改具体;排查多个文件互相矛盾 |
CLAUDE.md 太长 | 控制在 200 行内;只对部分文件生效的规则移到 .claude/rules/ |
-p 运行卡在权限 | 用 --allowedTools 放行,或指定 --permission-mode |
--bare 报未认证 | bare 不用订阅登录,需设置 ANTHROPIC_API_KEY |
--json-schema 报错 | 检查 Schema 是合法 JSON Schema,引号是否被 shell 吃掉 |
延伸阅读:官方 Best practices 与 CLI reference。
