用过 Claude Code 的朋友应该都有过这种体验同一个项目开了十几个会话每次新开会话都要把项目背景、技术栈、代码规范重新交代一遍稍微少说两句AI 给出的方案就跑偏。一开始我以为是自己提示词写得不好后来把它的自动化体系完整摸了一遍才发现问题根本不在提示词而在于我没有把“上下文”分层打理。这篇文章就围绕 Claude Code 的自动化体系展开重点拆解三层记忆机制与 Hook 事件驱动这两块核心设计以及它们组合起来能跑出什么效果。适合两类人看一类是已经用 Claude Code 写代码、但每次都要重复交代背景的开发者另一类是准备把 AI 编程助手接入现有工作流希望它能自动做格式化、跑测试、发通知的人。看完你会明白一个核心结论Claude Code 的上下文不应该只靠临时对话窗口而应当分成会话内、项目内、用户全局三层同时它的 Hook 机制能让你在 AI 工作流的每个关键节点插入自定义脚本把 AI 变成自动化流水线上的一环而不是一个“用完即走”的问答题工具。1. 为什么记忆要拆成三层1.1 会话上下文只是一次性窗口很多人默认 Claude Code 和聊天机器人一样上下文存在肚子里过几天再打开还能记得。实际用过的都知道它的每个会话都是一段独立上下文虽然系统会在上下文接近上限时自动做压缩摘要auto-compact但压缩是有损的——它丢掉的大多是细节比如你之前明确说过的“这个模块不要动”“测试要用 mock 数据”“构建工具是 pnpm 而不是 npm”。这些细节在压缩摘要里往往只剩一句“项目使用 pnpm 构建”但“为什么不用 npm”“哪些脚本对 npm 有依赖”这类决策信息全丢了。我最早犯的错就是把会话上下文当成唯一记忆。某次在模拟项目里让它重构一个工具函数结果它按照另一个模块的旧约定写了代码我气得够呛回看才发现那个旧的约定只存在于三天前某个会话里而当前会话完全没有相关信息。会话上下文适合当“工作记忆”用——就像程序员桌面上的即时贴写的是此刻正在做的事做完就该清掉。你真正需要的是能跨会话、跨项目的持久记忆这就引出了后面的层级设计。1.2 项目级上下文为什么容易丢还有一个容易被忽略的现状Claude Code 默认会读取项目根目录的说明文件比如 CLAUDE.md作为启动上下文但很多人的项目里根本没有这份文件或者写了但只写了两行废话。没有结构化的项目级记忆AI 每次都要靠你现场补充信息而且补充的信息是零散的、随口的没有沉淀下来下一个会话又得重新说。在我做过的一个某跨平台系统项目里前后端代码在同一仓库技术栈涉及两种不同的构建链。前期我习惯在提示词里手写“当前改的是前端模块用的构建命令是 xxx”结果几个会话一多AI 把前后端命令混在一起执行了完全错误的构建步骤。后来我意识到缺的不是提示词而是一份能被自动加载、始终在线的项目级记忆文件。项目级记忆不是写文档给同事看是写给 AI 看的运行配置。它应该包含项目目标、技术栈、目录结构、常用命令、编码约定、当前任务状态。这层记忆一旦建立你会明显感觉到 AI 的“进入状态”速度快了一大截。1.3 全局记忆负责回答“你是什么风格的人”第三层是用户级全局记忆这个层级管的是跨项目的通用偏好和行为习惯。比如你写代码习惯两空格缩进、喜欢接口返回结构用统一包装、讨厌冗长的注释、希望 AI 默认用中文回复、提交信息必须按特定格式写。这些偏好与单一项目无关却决定了 AI 输出是否“顺手”。全局记忆的本质是把你的长期偏好从“每次教”变成“自动懂”。没有它你换了项目、换了机器AI 又变成陌生人。装了它哪怕你只是在空目录里写一段练习代码AI 也会按照你习惯的方式组织输出。这三层的关系可以这么理解会话记忆是工作台桌面项目记忆是项目档案柜全局记忆是你的个人操作手册。只有三者在每个会话里协同工作Claude Code 输出的质量才谈得上稳定。2. 三层记忆的配置与实现2.1 第一层会话内压缩记忆的正确用法会话内记忆不是让你写配置而是靠操作来维护。它由 Claude Code 自动管理但你可以主动干预重点有两个操作第一个是/compact命令。当对话变长、上下文快撑满时你可以主动执行压缩让 AI 把当前对话总结成精炼摘要。关键点在于压缩前你最好先手动指示一次方向比如先输入一句“请把当前任务的进度、已完成改动、未完成事项、下一步计划整理成结构化摘要再执行 compact”。这样 AI 会按照你的框架来总结而不是自由发挥丢掉的细节会少很多。第二个是--resume或/resume。重新打开会话时用这个操作恢复之前的工作现场。我习惯恢复后先问一句“根据当前上下文记忆我们现在进行到哪了下一步是什么”而不是直接让它干活。这一句的用意是让 AI 把被压缩的记忆重新“调取”到显式上下文里后续指令才能建立在准确的前提之上。实测经验是会话内记忆适合任务跨度在几小时到一两天的短中期工作超过这个周期的任务光靠压缩摘要远远不够。别心疼一条会话有多长关键在于收尾时你有没有把状态写进项目级记忆文件否则压缩再多都只是临时便签。2.2 第二层项目级记忆文件的结构设计项目级记忆在 Claude Code 中的落点通常是项目根目录下的说明文件默认会作为启动上下文的一部分被读入。这个文件完全可以主动设计结构我的推荐模板是这样的# 项目档案 ## 项目目标 一句话说明项目解决什么问题。 ## 技术栈与版本 - 前端 / 后端 / 其他组件的技术选型 - 关键依赖版本、包管理器版本 - 本地环境变量清单不含密钥值 ## 目录结构 - src 下各模块职责 - 脚本、配置、文档的存放位置 - 哪些目录不要动 ## 常用命令 - 启动 / 测试 / 构建 / 代码检查命令 - 特殊场景命令如单测某个文件、清缓存 ## 编码约定 - 命名风格、组件 / 模块划分原则 - 注释规范、提交信息格式 - 特别强调的“不要做”事项 ## 当前任务状态 - 正在进行模块 A 的重构 - 已完成模块 B 的接口调整 - 下一步合并 PR 前先跑完整回归 - 已知问题构建机偶发内存不足这里有个很重要的原则这个文件不是写文档是给 AI 吃的“上下文种子”。所以语言要精炼重点要突出。不要把文档管理的内容全塞进去AI 读入上下文是有长度限制的一个又长又臭的档案反而稀释了真正重要的信息。写文件的时候我总是保持“一个屏幕能看完”的篇幅大概三四十行。每周末我会花十分钟更新“当前任务状态”这一节把本周完成、下周计划刷一遍。这个小习惯带来的收益超乎想象——每次新开会话AI 对进度的理解比我的同事还准确。2.3 第三层用户级全局配置的优先级与边界全局配置一般存放在用户主目录下的 .claude 配置目录里它和项目级文件是叠加生效的全局内容提供通用偏好项目内容提供局部事实。两者冲突时项目级优先级更高——因为项目档案描述的是当前仓库的具体情况理应覆盖通用假设。我维护全局配置的内容主要有四类输出偏好回复语言、代码注释风格、是否默认给出完整示例通用工作流比如“改完代码先自测再提交”“接口文档必须同步更新”术语表行业专有名词的固定译法、缩写含义工具偏好优先使用哪些命令行工具、输出格式要求这里提醒一句边界全局配置不要写太具体的项目信息否则你换项目时这些信息会变成噪音甚至误导 AI。比如你在全局里写了“当前项目用 pnpm”到了另一个 npm 项目AI 可能会莫名其妙执行 pnpm 命令。我自己维护的全局配置非常克制总共二十行左右只写“无论哪个项目都成立”的偏好。项目相关的全部扔进项目级文件两层的边界清晰了AI 才知道该以哪份为准。3. Hook 事件驱动的核心机制3.1 Hook 是什么解决什么问题Hook 是 Claude Code 在工作流的关键节点上向外暴露的事件切入点。简单说你可以在这些节点挂上自定义脚本让外部程序在特定时机被自动执行。它解决的是 Claude Code 的“封闭问题”AI 本身只负责思考、生成、调用工具但它对代码风格、测试门禁、通知提醒这些外部约束一无所知。没有 HookAI 的行为完全取决于提示词有了 Hook你可以在 AI 做任何重要动作之前或之后强制插入自己的检查、校验、记录和通知。我用一个类比来理解提示词像你给实习生的口头嘱咐Hook 则像公司里的门禁系统——你不需要每天提醒实习生进门前刷卡门禁本身就强制了这一行为。AI 也一样它再“聪明”也必须在你的门禁规则里运行。我实际用下来最明显的感受是Hook 让 Claude Code 从一个“个性很强的写码工具”变成了“流程的一部分”。比如代码改完自动格式化、提交前自动跑测试、出错自动通知这些事情以前靠我盯现在靠体系盯省心非常明显。3.2 核心事件类型与触发点Claude Code 的 Hook 事件围绕 AI 的工作循环展开核心事件大致能分成五类每一类负责一个时机事件触发时机典型应用场景UserPromptSubmit用户提交提示之后、AI 处理之前自动补充上下文、注入 git 状态、检查语句PreToolUseAI 准备调用某个工具之前安全检查、参数校验、拦截危险命令PostToolUse工具执行完成之后结果校验、自动格式化、发通知、记录日志StopAI 完成一段输出之后流程收尾、自动测试、整体通知Notification需要触发异步通知时推送结果到聊天群、发送邮件、上报监控每个事件都可以绑定一个或多个脚本脚本以命令行方式被执行。执行是同步的在脚本执行完成前AI 会等待对应的流程节点。这一点极其重要它意味着你可以用 Hook 做“硬门禁”而不是“事后广播”。打个比方假设你的项目要求所有代码改动都必须经过 lint那你就可以在 PostToolUse 事件上挂一个 lint 脚本。AI 每次写完文件lint 脚本先跑如果失败就通过 stderr 返回错误信息AI 会看到这个反馈并继续修正。这个循环直到 lint 通过才结束自动化程度非常高。3.3 Hook 配置文件的写法与匹配规则Hook 的配置在设置文件里完成一般位于项目 .claude 目录或用户配置目录下的 JSON 文件。结构大概是这样的{ hooks: { PreToolUse: [ { matcher: Write|Edit|MultiEdit, hooks: [ { type: command, command: sh .claude/hooks/pre-tool-check.sh \$\, timeout: 30 } ] } ], PostToolUse: [ { matcher: Write|Edit|MultiEdit, hooks: [ { type: command, command: sh .claude/hooks/post-tool-check.sh } ] } ], Stop: [ { hooks: [ { type: command, command: sh .claude/hooks/on-stop.sh } ] } ] } }这里的matcher是正则用来匹配具体的工具名称。比如Write、Edit、MultiEdit是文件操作类工具Bash是执行命令类工具。匹配规则很关键——你不想每次 AI 调用任何工具都触发脚本那样开销太大也不必要。写 matcher 时要注意正则语法我踩过坑写成Write|Edit时没发现问题后来改成^(Write|Edit)$反而更精准细节差很多。command字段就是实际执行的命令行。脚本能从标准输入读取事件相关的 JSON 信息比如工具名、参数、时间戳也可以从环境变量拿上下文。脚本的标准输出会被 Claude Code 捕获按规则处理有的输出会被当作辅助信息反馈给 AI有的错误信息通过 stderr 传给 AI 作为修正依据。3.4 事件驱动能解决的真实场景Hook 的价值不在于单个脚本而在于能组合成完整的事件驱动流程。我挑三个最常用的场景展开场景一自动代码门禁。在 Write / Edit 工具执行后触发 PostToolUse 脚本该脚本运行代码检查器和格式化工具。如果检查不通过脚本以非零退出码结束并把错误信息写入 stderrAI 会收到错误内容并自我修正。这个场景除了省去人工提醒还能保证代码风格在 AI 手里不跑偏这个意义非常现实。场景二动态注入 git 上下文。在 UserPromptSubmit 事件里挂一个脚本自动把当前 git 分支、最近提交、工作区改动情况打印出来作为提示的一部分喂给 AI。这比你在提示词里手打“现在在 main 分支”准确一万倍而且永远不会忘记更新。AI 只要每次看到 git 状态就知道它应该基于哪个版本的代码做修改这个上下文价值非常大。场景三异常异步通知。在 Stop 事件里挂一个脚本AI 每次完整输出后脚本检查输出内容有没有“失败”“错误”等关键信息有就通过 webhook 推到内部聊天工具。这样你不需要盯着终端等结果AI 遇到搞不定的问题时会主动“喊你”。托管在后台跑批处理时这种 Hook 几乎是刚需。这三个场景单独看都不是惊天动地的大功能但合在一起你会发现 Claude Code 从“你盯它”变成“它配合体系自动运转”。我认为这才是 Hook 最值得琢磨的地方。4. 实战搭建一套可复用的自动化工作流4.1 从记忆到 Hook 的联动设计记忆和 Hook 不是两条独立的技术线而是同一个自动化体系的正反面。记忆层解决“AI 知道自己在哪、要干什么”Hook 层解决“AI 的行为能被外部系统约束和放大”。前者是输入质量的基础后者是输出可靠性的保障。我搭建自动化工作流的标准套路是三步第一步建立记忆文件。先把项目档案写清楚包括技术栈、命令、约定、当前状态再把全局偏好配置好。这一步解决“AI 的基础认知问题”。第二步设计关键 Hook 节点。确定你希望自动化的环节比如代码检查、格式化、测试、通知。把每个环节对应到具体事件写文件用 PostToolUse提交前检查用 Stop通知用 Notification。第三步串联成闭环。确保每个 Hook 脚本的退出结果能反馈给 AI而不是“脚本自己跑完就完了”。让 AI 在每次操作后都能看到检查结果并根据结果自动修正这才是自动化循环的完整形态。我在某跨平台系统项目里应用的是“记忆 三 Hook”的组合项目记忆提供构建命令和模块边界UserPromptSubmit Hook 注入 git 状态PostToolUse Hook 自动格式化Stop Hook 跑完整回归测试。这个工作流跑了一个多月状态非常稳定。4.2 一个完整的自动化巡检示例为了让你能直接上手我给一个完整的巡检脚本示例。假设你有一个长期维护的模拟项目每天都要检查有没有未提交代码、测试是否通过、有没有遗留的 TODO。先写巡检脚本本体存为.claude/hooks/health-check.sh#!/usr/bin/env bash # 自动化巡检脚本检查工作区、跑测试、汇总 TODO set -euo pipefail cd $(git rev-parse --show-toplevel) echo 巡检开始: $(date) # 1. 检查未提交代码 if [[ -n $(git status --porcelain) ]]; then echo [WARN] 工作区存在未提交改动: git status --short else echo [OK] 工作区干净 fi # 2. 扫描 TODO / FIXME echo TODO/FIXME 扫描 grep -rn TODO\|FIXME --include*.js --include*.ts --include*.py src/ || true # 3. 跑测试 echo 自动化测试 if [[ -f package.json ]]; then npm test -- --reporterminimal || echo [FAIL] 测试未通过 else echo [SKIP] 未识别到测试框架 fi echo 巡检结束: $(date) 这个脚本完全不依赖 Claude Code 的特殊接口纯 bash 就能跑。接着把它绑定到 Stop 事件在配置文件的 hooks 节里加Stop: [ { hooks: [ { type: command, command: bash .claude/hooks/health-check.sh } ] } ]效果就是AI 每完成一轮输出脚本自动执行一次巡检结果直接显示在终端里。如果测试挂了AI 会在下一轮对话里看到失败信息继续修复直到通过。实测中这个闭环让“AI 改代码导致测试变红”的情况从必须人工发现变成了 AI 自己就会接着改。4.3 权限边界与执行安全Hook 脚本和 AI 是同一个工作环境这意味着它有足够的能力改动文件、执行命令。能力越大越要限制我给自己定了几个规矩第一Hook 脚本默认只做“检查 报告”不主动删除或覆盖用户文件。像格式化这类修改操作也只在明确的文件范围里进行加上set -euo pipefail防止中途静默失败。第二脚本里不要直接拼接用户或 AI 生成的输入作为命令参数。Hook 拿到的 JSON 信息里包含工具参数这些参数可能来自用户提示词如果你直接拼进 shell 命令存在注入风险。我的做法是只读取、不做复杂拼接或者用脚本语言解析 JSON 后再安全传参。第三给每个 Hook 设置超时。在配置的timeout字段里指定上限比如 30 秒。脚本卡死了Hook 会超时失败AI 继续流程而不是无限等待。一个卡住的巡检脚本比不巡检还麻烦这个坑我踩过一次之后就老老实实加超时了。5. 常见问题与排查技巧5.1 Hook 不触发到底为什么Hook 最让人头疼的问题就是“我明明配了它就是不触发”。我整理过一张自查表按概率从高到低排查现象可能原因解决方式完全不触发配置文件路径不对或 JSON 格式错误检查当前工作目录下配置是否生效用claude --version环境核对matcher 没匹配上正则写错比如事件对象名不匹配在脚本里先打印$STDIN内容确认真实工具名脚本执行失败但没反馈忽略了退出码和 stderr在命令末尾把 stderr 重定向到日志文件落盘排查事件匹配了但顺序不对多个 Hook 脚本同时执行顺序不符预期给脚本内部用时间戳文件打点核对执行时序其中最隐蔽的坑是 matcher 的正则匹配。我曾写matcher: Write想匹配所有文件写入操作结果只有一部分触发。从标准输入把事件 JSON 打印出来才发现工具名有时是Write有时是MultiEdit还有可能在前面带了命名空间前缀。现在我都用Write|Edit|MultiEdit这种显式枚举不再指望模糊匹配。5.2 记忆文件失效或冲突怎么办记忆系统看着简单其实有几个容易踩的坑第一个是“改了 CLAUDE.mdAI 还按旧记忆走”。原因是 Claude Code 只在会话启动时读取记忆文件运行过程中改文件当前会话不一定重新加载。解决方式很简单改完文件后新开一个会话或者执行一次上下文重建命令。我养成了习惯每次改完项目档案都顺手/clear重开一个会话。第二个是全局记忆和项目记忆打架。比如全局配置写了“统一用 npm”项目档案写的是“这个仓库必须用 pnpm”AI 可能按全局偏好行事。优先级上项目记忆高于全局记忆但为了减少歧义项目档案里最好明确写出“即使全局有其他配置本项目一律使用 pnpm”这类强声明。第三个是文件太长被截断。记忆文件本身消耗上下文空间太长会让真正的会话空间变小甚至触发截断。我见过有人把整个 README 塞进去结果 AI 答非所问。解决办法是把记忆文件控制在关键信息的精炼描述上详细信息拆到单独文档需要时让 AI 再去读。5.3 稳定性与性能踩坑记录跑自动化体系最怕的不是功能不实现而是平时好好的某一天突然全线崩溃。几个稳定性的点值得单独说Hook 脚本必须幂等也就是重复执行结果一致。我早期写巡检脚本时用了追加模式写日志每次 AI 想重试脚本就重复追加一段日志文件膨胀得飞快。后来全部改成覆盖写或者按时间戳分文件杜绝了累加污染。脚本里的临时文件要处理好。有些脚本依赖环境变量或者当前工作目录如果 AI 可能在任意目录下启动脚本里必须显式cd到项目根目录否则路径一错直接全挂。最后是超时和重试的权衡。超时设太短大项目测试脚本跑不完设太长AI 卡住半天没反应。我的经验是按脚本实际耗时乘以 3 倍设超时并且利用返回值区分“正常失败”退出码非零和“超时中断”在日志里打不同标记排查起来方便很多。这些稳定性问题不致命但会消耗大量时间排查提前把这些注意事项写进自己的脚本模板能省下无数个挠头的晚上。我在实际搭建这套体系时体会最深的一点是记忆机制解决的是“AI 知道自己在哪”Hook 机制解决的是“AI 的行为能被约束和放大”。如果只配记忆不配 Hook遇到需要外部协作的环节还是得靠人肉盯如果只配 Hook 不配记忆AI 大概率会在错误前提下执行正确的动作最后结果一样走偏。两条腿都搭起来Claude Code 才真正从“工具”变成了“自动化流水线”。最近我还在试着把 Notification 事件接到内部聊天机器人上让每次巡检结果主动推送出来而不是我守在终端前看。等这套跑稳定了我会再单独写一篇具体实现。