首页
/ MemPalace Cursor IDE 自动记忆 Hooks:接入 sessionStart / stop / preCompact 三事件,实现无感存档与会话召回

MemPalace Cursor IDE 自动记忆 Hooks:接入 sessionStart / stop / preCompact 三事件,实现无感存档与会话召回

2026-09-07 18:03:36作者:房伟宁

MemPalace 为 Cursor IDE 提供了一套开箱即用的自动记忆 hooks(hooks/cursor/),覆盖 stop(回合结束自动存档)、preCompact(压缩前快照转录)与 sessionStart(会话启动注入 wing 级召回指引)三个事件,让 Agent 无需手动输入“保存”命令也能把每次对话沉淀进记忆宫殿。读完本文,你将掌握这套 hooks 的安装/卸载方式、全部环境变量旋钮、三种事件的触发时机与输出契约,以及它们相对 Claude Code hooks 的差异设计原理,可直接在自己的 Cursor 工作区中落地并排障。

这套 hooks 与仓库内既有的 Claude Code + Codex hooks叠加关系:二者可以同时运行,共享同一个 ~/.mempalace/hook_state/ 状态目录与同一组 kill switch,互不干扰。

目录里有什么

hooks/cursor/ 目录是 Cursor 集成的最小发行单元,仓库内 hooks/cursor/README.md 对每个文件做了定位说明:

文件 职责
lib/common.sh 共享 bash 助手(stdin 解析、日志、计数器、wing 推断、kill switch)。三个 hook 脚本都 source 它。
mempal_save_hook_cursor.sh Cursor stop hook。按会话统计 stop 调用次数,每 SAVE_INTERVAL(默认 15)次就输出一条 followup_message,指示 Agent 把本次会话归档进 MemPalace。
mempal_precompact_hook_cursor.sh Cursor preCompact hook。在上下文压缩前同步对转录执行 mempalace mine,再落下 .pending 标记,迫使下一次 stop 强制触发存档提醒。
mempal_wake_hook_cursor.sh Cursor sessionStart hook。返回 additional_context,指示 Agent 依据工作区根目录推断出的 wing 做作用域化召回。Cursor 独有能力——Claude Code 没有对应事件。
install.sh 可选安装器。把脚本复制到 ~/.mempalace/hooks/cursor/,并将条目合并进 ~/.cursor/hooks.json(项目级则为 .cursor/hooks.json)。支持 --dry-run--uninstall
STDIN_SHAPE.md 参考文档。逐事件给出 stdin/stdout 的 JSON schema,并引用官方 Cursor hooks 文档。

入门提示:hooks 只负责“自动保存”这一侧。若要同时获得 MemPalace 的 MCP server、斜杠命令(如 /mempalace-search)与 mempalace skill,可另行安装仓库根目录的 Cursor 插件(部署到 ~/.cursor/plugins/local/mempalace)。插件与 hooks 彼此正交、可任意顺序安装——插件刻意代为接线 hooks,因为 Cursor 的 hooks 是按用户/项目配置在 hooks.json 中的,并非按插件配置。

三个事件各自做什么

Hook 触发时机 行为
Wake Hook sessionStart——每次打开新 Cursor 会话 返回 additional_context,指示 Agent 依据工作区根目录推断出的 wing 做召回。Cursor 独有,Claude Code 无对应物。
Save Hook stop——每个 Agent 回合结束后 按会话统计 stop 次数,默认每 15 次输出一条 followup_message,引导 Agent 把会话归档进 MemPalace 并写日记。
PreCompact Hook preCompact——上下文压缩即将开始前 对转录同步执行 mempalace mine(压缩前的兜底捕获),并落下 pending-save 标记,使下一次 stop 无视计数器强制触发一次存档提醒。

双层捕获策略:save 与 preCompact 两个 hook 都会把 JSONL 转录直接 mine 进宫殿(捕获 Shell 结果、搜索发现、构建报错等逐字工具输出);save hook 额外引导 AI 写结构化 drawer 与日记条目,形成双保险(belt-and-suspenders)。

