| name | session-memory |
|---|---|
| description | 为 AI agent 保存和恢复高价值会话记忆。适用于会话过长、准备结束当前会话、准备在新会话中接续同一项目,或需要保留决策、思路变化、已完成工作、研究结论、失败路线、约束和下一步,而不携带完整聊天记录的场景。 |
这不是聊天摘要工具,而是一套“高价值会话记忆”机制。目标是只保留跨会话真正有用的状态,让新会话能快速恢复上下文,并支持轻量检索、保存闸门、后台 sleep/dream 复盘。
- 这个仓库可直接作为本地 agent skill 使用;存储根目录默认是
${SESSION_MEMORY_HOME:-$HOME/.session-memory}。 - 仓库不应提交运行时产物,例如
__pycache__/、.DS_Store、日志文件,以及项目内.session-memory/、.codex/、.claude/数据。 - 对外分发时,优先把行为约定写在
SKILL.md,把安装、贡献和许可证写在README.md、CONTRIBUTING.md、LICENSE。 - 不同 agent 平台可以复用
scripts/和references/,再按目标平台调整 skill 元数据和入口描述。
- 用户说当前会话太长,context 太臃肿。
- 用户想在新会话中继续同一项工作。
- 用户想保留决策、研究结果、失败尝试和下一步。
- 一个任务存在明显的思路演化,需要记录“为什么变了”。
- 结束或归档会话前,需要留下可恢复的状态。
- 同时进行多个项目,必须避免项目间记忆串线。
用户主入口只保留三个,中英文别名等价:
session-memory 保存/session-memory save:内部应拆成prepare -> 编辑文件 -> commit三步,不再是假定一次命令就完成保存。session-memory 恢复/session-memory restore:恢复当前项目的记忆,先读current.md,必要时再读history.md,并且只在有未消费 dream 时才读取dream-notes.md。session-memory 搜索 <关键词>/session-memory search <keyword>:在当前项目的记忆中查旧结论、旧路径、旧决策。
辅助入口不占用户主心智:
session-memory 研究保存/session-memory research-save:把未并入主线的研究阶段性追加到当前命中记忆空间的research.md,不覆盖current.md。session-memory 检查/session-memory check:agent 的 save gate(保存闸门),判断现在是否到了应该保存的时机;通常不要求用户手动使用。
对应脚本入口:
- 保存准备/提交:
scripts/save_session_memory.py --stage prepare|commit - 研究保存准备/提交:
scripts/research_save_session_memory.py --stage prepare|commit - 恢复:
scripts/restore_session_memory.py - 搜索:
scripts/search_session_memory.py,默认只查热层;明确要求查研究时再加--include-research,明确要求查当前记忆空间的冷层归档时再加--include-archive - 检查:
scripts/checkpoint_session_memory.py - 归档:
scripts/archive_session_memory.py
如果项目记忆文件还不存在,保存 / save 和 研究保存 / research-save 的 prepare 阶段都应先初始化。
默认使用中文记录。只有代码、命令、路径、API 名、库名、固定技术标识等内容保留原文。
默认优先使用项目级记忆,避免不同项目互相污染。
--scope auto 的解析规则是:
- 如果当前在 Git 仓库里,默认使用
<git-root>/.session-memory/ - 如果不在 Git 仓库里,但某个祖先目录已经存在
.session-memory/,默认继续复用那一层共享项目记忆 - 如果上述共享根都不存在,才退回当前目录自己的
.session-memory/
默认共享层的核心文件是:
<project-root>/.session-memory/current.md:当前最新状态,作为最小恢复入口<project-root>/.session-memory/history.md:追加式历史,保留关键变化,以及已经过去但不能丢的旧current.md内容<project-root>/.session-memory/research.md:研究流水账,面向同项目多个工作上下文的追加式研究记录
默认恢复入口只看 current.md、history.md、dream-notes.md。research.md 是研究层,不进入默认恢复/检索热路径,只有用户明确要求“查研究”“恢复某条研究上下文”时才读取。
如果同一项目里需要多套互不覆盖的研究记忆,在项目根创建 .session-memory/config.toml:
[spaces]
"路线A" = "current-research"
"路线B" = "legacy-research"也兼容最简顶层写法,例如 "路线A" = "current-research"。
路由规则:
- key 是记忆空间名,value 是相对项目根的子目录
- 当前工作目录命中某个子目录时,目标记忆会切到
<子目录>/.session-memory/ - 多条路径重叠时,按最长匹配优先
- 不会自动混读项目共享层和其他记忆空间
保存 / 研究保存 / 恢复 / 搜索 / 做梦 / 归档都只作用于当前命中的那一层记忆空间
只有在明确处理“个人跨项目主题”时,才使用全局记忆。
正常读写只使用 agent-neutral(智能体中立)的新路径:
- 项目级:
<project>/.session-memory/ - 全局级:
${SESSION_MEMORY_HOME:-$HOME/.session-memory}/
如果发现旧路径里已有记忆,脚本会先迁移到新路径,再继续当前动作:
- 项目级旧路径:
<project>/.codex/session-memory/、<project>/.claude/session-memory/ - 全局级旧路径:
${CODEX_HOME:-$HOME/.codex}/session-memory/、${CLAUDE_HOME:-$HOME/.claude}/session-memory/
迁移会把旧目录内容搬进新目录,然后删除旧的 session-memory 目录。项目内 .codex/ 或 .claude/ 如果因此变空,也会一并清理;如果还有其他内容则保留。重名冲突不会覆盖新文件,旧文件会放到 .session-memory/archive/legacy-imports/。
除了项目内的 current.md/history.md,这个 skill 还使用全局索引层。它是隐性维护层,不是用户主入口:
${SESSION_MEMORY_HOME:-$HOME/.session-memory}/registry.json:记录已接触项目的位置和时间戳${SESSION_MEMORY_HOME:-$HOME/.session-memory}/state.json:记录全局 sleep check / sleep 时间${SESSION_MEMORY_HOME:-$HOME/.session-memory}/sleep.lock:防止同时触发多个后台 dream${SESSION_MEMORY_HOME:-$HOME/.session-memory}/dreams/:保存每次 dream 的全局快照
每次执行 恢复/搜索/检查 时,都要先做统一前置钩子。保存 因为会先修改文件,所以改成两阶段:
save --stage prepare:先定位并确保记忆文件存在- 先把已经过去但仍有价值的内容追加到
history.md,再把current.md重写成当前最小恢复快照 save --stage commit:提交本次保存动作,登记项目并触发sleep check
也就是说:
恢复/搜索/检查:进入主动作前先跑前置钩子保存:只有commit阶段才登记项目活动并触发sleep check
统一前置钩子内容:
- 登记当前项目到全局
registry - 更新当前项目的
last_seen_at - 只有
save --stage commit才更新当前项目的last_active_at - 检查距离上次
sleep check是否超过 5 小时 - 若超过,再判断是否存在需要 dream 的项目
- 若需要且当前没有运行中的 dream,则后台异步启动一次 dream
这样做的原因是:单纯 restore/search/check 不应把项目重新标成“发生了新内容变化”,否则会造成重复 dream 和无意义快照增长。
dream 判定规则:
last_dream_at不存在- 或
last_active_at > last_dream_at
任一满足即表示该项目需要进入本轮 dream。
当用户不是要“完整恢复”,而是只想追问一个具体问题时,优先检索,不要默认整份读取。
适用场景:
为什么之前放弃方案 A之前查过哪个仓库某个命令是否验证过某个路径、接口名、文件名之前记到哪里了
默认命令:
python3 "<skill-root>/scripts/search_session_memory.py" --workspace "$PWD" --scope auto --query "关键词"只有当用户明确要求“查归档”时,才追加:
python3 "<skill-root>/scripts/search_session_memory.py" --workspace "$PWD" --scope auto --query "关键词" --include-archive--include-archive 只查当前命中记忆空间里的 archive/history-archive.md 和 archive/research-archive.md,不默认跨项目扫描全局 dream 快照。
只有当用户明确要求“查研究”时,才追加:
python3 "<skill-root>/scripts/search_session_memory.py" --workspace "$PWD" --scope auto --query "关键词" --include-research检索命中后:
- 先简短复述命中点。
- 只有当命中结果不足以支持当前任务时,再读取
current.md或history.md。 - 不要把整份记忆文件一次性倒给用户。
默认初始化到项目根目录或当前工作目录:
python3 "<skill-root>/scripts/init_session_memory.py"显式按当前目录自动判断项目范围:
python3 "<skill-root>/scripts/init_session_memory.py" --workspace "$PWD" --scope auto显式初始化全局记忆:
python3 "<skill-root>/scripts/init_session_memory.py" --scope global检查 是 agent 内部的 save gate(保存闸门),不是要求用户手动多走一步。它只回答“现在值不值得保存”。
在以下时刻,agent 应该主动检查是否需要保存,而不是等用户提醒:
- 主目标变化
- 主方案变化
- 研究结论从“不确定”变成“已确认”
- 一个关键阻塞被清掉
- 下一步优先级变化
- 一个阶段性任务完成
- 会话准备结束
默认检查命令只输出结论、原因和下一步:
python3 "<skill-root>/scripts/checkpoint_session_memory.py" --workspace "$PWD" --scope auto排障时才使用详细输出:
python3 "<skill-root>/scripts/checkpoint_session_memory.py" --workspace "$PWD" --scope auto --verbose如果已知触发原因,带上 --event:
python3 "<skill-root>/scripts/checkpoint_session_memory.py" --workspace "$PWD" --scope auto --event approach-changed --event research-confirmed事件枚举:
goal-changedapproach-changedresearch-confirmedblocker-clearednext-step-changedtask-completedsession-ending
处理规则只看三种结果:
decision=INIT_FIRST:先初始化,再保存。decision=SAVE_NOW:应主动执行保存,不要等用户再补一句。decision=SKIP:继续当前任务,不必强行记录。
sleep check 不是单独给用户使用的主命令,而是 保存/恢复/搜索/检查 的统一前置动作。
规则:
- 每次进入
sm主动作时都先检查 - 若距离上次
sleep check未超过 5 小时,直接跳过 - 若已超过 5 小时,再看是否存在需要 dream 的项目
- 若需要,则后台启动一次
scripts/dream_session_memory.py - 同一时刻只允许一个 dream 运行,靠
sleep.lock防重入
这个机制的目标不是“每次都做梦”,而是“隔一段时间按需做梦”。
每个项目的 dream 结果写到:
<project>/.session-memory/dream-notes.md
全局快照同时写到:
${SESSION_MEMORY_HOME:-$HOME/.session-memory}/dreams/
这里要区分三层:
<project>/.session-memory/dream-notes.md是覆盖式文件,每次 dream 会重写最新提炼稿,不会无限追加。<project>/.session-memory/history.md是追加式文件,会随着关键变化持续变长。<project>/.session-memory/research.md是追加式研究层,会在 dream 提炼时参与归纳,但不进入默认恢复入口。${SESSION_MEMORY_HOME:-$HOME/.session-memory}/dreams/会按每次成功 dream 的快照数量持续增加,但会在后续 dream 成功后做冷层归档。<project>/.session-memory/archive/与${SESSION_MEMORY_HOME:-$HOME/.session-memory}/archive/是冷层,只做兜底保留,不进入默认恢复/检索路径。<project>/.session-memory/current.md与dream-notes.md头部会写Last Updated,用于判断当前记忆是否过久。
dream-notes.md 不是 current.md/history.md 的复制,而是项目提炼稿,只保留以后还能直接指导判断的内容:
正确轨迹:最多 3 条,只记被证明有效的做法和路径错误与错因:最多 3 条,优先写成错误 -> 规避动作,不要只写事故现象判断准则:最多 3 条,只记以后遇到类似问题该怎么判断预警信号:最多 3 条,只记哪些信号说明项目又在偏航或重踩旧坑
写法要求:
- 只写判断句,不写情绪、铺垫和解释性废话
- 能压成短句就不要写成长句
- 能提炼成规则就不要复述过程
- 没有实质内容的段落不要输出
- 如果提炼不出有效内容,就不要生成新的 dream 产物
归档必须放在 dream 之后,而不是和热层并列长期参与默认读取。也就是说:先提炼,再瘦身。
如果项目已经持续较久,建议归档“旧历史”和“旧快照”,但不要归档当前活跃层:
- 不要归档:
current.md、最新dream-notes.md、活跃项目的registry/state元数据 - 可以归档:
history.md的旧条目、${SESSION_MEMORY_HOME:-$HOME/.session-memory}/dreams/里的旧快照、research.md中已并入主线或已判定无效的旧研究条目
默认命令:
python3 "<skill-root>/scripts/archive_session_memory.py" --workspace "$PWD" --scope auto --dry-run默认行为:
- 只有在存在“新 dream 尚未归档”的前提下,才允许继续做项目历史瘦身
- 保留
history.md最新若干条,把更早的条目移到archive/history-archive.md - 把
research.md中是否并入主线=yes或是否有效=no的研究条目移到archive/research-archive.md - 保留近一段时间的全局 dream 快照,把更老的快照移到
${SESSION_MEMORY_HOME:-$HOME/.session-memory}/archive/dreams/ - 默认
restore/search不读取archive;只有用户明确要求查看当前记忆空间的归档时,才显式带--include-archive
当用户要求继续之前的工作时:
- 先读取项目级
.session-memory/current.md。 - 只有当需要解释“为什么思路变了”时,再读取
.session-memory/history.md。 - 检查当前项目是否存在“未消费的新 dream 产物”:
last_dream_at存在- 且
last_dream_at > last_dream_consumed_at - 且
dream-notes.md存在
- 只有满足上面条件时,才额外读取
dream-notes.md。 - 读取后先检查
current.md/dream-notes.md的Last Updated;如果已经过久,只把它们当弱参考,并优先核对当前代码、目录、分支和真实状态。 - 先向用户简短复述恢复结果,再继续执行任务。复述内容应包括:
- 当前目标
- 当前思路
- 已完成工作
- 有效做法 / 无效做法
- 下一步
- 读取过新的
dream-notes.md后,更新last_dream_consumed_at,避免重复消费。 - 把记忆文件视为恢复依据,而不是去依赖旧聊天记录。
对应脚本的可见信号:
include_dream=yes:本次恢复读入了新的dream-notes.mdinclude_dream=no:本次恢复没有新的 dream 需要消费current_last_updated/current_freshness:主线记忆的新鲜度dream_last_updated/dream_freshness:本次 dream 记忆的新鲜度
如果用户只是问一个局部问题,先走“轻量检索”,不要默认完整恢复。
项目级 AGENTS.md 可以加入一条辅助规则:
- 如果
<project>/.session-memory/dream-notes.md存在,进入项目上下文或恢复时一并读取
但它只作为补充上下文,不应覆盖 current.md 的优先级。
当某个项目第一次成功生成 dream-notes.md 后,dream 流程会自动检查 <project>/AGENTS.md:
- 若不存在,则创建一个最小
AGENTS.md并写入这条读取规则 - 若已存在且尚未包含这条规则,则自动追加到文件末尾
- 若已包含,则不重复写入
- 规则里也会提醒:如果
Last Updated已经过久,记忆只能当弱参考,必要时可以提醒手动执行一次新的session-memory save
在出现有意义的状态变化后更新记忆,尤其是:
- 主方案变化
- 某次实验确认有效或无效
- 发现了重要约束
- 一个阻塞被解决
- 会话即将结束
如果 agent 不确定现在该不该保存,先运行 session-memory 检查 / session-memory check 对应脚本,再决定;不要把这一步变成用户必须记住的手动流程。
执行 session-memory 保存 / session-memory save 时,内部流程应是:
- 先运行
save --stage prepare,定位current.md/history.md,必要时初始化。 - 先归层:仍影响下一步的内容留在
current.md;已经过去但以后要追溯原因的内容追加到history.md;未并入主线的旁路研究写入research.md;工具噪音直接丢弃。 - 先更新
history.md,保住过去但有价值的变化;再重写current.md,让它只保留当前目标、当前思路、当前仍有效结论、关键路径和下一步。 - 编辑完成后运行
save --stage commit;只有current.md的主线内容相对prepare阶段发生变化时,才刷新它头部的Last Updated。随后把本次主线或历史更新登记为项目新活动,并触发sleep check。 - 只记录耐久、可复用的信息,不记录工具噪音、来回讨论、低价值中间输出。
如果当前内容还没有进入主线,不要直接覆盖 current.md,优先改走 研究保存:
- 先运行
research-save --stage prepare,定位research.md,必要时初始化。 - 用
research-save --stage commit追加一条研究记录,至少带上工作上下文 / 研究主题 / 当前结论 / 是否有效 / 是否并入主线 / 下一步。 - 同一工作上下文允许多次
研究保存,每次都只追加,不回写旧条目。 - 只有当某条研究已经成为默认方向时,才把它的最终结果并入
current.md,并把“为什么并入”的变化追加到history.md。
current.md 不再默认放 分支研究 表格,也不承担多阶段研究流水账的职责;详细研究过程默认写入 research.md,已经过去但需要追溯的主线变化默认写入 history.md。
current.md 是当前最小恢复快照,不是第二份项目历史。它必须短到一次读取就能恢复状态;如果某段内容主要回答“之前为什么那样做”,而不是“现在从哪里继续”,就应该移到 history.md。
建议包含以下部分:
当前目标:现在到底要完成什么。当前思路:当前采用的方案,以及为什么采用它。当前仍有效的结论:只保留仍会影响下一步判断的少量结论,默认 3-5 条以内。已完成工作:已经做完、无需重复做的部分,不写普通过程。关键词/标签:便于后续搜索命中。关键文件与路径:便于快速找回上下文落点。有效做法:现在仍应沿用的方案、实验或材料。无效或放弃的做法:现在仍需要避免的路线;详细否定过程放history.md。未决问题:还没解决、但确实影响推进的问题。下一步:新会话接手后应该先做什么。恢复提示:适合直接交给新会话的短提示。
research.md 是研究层,不是主线层。最小版只做追加记录,不承担主线恢复入口职责。
- 每次研究保存只追加一条,不回写主线
current.md - 每条记录至少带:
时间 / 工作上下文 / 研究主题 / 当前结论 / 是否有效 / 是否并入主线 / 下一步 工作上下文用来区分同项目下不同 fork、worktree 或实验副本- 同一
工作上下文允许多次研究保存,每次都视为新的阶段性 checkpoint,不覆盖之前的研究条目 - 研究真正进入主线后,把当前仍有效的结果并入
current.md,把“为什么从旁路变成主线”追加到history.md - 默认
restore/search不读取research.md;只有明确要求查看研究层时,才显式带--include-research
只有在以下三类“真实状态变化”发生时,才追加到 history.md:
思路变化研究结论下一步变化
如果保存时发现 current.md 里有一批已经不是当前入口、但以后仍可能要追溯原因的内容,也要先把它们压成历史条目追加到 history.md,再从 current.md 删除。
不要因为措辞变化、普通执行过程、零散聊天、或短暂工具输出就写历史。
如果更新属于某条分支研究,条目标题建议写成:
### YYYY-MM-DD HH:MM [context: main-local]并补充:
工作上下文:main / main-local / feature-xxx分支研究:这条研究路径的短名研究主题:当前在验证什么研究结果:这次更新确认了什么是否有效:yes / no / partial / unknown是否并入主线:yes / no
指主方案、判断框架或关键假设发生了变化。
应该记录的情况:
- 主路线改了
- 原本偏好的方案被否掉了
- 做判断的依据变了
- 新约束迫使方案变化
不应该记录的情况:
- 只是换了说法,方案没变
- 只是脑暴,没有影响决策
- 只是补充细节,没有改方向
快速判断: 如果新会话需要知道“为什么不再按原方案做”,就应该记录。
指查阅、比较、测试、验证之后,形成了对后续决策有价值的稳定结论。
应该记录的情况:
- 某个工具、库、方案被确认可用或不可用
- 某个原本不确定的问题被证据解决了
- 一次比较得出了明确选择
- 某项检查改变了后续路线
不应该记录的情况:
- 还只是猜测
- 只是原始输出,没有形成结论
- 这个发现对后续选择没有影响
快速判断: 如果这个结论会改变后续选路,就应该记录。
指“接下来先做什么”的优先级、顺序或目标发生了变化。
应该记录的情况:
- 下一项任务变了
- 执行顺序变了
- 优先级变了
- 由于阻塞,下一最佳动作变了
不应该记录的情况:
- 只是很小的操作动作
- 只是“我现在去读一个文件”
- 不会影响新会话如何继续
快速判断: 如果一个新会话接手时会因为这个变化而从不同地方开始,就应该记录。
- 优先写事实、决策和依据,不写空泛叙述。
- 要保留“为什么变了”,不只保留最终结论。
- 涉及关键文件、命令、路径、Issue、提交时,应写进去。
- 已验证和未验证的信息要区分清楚。
- 不要假装确定。
current.md必须足够短,能在一次读取中快速恢复状态。- 搜索友好的关键词要具体,避免只写“这个”“那个方案”。
- 当前状态模板:
references/current-template.md - 历史模板:
references/history-template.md
session-memory 保存session-memory savesession-memory 恢复session-memory restoresession-memory 搜索 stripe webhooksession-memory search stripe webhooksession-memory 恢复,并带上新的 dream-notessession-memory restore with latest dream-notes把这个 local fork 的研究结果增量记下来,但不要覆盖主线记录这条 feature 分支的研究结论,并标明工作上下文是 feature-auth把这次会话里真正有用的东西记下来,后面新开会话能接上。不要总结聊天,帮我记录当前思路、做过什么、哪些路走不通。新会话先恢复之前的关键记忆,再继续做。
使用这个 skill 时,要明确当前是在做哪一类动作:
- 恢复记忆
- 保存记忆
- 初始化记忆文件
- 搜索记忆
- 检查保存时机(agent 内部判断)
如果是在恢复,先给出简短恢复结果,再继续执行用户当前任务。