为 Cursor CLI 接入 Hindsight 持久记忆:Auto-Recall / Auto-Retain 集成实战指南
【免费下载链接】hindsightHindsight: Agent Memory That Learns项目地址: https://gitcode.com/GitHub_Trending/hindsight2/hindsight
<output文章>
Cursor CLI 持久记忆实战:用 Hindsight 为每个提示词自动召回与沉淀上下文
Hindsight 为 Cursor CLI 提供了一套基于官方 Hook 机制的持久记忆集成:在每次提交提示词前自动召回历史记忆并注入为additional_context,在每次对话回合结束后自动将对话沉淀为可检索的记忆,全程无需改变你已有的 Cursor 工作流。读完本文,你将掌握从安装、四种 Hook 事件的工作原理、全部配置项与加载优先级,到按项目隔离记忆库、故障排查的完整实战方案。
集成概览:给 CLI 时代的 Composer 装上"跨会话记忆"
Cursor CLI 的 Composer 会话默认是相互独立的——新会话看不到旧会话中你解释过的技术选型、调试结论和偏好。Hindsight 的hindsight-cursor-cli集成通过四个 Python Hook 脚本把"记忆"接入会话生命周期:
- 会话开始(
sessionStart)时确认 Hindsight 服务可达; - 每次提交提示词(
beforeSubmitPrompt)前自动召回相关记忆并注入上下文; - 对话停止(
stop)后自动保留对话内容; - 会话结束(
sessionEnd)时强制做最后一次保留,避免短会话丢失。
从源码结构看,这套集成的实现位于仓库的 hindsight-integrations/cursor-cli 目录:安装器(cli.py/install.py)、四个 Hook 脚本(hooks/scripts/下的session_start.py、recall.py、retain.py、session_end.py)以及共享库(hooks/scripts/lib/),并配有 tests 测试目录。
注意:根据官方文档,该集成已被 Coding Agents 插件 取代——后者一个包即可覆盖 Claude Code、Codex、opencode、Kilo、Cursor、Copilot 等多种 CLI Agent,并共享同一套按仓库划分的记忆库。本页所述集成及其已发布的包仍然可用,但不再继续开发。由于二者记忆库的划分方式不同,且 Cursor CLI 的历史记录保存在内部数据库中、无法导入,切换时记忆不会自动迁移,详见 Coding Agents 插件文档中的"从单 Agent 插件迁移"一节。
Quick Start:三步接入记忆
安装与注册 Hook
# 1. 安装 CLI(pip) pip install hindsight-cursor-cli # 2. 安装 Hook(默认连接 Hindsight Cloud) hindsight-cursor-cli install --api-url https://api.hindsight.vectorize.io --api-token your-api-key # 3. 重启 Cursor CLI——记忆立即生效如果不使用云端,也可以省略两个参数、直连本地hindsight-embed守护进程:
hindsight-cursor-cli install卸载同样简单:
hindsight-cursor-cli uninstall安装器到底做了什么
从 install.py 的run_install()可以看出,安装过程包含四个步骤:
- 部署脚本:把打包的
scripts/目录(含四个 Hook 脚本及其lib/包)复制到~/.cursor/hooks/cursor-cli/; - 写入默认配置:把 settings.json 写入安装目录,并盖上当前包版本号;
- 注册 Hook:读取打包的 hooks.json 模板,把其中的
__SCRIPTS_DIR__占位符替换为脚本绝对路径,再合并进~/.cursor/hooks.json(merge_hooks()会保留用户已有的其他 Hook 条目,且幂等——重复安装只替换 Hindsight 自己的条目,不会重复追加); - 生成个人配置:在
~/.hindsight/cursor-cli.json不存在时写入种子配置(seed_user_config()永不覆盖已有文件),之后你可以把hindsightApiToken填在这里。
四个 Hook 事件与注册的超时
仓库内 hooks.json 展示了四个事件在~/.cursor/hooks.json中的注册形态:
| Hook 事件 | 脚本 | 用途 | 注册超时 |
|---|---|---|---|
sessionStart | session_start.py | 预热——确认 Hindsight 可达 | 5s |
beforeSubmitPrompt | recall.py | 自动召回——查询记忆并注入上下文 | 45s |
stop | retain.py | 自动保留——提取对话并异步 POST | 30s |
sessionEnd | session_end.py | 最终冲刷——强制保留最后几轮 | 30s |
环境要求:Cursor CLI v0.45+(支持 Hook)、Python 3.9+(Hook 脚本为纯标准库实现,无需额外安装依赖)。
架构与原理:四个 Hook 如何协同
会话开始:预热与守护进程预启动
session_start.py在 Composer 会话开始时触发一次。如果autoRecall和autoRetain都被关闭它会直接跳过;否则尝试解析 API 地址并构建客户端验证可达性,若不可达则调用prestart_daemon_background()在后台预启动本地hindsight-embed守护进程,保证第一个 recall/retain 到来时服务已经就绪。
提交提示词前:自动召回并注入上下文
recall.py是整套集成的核心,执行流程为:
- 从 stdin 读取 Hook 输入(
prompt/user_prompt、conversation_id、transcript_path等); - 若
autoRecall关闭则直接退出;提示词过短(少于 5 字符)也跳过召回; - 解析 API URL、构建
HindsightClient,通过derive_bank_id()确定记忆库、ensure_bank_mission()确保库的 mission 已设置; - 若
recallContextTurns > 1,从transcript_path读取历史轮次并组合成多轮查询,再按recallMaxQueryChars(默认 800)截断; - 调用 Hindsight 召回 API(携带
max_tokens、budget、types、timeout); - 把召回结果格式化为
<hindsight_memories>上下文块,写入last_recall.json状态文件; - 按 Cursor 的
beforeSubmitPrompt输出协议向 stdout 输出{"continue": true, "additional_context": "<hindsight_memories>..."}。
注入的上下文块结构如下(来自文档示例):
<hindsight_memories> Relevant memories from past conversations... Current time - 2026-03-27 09:14 - Project uses FastAPI with asyncpg — not SQLAlchemy [world] (2026-03-26) - Preferred testing framework: pytest with pytest-asyncio [experience] (2026-03-26) </hindsight_memories>Cursor 会在把对话发送给模型前把这段上下文前置到会话中——它对模型可见,但不会出现在对话转录里。值得强调的是,recall 永远输出continue: true,任何记忆查询失败都不会阻断你的提示词提交——这是"记忆 Hook 的安全默认值"(源码注释明确说明非零退出会阻断提示词,对记忆 Hook 而言是危险默认值)。
对话停止后:自动保留
retain.py在stop事件(Agent 循环结束)后触发:
- 读取 Hook 输入中的
conversation_id/session_id与transcript_path; - 读取完整转录(
read_transcript,可含工具调用标记); - 依据
retainEveryNTurns做节流——用increment_turn_count()统计轮次,非整倍数轮次直接跳过; - 依据
retainMode选择保留策略:full-session保留完整会话;chunked模式用slice_last_turns_by_user_boundary()截取滑动窗口(窗口 =retainEveryNTurns + retainOverlapTurns); - 剥离之前注入的记忆标签(防止"记忆套娃"式的反馈循环),过滤角色后格式化为纯文本转录;
- 以
session_id作为 document ID POST 到 Hindsight 保留 API(async=true后台处理)——同一会话重复运行会更新而非重复存储;chunked模式下则追加时间戳生成独立文档; - 支持
retainTags模板变量(如{conversation_id}、{session_id}、{bank_id}、{timestamp})与retainMetadata自定义元数据。
Cursor 的stopHook 是 fire-and-forget 语义——Agent 循环不等待响应,所以 retain 失败只记录到 stderr 并退出码为 0,绝不影响 Agent。
会话结束:最终冲刷
session_end.py在会话终止时触发,直接调用run_retain(hook_input, force=True)——force=True会绕过retainEveryNTurns节流,保证即使整个会话只有一两轮(不足 10 轮阈值)也能被完整保留。
连接模式:云端 API 与本地守护进程
集成支持两种连接方式,在~/.hindsight/cursor-cli.json中配置:
1. 外部 API(推荐)
连接正在运行的 Hindsight 服务(云端或自托管):
{ "hindsightApiUrl": "https://api.hindsight.vectorize.io", "hindsightApiToken": "hsk_your_token" }2. 本地守护进程
在本地运行hindsight-embed(session_start.py会按apiPort默认9077检测它)。守护进程不会由插件自动启动,需要单独启动:
uvx hindsight-embed然后在配置中把hindsightApiUrl留空,插件即连接http://localhost:9077。此外retain.py在get_api_url(config, allow_daemon_start=True)时还允许在守护进程未运行时尝试自动拉起它。
配置详解:全参数表与加载优先级
默认配置随安装部署在~/.cursor/hooks/cursor-cli/settings.json(内含完整默认值,见仓库内 settings.json)。个人覆盖配置应放在~/.hindsight/cursor-cli.json(升级时保留)。大多数设置还可用环境变量覆盖。
加载优先级(后加载者胜出,见 config.py 的load_config()):
- 内置默认值(
DEFAULTS) - 插件
settings.json(~/.cursor/hooks/cursor-cli/settings.json) - 用户配置(
~/.hindsight/cursor-cli.json) - 环境变量(
ENV_OVERRIDES中定义的 24 个变量)
连接相关
| 配置项 | 环境变量 | 默认值 | 说明 |
|---|---|---|---|
hindsightApiUrl | HINDSIGHT_API_URL | "" | Hindsight API 服务地址;空值 = 本地守护进程 |
hindsightApiToken | HINDSIGHT_API_TOKEN | null | API Token,连接 Hindsight Cloud 必填 |
apiPort | HINDSIGHT_API_PORT | 9077 | 本地hindsight-embed守护进程端口 |
记忆库(Memory Bank)
| 配置项 | 环境变量 | 默认值 | 说明 |
|---|---|---|---|
bankId | HINDSIGHT_BANK_ID | "cursor-cli" | 读写使用的记忆库;未开dynamicBankId时所有会话共用 |
bankMission | HINDSIGHT_BANK_MISSION | coding assistant prompt | 描述 Agent 用途,创建/更新记忆库时发送 |
retainMission | — | extraction prompt | 指导 Hindsight 事实抽取的指令(从编程对话中抽取什么) |
dynamicBankId | HINDSIGHT_DYNAMIC_BANK_ID | false | 为true时按dynamicBankGranularity字段派生唯一记忆库 ID |
dynamicBankGranularity | — | ["agent", "project"] | 参与派生动态记忆库 ID 的字段;"project"= 工作目录,"agent"= Agent 名 |
agentName | HINDSIGHT_AGENT_NAME | "cursor-cli" | 动态记忆库 ID 派生中使用的 Agent 名 |
bankIdPrefix | — | "" | 记忆库 ID 前缀(可选) |
从 bank.py 可以看到,动态记忆库 ID 派生支持五个合法字段:agent、project、gitProject、session、user(后两者不在默认粒度中)。project名称的解析优先级是:CURSOR_PROJECT_DIR环境变量(Cursor 为每个 Hook 设置)→workspace_roots[0]→cwd,均取 basename,找不到时回退"unknown";gitProject在实现上是project的别名,用于跨 worktree 共享记忆。多个字段用::连接(如cursor-cli::my-project)。
自动召回(Auto-Recall)
| 配置项 | 环境变量 | 默认值 | 说明 |
|---|---|---|---|
autoRecall | HINDSIGHT_AUTO_RECALL | true | 自动召回总开关 |
recallBudget | HINDSIGHT_RECALL_BUDGET | "mid" | 搜索深度:"low"(快)、"mid"(均衡)、"high"(彻底) |
recallMaxTokens | HINDSIGHT_RECALL_MAX_TOKENS | 1024 | 召回记忆块的最大 token 数 |
recallTimeout | HINDSIGHT_RECALL_TIMEOUT | 10 | 召回 API 调用超时(秒) |
recallTypes | — | ["world", "experience"] | 要检索的记忆类型 |
recallContextTurns | HINDSIGHT_RECALL_CONTEXT_TURNS | 1 | 构造召回查询时纳入的历史轮次;1= 仅当前提示词 |
recallMaxQueryChars | HINDSIGHT_RECALL_MAX_QUERY_CHARS | 800 | 召回查询最大字符数 |
recallRoles | — | ["user", "assistant"] | 参与多轮查询的角色 |
recallPromptPreamble | — | 内置提示语 | 注入上下文块开头的前言 |
includeTools | HINDSIGHT_INCLUDE_TOOLS | false | 是否在纯文本转录中把工具调用呈现为[tool_use:name]/[tool_result]标记(用于召回查询;当retainToolCalls关闭时也用于保留) |
自动保留(Auto-Retain)
| 配置项 | 环境变量 | 默认值 | 说明 |
|---|---|---|---|
autoRetain | HINDSIGHT_AUTO_RETAIN | true | 自动保留总开关 |
retainMode | HINDSIGHT_RETAIN_MODE | "full-session" | "full-session"按会话发送完整转录(按 session ID upsert);"chunked"每 N 轮发送滑动窗口 |
retainEveryNTurns | — | 10 | 每 N 轮触发一次保留;1= 每轮。数值越大 API 调用越少 |
retainOverlapTurns | — | 2 | chunked模式下窗口重叠轮数 |
retainContext | — | "cursor-cli" | 标识来源集成的标签;多个集成写入同一记忆库时用于区分 |
retainRoles | — | ["user", "assistant"] | 参与保留的角色 |
retainToolCalls | — | true | 转录中是否包含工具调用 |
retainTags | — | ["{conversation_id}"] | 保留文档的标签,支持模板变量 |
retainMetadata | — | {} | 附加元数据,值支持模板变量 |
调试
| 配置项 | 环境变量 | 默认值 | 说明 |
|---|---|---|---|
debug | HINDSIGHT_DEBUG | false | 向 stderr 输出详细日志,所有日志行以[Hindsight]前缀标记 |
此外,settings.json中还有daemonIdleTimeout、embedVersion、embedPackagePath、llmProvider、llmModel、llmApiKeyEnv等用于本地守护进程/LLM 模式的参数,可通过HINDSIGHT_DAEMON_IDLE_TIMEOUT、HINDSIGHT_EMBED_VERSION等环境变量覆盖。环境变量的布尔值按"true"/"1"/"yes"解析,整数用int()转换(见 config.py 的_cast_env())。
环境变量示例
export HINDSIGHT_API_URL=https://api.hindsight.vectorize.io export HINDSIGHT_API_TOKEN=your-api-key export HINDSIGHT_BANK_ID=my-project export HINDSIGHT_RECALL_TIMEOUT=30 export HINDSIGHT_DEBUG=true按项目隔离记忆:Dynamic Bank ID 实战
默认情况下所有会话共享cursor-cli这一个记忆库。要为每个项目建立独立记忆库,开启动态记忆库 ID:
{ "dynamicBankId": true, "dynamicBankGranularity": ["agent", "project"] }按此配置,在~/projects/api与~/projects/frontend中分别运行 Cursor 时,记忆会分别存储与召回(记忆库 ID 由工作目录路径派生,如cursor-cli::api)。
若想让同一仓库的所有 worktree 共享记忆,可改用gitProject维度:
{ "dynamicBankId": true, "dynamicBankGranularity": ["agent", "gitProject"] }故障排查
Hook 不触发:确认~/.cursor/hooks.json存在且为合法 JSON、包含四个 Hook 条目,并确认python3在你的 shell$PATH中。重新运行hindsight-cursor-cli install可重写 Hook 条目(merge_hooks()幂等合并,安全)。
没有召回记忆:召回只有在有内容被保留之后才有结果。先完整跑完一个 Cursor 会话,再开启新会话验证。
记忆没有存储:retainEveryNTurns默认是10——stopHook 每 10 轮才触发一次保留。测试时在~/.hindsight/cursor-cli.json中加"retainEveryNTurns": 1。注意sessionEndHook 在关闭会话时会强制执行一次最终保留。
调试模式:在~/.hindsight/cursor-cli.json中加"debug": true(或设置HINDSIGHT_DEBUG=true),即可在 stderr 看到每个回合 Hindsight 在做什么;安装器提示调试日志可tail -F ~/.hindsight/cursor-cli/state/*.log查看。
会话开始没有 "Hindsight is active" 提示:同样用"debug": true查看 stderr,并确认HINDSIGHT_API_URL指向可达的服务器。
本地开发与测试
仓库内该集成自带测试套件(位于 hindsight-integrations/cursor-cli/tests),可在本地运行:
cd hindsight-integrations/cursor-cli uv sync uv run pytest tests/ -v测试通过 mock HTTP 客户端、stdin/stdout 管道与基于文件的状态来模拟 Hook 行为,无需真实运行 Hindsight 服务即可验证 recall/retain/bank 派生/安装合并等逻辑(见 test_hooks.py、test_install.py 等)。
迁移到 Coding Agents 插件
由于 Cursor CLI 集成已被 Coding Agents 插件取代,新项目建议直接使用统一插件:
cd /path/to/your/repo npx @vectorize-io/hindsight-coding-agents install cursor-cli需要留意的是:记忆不会自动迁移——两者的记忆库划分方式不同,且 Cursor CLI 插件的历史记录保存在其内部数据库中、无法导入。切换后,旧会话的记忆需要通过 Coding Agents 文档中"从单 Agent 插件迁移"一节的说明处理。 </output文章>
【免费下载链接】hindsightHindsight: Agent Memory That Learns项目地址: https://gitcode.com/GitHub_Trending/hindsight2/hindsight
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考