三层召回体系中的定位

sessionStart hook 之外,MemPalace 还提供另外两种“让 Agent 先查宫殿再作答”的机制,三者正交、可自由组合:

层级 触发 范围 获取途径
sessionStart hook 每个新会话恰好一次 会话开场注入 wing 作用域的召回上下文 本文安装的三件套
mempalace-recall skill 当请求匹配其描述或主动挂载时 完整的“先搜索再回答”协议 Cursor 插件 skills/
Recall rule Cursor 匹配器判定当前回合与召回相关时 一段“先搜索”的简短提示 插件 rules/mempalace-recall.mdcexamples/cursor/rules/

其中 hook 是唯一“自动且每个会话恰好触发一次”的层级;skill 与 rule 是需求驱动式——只在用户真的问到过往工作、人物或历史决策时才介入,绿地编码时完全隐身。想让每个会话都强制召回,可把 examples/cursor/rules/alwaysApply: true 的变体复制到 ~/.cursor/rules/(更重、需要刻意选择的 opt-in)。

安装

快速安装(官方安装器)

仓库自带安装器 hooks/cursor/install.sh,推荐路径。安装器绝不会被自动触发——pip install mempalace 不会改写你的 Cursor 配置,因为“编辑器配置是神圣的,未经明确同意绝不应触碰”。安装是一步有文档记录的显式 opt-in。

先预览(不写任何东西,仅把将要生成的 JSON 打印到 stdout):

hooks/cursor/install.sh --scope user --dry-run

应用——写入 ~/.cursor/hooks.json 并把脚本复制到 ~/.mempalace/hooks/cursor/

hooks/cursor/install.sh --scope user

项目级作用域——只作用于该仓库,写入 <repo>/.cursor/hooks.json

hooks/cursor/install.sh --scope project --target /path/to/your/repo

安装器会保留 hooks.json 中任何与本产品无关的既有 hook;重复执行是幂等的。完整参数见脚本头注释:

  • --scope user|project——目标作用域,默认 user
  • --target <path>——--scope project 时的项目根(默认 $PWD),user 下被忽略;
  • --install-dir <path>——脚本复制目的地,默认 ~/.mempalace/hooks/cursor
  • --variant full|minimal——full = stop + preCompact + sessionStart;minimal = 仅 stop;默认 full
  • --dry-run——只打印将写入的 JSON,不写文件也不复制脚本;
  • --uninstall——从目标 hooks.json 移除 MemPalace 条目(保留无关 hook),删除已安装脚本。

手动安装(不使用安装器)

最小接线只需 stop 一个事件。向 ~/.cursor/hooks.json 添加:

{
  "version": 1,
  "hooks": {
    "stop": [
      {
        "command": "/absolute/path/to/hooks/cursor/mempal_save_hook_cursor.sh",
        "loop_limit": 1
      }
    ]
  }
}

完整三件套(推荐)还要接上 sessionStartpreCompact——参考 examples/cursor/hooks.json

{
  "version": 1,
  "hooks": {
    "sessionStart": [
      {
        "command": "$HOME/.mempalace/hooks/cursor/mempal_wake_hook_cursor.sh"
      }
    ],
    "stop": [
      {
        "command": "$HOME/.mempalace/hooks/cursor/mempal_save_hook_cursor.sh",
        "loop_limit": 1
      }
    ],
    "preCompact": [
      {
        "command": "$HOME/.mempalace/hooks/cursor/mempal_precompact_hook_cursor.sh"
      }
    ]
  }
}

只想要 stop-only 方案,则参考 examples/cursor/hooks.minimal.json。项目级安装时内容完全一致,只是写入 <repo>/.cursor/hooks.json——项目 hooks 会在任何受信工作区加载、可随项目入库,云端 Agent 同样会加载项目 hooks。

手动安装请先给脚本加可执行权限:

