【免费下载链接】claude-code-memory-setup
Up to 71.5x fewer tokens per session on Claude Code with Obsidian + Graphify. Persistent memory, codebase knowledge graphs, and chat import pipeline. 🇧🇷 PT-BR included.
claude-code-memory-setup是一个把 Claude Code 与 Obsidian、Graphify 结合的开源项目,用持久记忆和代码知识图谱为 Claude Code 提供"第二大脑"。它的scripts/session_autosave.py通过注册SessionEnd Hook,在会话结束时自动把关键信息写入 Obsidian 笔记——全程零 LLM 调用、毫秒级完成、不花一分钱 token。本文带你逐段解读这个 Hook 的实现原理。
为什么需要零 LLM 调用的会话自动保存 Hook?
先理解它要解决的痛点:
| 问题 | 表现 | session_autosave.py 的对策 |
|---|---|---|
| 跨会话失忆 | 每次新会话都要重新解释项目背景 | 会话结束时自动落盘日志,下次/resume可恢复 |
/save靠自觉 | 忘了执行/save,整场会话就消失 | Hook 作为"安全网",兜底记录每个会话 |
| LLM 调用成本高 | 用 LLM 总结会话要消耗 token | 纯 JSONL 解析,零 token、无需 API key |
项目 README.md 中将其定位为"Auto-Save Hook (Safety Net)"——它不是/save的替代品,而是补漏机制:/save产出的是包含决策和待办的"富日志",而自动日志保证被遗忘的会话也留下痕迹。
💡 核心思想:能机械解析的,绝不调 LLM。这是整个脚本最值得关注的设计取向。
项目全景:session_autosave.py 在记忆架构中的位置
claude-code-memory-setup由四层组成,session_autosave.py负责其中"连续性"的最后一道防线:
| 层级 | 工具 | 解决的问题 |
|---|---|---|
| 项目记忆 | Obsidian Zettelkasten 库 | 跨会话失忆 |
| 代码地图 | Graphify 知识图谱 | 重复读取源码浪费 token |
| 对话历史 | scripts/claude_to_obsidian.py 导入管线 | 聊天记录中的洞察丢失 |
| 自动兜底 | scripts/session_autosave.py | 忘记/save时会话消失 |
文件资料索引(方便对照阅读源码):
- Hook 主脚本:scripts/session_autosave.py
- 聊天导入脚本:scripts/claude_to_obsidian.py、scripts/sync_claude_obsidian.sh
- Hook 使用文档:README.md Part 5 章节
- 版本记录:CHANGELOG.md(1.0.0 版本新增该 Hook)
第一步:SessionEnd Hook 如何接收会话负载
当 Claude Code 会话结束(退出、/clear、登出)时,会触发SessionEnd事件,并把一段 JSON 通过stdin传给 Hook 脚本。文件头注释 scripts/session_autosave.py 明确列出了负载结构:
session_id:会话唯一标识transcript_path:本次会话的 JSONL 转录文件路径(关键输入)cwd:会话所在的工作目录(用于推导项目名)hook_event_name:固定为SessionEndreason:结束原因(exit/clear/logout)
入口函数main()(L211-L221)的流程非常克制:
json.load(sys.stdin)读取负载,解析失败只写日志、直接return- 校验
transcript_path存在,找不到转录文件就跳过 - 调用
parse_transcript提取事实,再走过滤与写盘流程
注意一个细节:cwd缺失时会回退到os.getcwd()(L219),保证极端情况下项目名仍有来源。
第二步:从 JSONL 转录中机械提取会话事实
parse_transcript()(L59-L136)是"零 LLM 调用"的核心——逐行读取 JSONL 转录,把一场会话压缩为 6 个字段:
first_prompt 用户消息数 触碰的文件 执行的命令 起始时间 结束时间防御式解析:兼容不同版本
函数注释直言:"格式可能随 Claude Code 版本变化,因此每次访问都加守卫"。具体做法包括:
- 单行
json.loads失败即continue,不因坏行中断(L76-L79) role兼容两种来源:message.role或顶层type(L88)- 文件以
errors="replace"打开,编码异常也不会崩(L71)
三个关键提取逻辑
① 统计真实用户消息(含去噪)
content可能是字符串或 block 列表,脚本只取type == "text"的块;并且用text.startswith("<")过滤掉伪装成用户轮次的工具结果(tool result 以<开头)(L92-L106)。第一条真实用户消息即被记录为first_prompt,作为会话"目标"。
② 追踪被编辑的文件
扫描 assistant 消息中的tool_use块,只对编辑类工具计数:Edit、Write、MultiEdit、NotebookEdit及str_replace系列(L116-L121)。用seen_files集合去重,文件路径优先取file_path、回退path字段。
③ 采样执行的命令
仅捕获Bash类工具(兼容bash、bash_tool命名),且只保留多行命令的第一行并截断到 120 字符(L123-L127)——目的是在日志里"够用即可",避免笔记被长命令刷屏。
第三步:零 token 成本生成 Obsidian 笔记并智能路由
路由规则:日志该写进哪个目录?
resolve_logs_dir()(L148-L154)用cwd的目录名作为项目名,规则很简洁:
| 条件 | 日志写入位置 |
|---|---|
<vault>/<project>/目录存在 | <vault>/<project>/logs/ |
| 否则 | 回退到<vault>/logs/ |
仓库目录名与 vault 文件夹名不一致时(例如 monorepo),官方建议建一个软链接解决(见 README.md "How routing works" 一节)。
笔记长什么样?
build_note()(L157-L208)输出带标准 YAML frontmatter 的 Markdown 笔记:
--- title: "Auto session log — 项目名 — 日期 时间" tags: - session-log - auto-log ← 关键标记,用于 Obsidian 过滤 - 项目名 status: imported session_id: xxx end_reason: exit ---正文包含四个板块:目标(首条 prompt,截断 300 字符)、触碰的文件(最多 20 条)、执行命令采样(最多 10 条)、统计信息(轮数 / 文件数 / 起止时间)。
这些"最多 N 条"的约束来自顶部配置常量 L33-L44:MAX_FILES = 20、MAX_COMMANDS = 10、FIRST_PROMPT_MAX_CHARS = 300——从源头控制笔记体积。
防冲突的文件命名
写入时若两个会话在同一分钟内结束,脚本会自动追加-1、-2后缀避免覆盖(L247-L254)。
四大设计原则:为什么这个 Hook 从不破坏你的会话
对照 README.md Part 5 的设计说明,源码里一一对应:
| 设计原则 | 源码体现 |
|---|---|
| ⚡零 LLM 调用 | 全程只有json、os、pathlib、datetime标准库,毫秒级运行 |
| 🛡️安全网而非替代 | 笔记末尾提示"要富日志请运行/save"(L206-L207) |
| 🔇静默失败 | log()函数自身也包了try/except pass(L49-L56);main()每个可能出错的环节都只写~/scripts/autosave.log后return,Claude Code 完全无感知 |
| 🚫噪声过滤 | 用户消息少于MIN_USER_MESSAGES = 2的"开了就关"会话直接跳过(L233-L235) |
静默失败尤其值得注意:Hook 运行在用户主流程上,任何异常都不能让会话崩掉。所以从读 stdin、解析转录到写文件,每一步都是"出错→记日志→安全退出"。
三步实操安装:在 settings.json 中注册 Hook
第 1 步:复制脚本
mkdir -p ~/scripts # 将仓库中的 scripts/session_autosave.py 复制到 ~/scripts/ chmod +x ~/scripts/session_autosave.py第 2 步:在~/.claude/settings.json注册
若文件已存在,合并hooks键即可,不要删除其他配置:
{ "hooks": { "SessionEnd": [ { "hooks": [ { "type": "command", "command": "VAULT_DIR=$HOME/vault python3 $HOME/scripts/session_autosave.py" } ] } ] } }VAULT_DIR环境变量指向你的 Obsidian 库路径(脚本默认值见 L33)。
第 3 步:验证是否生效
随便开一个项目,与 Claude Code 交互 2~3 轮(含一次文件编辑)后退出,然后检查:
tail -5 ~/scripts/autosave.log看到OK: wrote /path/to/vault/.../logs/YYYY-MM-DD-HHMM-auto-session.md即安装成功。之后在 Obsidian 中用tag:auto-log只看自动日志,-tag:auto-log则隐藏它们。
小结:这个 Hook 教会我们的工程模式
回看 scripts/session_autosave.py 全文仅约 260 行,却浓缩了几个可复用的模式:
- 能用确定性解析解决,就不调用模型——零 token、零延迟、零依赖
- 防御式解析——对上游数据格式(JSONL 转录)保持最大兼容
- 静默失败——旁路组件绝不污染主流程
- 配置常量化——截断阈值、条数上限集中在文件顶部,易于调参
这正是claude-code-memory-setup整体哲学的缩影:Obsidian 记住"决定过什么",Graphify 记住"代码长什么样",而session_autosave.py用最小的成本,保证没有任何一场会话无声无息地消失。
【免费下载链接】claude-code-memory-setup
Up to 71.5x fewer tokens per session on Claude Code with Obsidian + Graphify. Persistent memory, codebase knowledge graphs, and chat import pipeline. 🇧🇷 PT-BR included.
相关推荐
新范式源码解读source-code-hunter:Dubbo异步调用实现原理
新范式源码解读source code hunter:Dubbo异步调用实现原理 引言:异步调用的时代价值 在微服务架构盛行的今天,服务间的远程调用(RPC)性能
文档教程技术博客知识库LLOneBot源码架构解析:从Hook机制到API调用的实现原理
LLOneBot源码架构解析:从Hook机制到API调用的实现原理 LLOneBot是一款基于NTQQ的OneBot11协议实现,通过巧妙的Hook机制和模块化
后端即时通讯claude-code-memory-setup对话管线教程:把Claude Code与Web聊天记录自动归档进Obsidian
claude code memory setup对话管线教程:把Claude Code与Web聊天记录自动归档进Obsidian claude code mem
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考