chmod +x hooks/cursor/mempal_save_hook_cursor.sh \
         hooks/cursor/mempal_precompact_hook_cursor.sh \
         hooks/cursor/mempal_wake_hook_cursor.sh

编辑保存后,Cursor 会监听 hooks.json 并自动重载。若 hooks 仍未触发,重启 Cursor 并到 Settings → Hooks 面板检查。

配置项

所有旋钮都是环境变量,默认值尽量与 Claude Code hooks 对齐,让两个编辑器共享同一个 hook-state 目录:

变量 默认值 用途
MEMPAL_SAVE_INTERVAL 15 两次存档提醒之间的 stop 事件间隔。调低更频繁保存,调高更少打扰。
MEMPAL_CURSOR_SILENT (未设置) 设为 1/true/yes 以抑制 followup_message。hook 仍会执行尽力而为的后台 mine 并维持计数器,只是保持静默。MEMPAL_VERBOSE=false/0/no 等效。为何默认开打提醒见下文专节。
MEMPAL_DIR (未设置) 可选的额外项目目录,每次存档时以 --mode projects 一并 mine。纯粹叠加——永远不替代转录 mine。
MEMPAL_PYTHON 自动探测 Python 3 解释器路径。解析顺序:$MEMPAL_PYTHONcommand -v python3 → 裸 python3。macOS 从 GUI 启动 Cursor 导致继承 PATH 缺失已装 Python 时特别有用。
MEMPAL_STATE_DIR $HOME/.mempalace/hook_state hook 存放每会话计数器文件、pending-save 标记与 cursor_hook.log 的位置。
MEMPAL_STATE_TTL_DAYS 30 过期的 cursor_*.count / cursor_*.pending 状态文件在此天数后被垃圾回收。hooks 内置每日限频的一次清扫;只触碰 Cursor 自己的状态,共享日志与其他编辑器的状态不受影响。
MEMPAL_DISABLE_HOOK (未设置) 设为 1/true/yes 一键停用全部三个 hook,应急 kill switch。
MEMPALACE_HOOKS_AUTO_SAVE (未设置) 设为 false/0/no 停用。语义与 Claude Code hooks 一致,也支持经由 ~/.mempalace/config.json{"hooks": {"auto_save": false}} 生效。

实测口径的补充(来自 mempal_save_hook_cursor.sh 的防御逻辑):MEMPAL_SAVE_INTERVAL 会被强制洗白,空值、非数字与 0 一律回落为 15,以免取模运算触发 bash “division by 0” 崩溃;MEMPAL_STATE_TTL_DAYS 则要求纯数字并剥离前导零,避免坏 token 或八进制 token 流入 find -mtime

工作原理:三个事件的三条链路

Wake Hook(sessionStart

Cursor 打开新会话 → sessionStart 触发
                          ↓
           Hook 读取 workspace_roots[0]
                          ↓
           推断 wing = basename(workspace_root)
                          ↓
   {"additional_context": "把召回作用域限定到 wing=<...>"}
                          ↓
      Agent 在第一回合前读取 additional_context
                          ↓
      Agent 在首个相关问题上调用 mempalace_search +
      mempalace_diary_read(wing 作用域)

Cursor 的 sessionStart 是 fire-and-forget 的——Agent 循环不会等待阻塞式响应,也不消费 continue / user_message;但它会遵循 additional_context,而这是 MemPalace 唯一输出的字段。源码实现见 mempal_wake_hook_cursor.sh:推断出的 wing 以 argv 传给 Python 生成 JSON,提示 Agent 调用 mempalace_search (wing=..., query=...)mempalace_diary_read (agent_name=cursor-ide, wing=..., last_n=10)——这两个 MCP 工具在 mcp_server.py 中均有对应实现(tool_searchtool_diary_read)。

Save Hook(stop 事件)

用户发消息 → Agent 响应 → Cursor 触发 stop hook
                              ↓
              Hook 读取 stdin 中的 loop_count
                              ↓
    ┌── loop_count > 0(我们自己的 followup 正在执行)──→ 输出 "{}"
    │
    └── loop_count == 0
                    ↓
         检查 preCompact 留下的 pending-save 标记
                    ↓
      ┌── 标记存在 ──→ 删除标记 + 输出 followup_message
      │
      └── 无标记
                    ↓
     当前 conversation_id 的计数器原子自增
                    ↓
   ┌── counter % SAVE_INTERVAL != 0 ──→ 输出 "{}"
   │
   └── counter % SAVE_INTERVAL == 0
                       ↓
     后台: mempalace mine <transcript_dir>(尽力而为)
                       ↓
      输出 {"followup_message": "保存关键主题..."}
                       ↓
      Cursor 把 followup 自动提交为下一轮用户消息
                       ↓
      Agent 归档 drawers + 写日记
                       ↓
      Agent 停止;stop 再次触发且 loop_count = 1
                       ↓
      Hook 看到 loop_count > 0 → 输出 "{}" → Agent 收尾

loop_count > 0 短路是防死循环的关键:提醒发一次 → Agent 保存 → 停止 → 我们看到 loop_count = 1 → 放行。这正是 Claude Code stop_hook_active 标志的 Cursor 等价物;hooks.json 中的 loop_limit: 1 是再上一层的纵深防御。对应源码在 mempal_save_hook_cursor.sh:先短路自循环、再消费 pending 标记、最后走正常计数分支。

计数的语义细节值得注意:Cursor 的 stop 事件不携带 session_id,只有 conversation_id,因此计数器文件以 conversation_id 为键(形如 cursor_<conv>.count)。计数采用取模算术且单调递增、不重置,使日志文件对一次会话的总回合数可 grep。

PreCompact Hook(preCompact

上下文窗口接近满载 → Cursor 触发 preCompact(仅观测)
                              ↓
       同步执行: mempalace mine <transcript_dir>
                              ↓
       为当前 conversation_id 落下 pending-save 标记
                              ↓
       {"user_message": "转录已快照..."}
                              ↓
       压缩继续进行(我们无法阻塞它)
                              ↓
       下一次 stop 事件拾取标记 → 强制存档

Cursor 的 preCompact 被官方文档标记为仅观测(observational only)——它唯一允许的输出字段是 user_message,既没有 followup_message,也无法像 Claude Code 的 PreCompact 那样 decision: block 阻塞压缩。MemPalace 的绕行方案(见 mempal_precompact_hook_cursor.sh):

  1. 在 hook 内同步执行 mempalace mine,让逐字转录在压缩“总结掉”之前落进宫殿;
  2. 落下 cursor_<conversation_id>.pending 标记,下一次 stop 调用读取后无视计数器强制触发一次存档提醒。

为何坚持同步执行:压缩不可逆,必须在 hook 返回前完成摄取;后台化 mining 会与压缩竞速丢数据。代价是超大转录可能超过 Cursor 的每-hook 超时被中途 kill——这是可接受的,因为 mempalace mine 是增量、只追加的,被 kill 的 mine 会在下次调用时干净续跑而非损坏宫殿,pending-save 标记仍会在下一次 stop 强制重跑 mine 并附带一次逐字保存提醒。实现特意套更短的自设超时:截断 mine 等于用“可恢复的部分摄取”去交换“压缩前的必然静默数据丢失”。

Cursor 相对 Claude Code hooks 的差异

方面 Claude Code hooks(hooks/mempal_*.sh Cursor hooks(hooks/cursor/*.sh
计数器键 session_id conversation_id(Cursor 的稳定会话 id)
循环防护 stdin 中的 stop_hook_active 标志 stdin 中的 loop_count 字段
计数方式 解析 JSONL 转录统计用户消息 统计 stop 调用次数(转录 schema 未公开)
捕获路径 后台 mine --mode convos(normalize.py 有 Claude 解析器) 后台 mine 尽力而为(尚无 Cursor 解析器);followup_message 承担逐字捕获
保存默认 静默——日记提醒是 MEMPAL_VERBOSE=true 的 opt-in 默认开启提醒;用 MEMPAL_CURSOR_SILENT=1 / MEMPAL_VERBOSE=false 关掉
preCompact 行为 decision: block 在压缩前强制保存 预 mine + pending-save 标记(Cursor preCompact 仅观测)
sessionStart 无(Claude Code 无对应事件) additional_context 注入召回指引
状态目录 $HOME/.mempalace/hook_state(硬编码) 同默认,另有 MEMPAL_STATE_DIR 环境变量可覆盖
Kill switch MEMPALACE_HOOKS_AUTO_SAVE=false 同左,另有 MEMPAL_DISABLE_HOOK=1 别名
日志文件 hook.log cursor_hook.log(独立成文件,避免跨工具日志刷屏)

逐事件的 stdin/stdout schema 与官方文档引用见 hooks/cursor/STDIN_SHAPE.md,全文渲染版见 website/guide/cursor-hooks.md

为什么默认开启提醒(Cursor 专属决策)

默认静默的 Claude Code hook 不同——后者靠后台 mempalace mine --mode convos 自行捕获逐字转录(因为 normalize.py 有 Claude Code JSONL 解析器),LLM 驱动的日记提醒是 MEMPAL_VERBOSE 背后的 opt-in——Cursor 的转录格式未被官方文档公开,且 mempalace/normalize.py 尚无 Cursor 解析器。因此 Cursor 上 stop/preCompact hook 的后台 mine 只是尽力而为,暂时产不出干净的逐字对话 drawer。

这使 followup_message 成为 Cursor 上承载逐字捕获的关键路径(load-bearing verbatim-capture path):它驱动 Agent 把自己上下文里的逐字引文通过 mempalace_checkpoint 归档(一次调用内去重、写入非重复项并落日记)。若默认关闭它,一个默认安装的 Cursor 将什么都捕获不到——这就是它在 Cursor 上默认开启的原因。设置 MEMPAL_CURSOR_SILENT=1(或 MEMPAL_VERBOSE=false)即可切回 Claude 风格静默,代价是捕获能力下降。一旦 normalize.py 学会读取 Cursor 转录,该默认值将翻转回静默以与 Claude 对齐——这是有记录的后继工作。

调试

一切运行痕迹都追加到同一个日志:

cat ~/.mempalace/hook_state/cursor_hook.log

示例日志行(ISO 8601 时间戳 + 事件 + 会话 id):

[2026-05-27T02:16:01Z] [event=sessionStart] [conv=abc123] workspace=/Users/me/proj wing=proj
[2026-05-27T02:21:33Z] [event=stop]         [conv=abc123] counter 0 -> 1 (interval=15)
[2026-05-27T02:42:09Z] [event=stop]         [conv=abc123] counter 14 -> 15 (interval=15)
[2026-05-27T02:42:09Z] [event=stop]         [conv=abc123] TRIGGERING SAVE at counter=15
[2026-05-27T02:42:11Z] [event=stop]         [conv=abc123] loop_count>0; letting agent stop
[2026-05-27T03:05:44Z] [event=preCompact]   [conv=abc123] trigger=auto transcript=/Users/me/.cursor/.../transcript.txt
[2026-05-27T03:05:46Z] [event=stop]         [conv=abc123] consumed pending-save marker (post-compaction)

对比 Claude Code 的 %H:%M:%S 日志,Cursor 日志改用 ISO 8601(UTC)以跨时区可 grep。当 hook 无法解析 stdin(payload 损坏、Cursor schema 未来变更)时,被截断到 4096 字节、权限 0600 的原始输入落在:

~/.mempalace/hook_state/cursor_last_input.log
~/.mempalace/hook_state/cursor_last_python_err.log

两份文件在每次失败时覆盖写、绝不追加,因此反复出现的错误配置不会撑爆磁盘。

源码级防御细节(读 common.sh 的收获)

共享库 hooks/cursor/lib/common.sh 值得细读,它把三条 hook 的健壮性做到了很细的颗粒度:

  • stdin 解析mempal_parse_stdin):用 python3 -c + 哨兵标记 + sed -n 'Np' 逐行取数,兼容 macOS 默认的 bash 3.2(无 mapfile/readarray);解析器刻意只用 python -c 而非 heredoc,避免 heredoc 屏蔽 Python stdin 导致 json.load(sys.stdin) 静默读空。
  • 字符清洗:conversation_id、transcript_path 等全部经过 shell 安全字符集白名单(字母数字与 _ / . - ~)清洗,防止恶意 transcript_path 注入元字符。
  • 解析失败回退:Cursor 保证每次 hook 执行都会注入 CURSOR_TRANSCRIPT_PATHCURSOR_PROJECT_DIR 等环境变量,JSON 解析失败时仍有可用工作区;transcript 路径还支持 ~/ 前缀展开。
  • 原子计数器mempal_write_counter_atomic):同目录临时文件 + mv 原子改名(POSIX 原子),并发 hook 不会写坏文件。
  • 每日限频 GCmempal_gc_stale_state):借 cursor_last_sweep 标记做到 24 小时最多一次,且 glob 后缀锚定 cursor_*.count / cursor_*.pending——共享日志、其他编辑器状态都不会被误删;先写标记再清扫,中途崩溃也只跳过本轮。
  • wing 推断mempal_infer_wing):纯 bash + POSIX 工具,处理 /root、尾斜杠、空格折叠、Windows 反斜杠路径等边界;推断为空则回落 cursor_session
  • 转录校验mempal_is_valid_transcript):非空、.json/.jsonl 后缀、无 .. 穿越段,三个条件缺一不可。
  • JSON 输出mempal_emit):用 printf '%s\n' 而非 echo,避免 echo-n/-e 当旗标、以及各实现间反斜杠差异。

三个脚本与 shared lib 都被 tests/test_cursor_hooks_shell.py 覆盖:包括 MEMPAL_SAVE_INTERVAL=0 回落默认的回归用例、preCompact 必须落下 pending 标记的断言、sessionStart 必须输出 additional_context 的断言,以及静默开关(MEMPAL_CURSOR_SILENT / MEMPAL_VERBOSE)两路等效性的参数化测试——这些正是仓库对上述行为承诺的可执行证据。

成本

hooks 本身零额外 LLM token:它们是跑在本机的 bash 脚本,不调用任何 API。save hook 发出的 followup_message 是一次普通用户回合,计费与任何其他用户消息相同,不会触发除用户本会发出的那次之外的额外 LLM 调用。想要聊天窗里零 followup,设 MEMPAL_CURSOR_SILENT=1

已知限制与解决路径

  • hooks 在会话开始时加载:Cursor 监听 hooks.json 并重载接线,但要让新加载的 hook 脚本作用于既有会话,通常需要新开会话。这与 Claude Code 的 hook 生命周期一致。
  • preCompact 无法阻塞:见上文流程图,pending-save 标记就是针对它的绕行方案。
  • 转录文件格式不透明:Cursor 未公开 transcript_path 指向文件的 schema,mempalace/normalize.py 也暂无 Cursor 解析器,因此 mempalace mine --mode convos 在 Cursor 上是尽力而为——产不出干净的逐字对话 drawer,followup_message 才是承载捕获的主路径。为 normalize.py 增加 Cursor 解析器是有记录的后继工作;落地后 followup 即可像 Claude hook 一样默认静默。
  • preCompact 同步 mine 可能超时:超大转录下可能超过 Cursor 的每-hook 超时被 kill;因 mine 增量只追加,被 kill 的 mine 会安全续跑,pending 标记仍会兜底强制下次存档。

延伸阅读

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.13 K
2.75 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
857
1.35 K
docsdocs
暂无描述
Markdown
897
5.8 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
529
593
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
915
1.83 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.58 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.35 K
1.46 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
1.01 K
515
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
547
388