Hindsight Cursor 集成指南:为 Cursor 接入跨会话长期记忆(Hook 自动回忆 + MCP 按需记忆工具)
【免费下载链接】hindsightHindsight: Agent Memory That Learns项目地址: https://gitcode.com/GitHub_Trending/hindsight2/hindsight
本文是一份面向 Cursor 用户与 AI 编程代理开发者的实操指南,完整讲解如何通过官方hindsight-cursor插件,让 Cursor 在会话启动时自动回忆项目级长期记忆、在任务结束时自动沉淀对话内容,并在会话中途通过 MCP 工具按需执行 recall / retain / reflect 记忆操作。读完本文,你将掌握插件安装与卸载、三种连接模式、全部配置项及其环境变量覆盖方式、Hook 触发验证与常见故障排查方法,并从源码层面理解会话回忆、自动保留与防重复存储的底层实现。
背景与定位
Cursor 是当前流行的 AI 代码编辑器之一,其每次会话都从空白上下文开始:上一轮讨论过的技术决策、用户偏好与项目约定,除非显式写入文档,否则不会自动出现在新会话中。Hindsight 提供"类生物"的长期记忆能力(项目名为 Hindsight: Agent Memory That Learns),而hindsight-cursor插件正是把这一能力嫁接到 Cursor 的载体。
插件适配了 Cursor 的Hook 机制(自动触发回忆与保留)与MCP 机制(会话中按需调用记忆工具),二者互补,由同一条命令hindsight-cursor init一次性完成安装。本仓库中该集成的完整实现位于 hindsight-integrations/cursor,包含 CLI(cli.py)、Hook 脚本(session_start.py、retain.py)、运行库(scripts/lib/)与测试(tests)。
工作原理:两种互补的记忆机制
插件使用两套机制协同工作:
| | 插件 Hooks(自动) | MCP 工具(按需) | |--|--------------------------|----------------------| |安装|pip install hindsight-cursor && hindsight-cursor init| 由init自动配置 | |回忆(Recall)| 会话启动时,通过additionalContext注入记忆 | Agent 在会话中调用recall工具 | |保留(Retain)| 任务结束时自动执行 | Agent 显式调用retain工具 | |反思(Reflect)| Hooks 不可用 | 作为工具提供 | |适用场景| 无需用户干预的沉浸式项目记忆 | 定向查找与显式记忆操作 |
两种机制都由单条hindsight-cursor init命令完成配置;如果只想用 Hooks、不需要 MCP,可加--no-mcp跳过。
从源码看,init写入的 Hook 注册表实际包含三个事件。查看 cli.py 中的_project_hooks_block():
sessionStart→ 执行scripts/session_start.py,超时 15 秒;stop→ 执行scripts/retain.py,超时 15 秒;sessionEnd→ 同样执行scripts/retain.py,超时 15 秒。
对应地,仓库中随包分发的模板 hooks/hooks.json 也声明了这三个事件,但它使用${CURSOR_PLUGIN_ROOT}变量,仅适用于安装在~/.cursor/plugins下的场景;而init会改写成工作区相对路径,确保不依赖该环境变量也能运行。
快速开始
# 1. 安装插件 pip install hindsight-cursor cd /path/to/your-project # 2a. 连接 Hindsight Cloud(最快——无需本地服务器) hindsight-cursor init --api-url https://api.hindsight.vectorize.io --api-token YOUR_HINDSIGHT_API_TOKEN # 2b. 或连接本地 Hindsight 服务器 hindsight-cursor init --api-url http://localhost:8888 # 3. 完全退出并重新打开 Cursor —— 插件在启动时加载⚠️重要:如果向一个已经打开的 Cursor 工作区添加插件,必须完全退出 Cursor 后重新打开。插件在启动时加载,仅刷新窗口(window reload)不够。
获取 Hindsight 服务端
两种方式任选其一:
方式一:Hindsight Cloud。注册获得 API Token 后,在init时通过--api-url与--api-token传入。
方式二:本地 Docker 自托管:
export OPENAI_API_KEY=your-key docker run --rm -it --pull always -p 8888:8888 \ -e HINDSIGHT_API_LLM_API_KEY=$OPENAI_API_KEY \ -e HINDSIGHT_API_LLM_MODEL=gpt-4o-mini \ -v $HOME/.hindsight-docker:/home/hindsight/.pg0 \ ghcr.io/vectorize-io/hindsight:latestinit命令做了什么
根据 cli.py 的cmd_init流程,init依次完成:
- 拷贝插件文件到项目下的
.cursor-plugin/hindsight-memory/(文件清单定义在_PLUGIN_FILES,共 16 个文件,包含 Hook 脚本、settings.json、规则文件与技能文件)。源码注释强调:任何文件缺失都会中止安装并报错——因为session_start.py会 importlib/下所有模块,缺一个文件就会让每次 Hook 调用变成静默 ImportError; - 写入/合并项目的
.cursor/hooks.json,让 Cursor 注册 Hook。_setup_hooks()是幂等的:已有用户的 Hook 会被保留,重复执行init只替换 Hindsight 自己的条目(通过_HOOK_MARKER = ".cursor-plugin/hindsight-memory"识别归属)。注意 Cursor 只从.cursor/hooks.json(工作区)或~/.cursor/hooks.json(用户级)加载 Hook——仅把文件丢进.cursor-plugin/是不够的; - 创建
~/.hindsight/cursor.json(若文件尚不存在),写入连接设置; - 写入
.cursor/mcp.json,配置 Hindsight 的 MCP 端点。_setup_mcp()使用单 bank 端点:{api_url}/mcp/{bank_id}/,并将Authorization: Bearer <token>写入请求头,使 recall / retain / reflect 工具自动限定在配置的 bank 内、无需每次传bank_id; --force:覆盖已有安装;--no-mcp:跳过 MCP 配置。
卸载:hindsight-cursor uninstall会全部还原——删除插件目录、从.cursor/hooks.json移除 Hindsight 条目、删除 MCP 服务器条目、删除生成的会话规则文件以及对应的.gitignore行。其中_remove_session_rules()的存在是有讲究的:会话规则文件会在每次sessionStart时重新生成,若卸载后残留,其alwaysApply: true属性会让已死会话的记忆继续注入每一次 Agent 轮次。
核心特性
- 会话回忆(Session recall)——每个会话开始时,向 Hindsight 查询项目相关记忆,通过
additionalContext注入上下文(对聊天界面不可见,对 Agent 可见); - 自动保留(Auto-retain)——每个任务完成后,提取会话内容并存储到 Hindsight 长期记忆;
- 按需 MCP 工具——
recall、retain、reflect三个工具支持会话中途的显式记忆操作; - 按需回忆技能(Skill)——
hindsight-recall技能支持手动记忆查询; - 守护进程管理——可自动启停本地
hindsight-embed,或连接外部 Hindsight 服务器; - 动态 Bank ID——支持按 Agent、按项目、按会话隔离记忆;
- 零运行时依赖——插件脚本仅使用 Python 标准库。
架构:三个 Hook 事件如何协同
插件构建在 Cursor 的 Hook 系统之上,具体事件分工如下:
| Hook | 事件 | 用途 |
|---|---|---|
session_start.py | sessionStart | 会话回忆——查询记忆,注入为additionalContext |
retain.py | stop | 自动保留——提取会话文本,POST 到 Hindsight |
retain.py | sessionEnd | 最终冲刷——保留轮次窗口未能覆盖的尾部内容 |
会话回忆(sessionStart)
sessionStart事件在每个新 Cursor 会话开始时触发一次,执行一次广谱的项目级回忆并把相关记忆注入为隐藏上下文。查看 session_start.py 的实现,其完整流程是:
- 从 stdin 读取 Hook 输入(
workspace_roots、conversation_id等); - 解析 API 地址(外部 API / 已有本地服务 / 自动启动守护进程,见下文"连接模式");
- 派生 Bank ID(静态或基于项目上下文动态派生,见 bank.py);
- 首次使用时确保 Bank Mission 已设置(ensure_bank_mission);
- 基于工作区上下文构造广谱查询——项目名来自
workspace_roots的 basename,叠加配置的bankMission,并以recallMaxQueryChars(默认 800)截断; - 调用 Hindsight 回忆 API(超时 10 秒,参数含
max_tokens、budget、types); - 将记忆格式化为
<hindsight_memories>块,输出additionalContext; - 写入
last_recall.json状态文件。
值得注意的一个健壮性细节:脚本总是以退出码 0 结束(任何错误都优雅降级),避免 Hook 失败反过来干扰 Cursor 的正常会话启动。
自动保留与最终冲刷(stop + sessionEnd)
retain.py同时注册在stop与sessionEnd两个事件上,这是有明确原因的——只看 retain.py 的实现与注释:
stop在每次 Agent 循环结束时触发,是周期性自动保留的合适粒度,但每次触发都要过轮次闸门(retainEveryNTurns)。默认值为 10 时,一段 7 轮的对话会触发 7 次stop、被闸门拦下 7 次,最终永远不会被存储;sessionEnd在对话结束时触发一次,携带相同的transcript_path,被当作最终冲刷(final flush):它绕过轮次窗口,无论会话停在哪一轮,尾部内容都会被保留。
两者在会话末尾重叠:插件为每个会话维护一个已保留消息数的水位线(retained.json,见 state.py),当一次调用发现没有新增消息时直接跳过,因此重叠不会导致重复存储。
其他值得展开的实现细节:
- 转录读取兼容三种格式:扁平式(
{role, content})、类型嵌套式({type, message: {...}})以及 Cursor 3.x 的角色嵌套式({role, message: {content: [blocks...]}})。注释明确指出 Cursor 3.6.31 实际写入~/.cursor/projects/<workspace>/agent-transcripts/<conv>/<conv>.jsonl的就是角色嵌套格式,早期解析器因不认识该结构会在每个 stop 钩子上静默丢弃全部内容(empty_transcript问题); - 文档 ID 去重:
document_id = "{session_id}-{毫秒时间戳}",保证同一会话内多次保留写入的是不同文档而非互相覆盖——旧设计在 full-session 模式下用session_id作文档 ID,多轮会话重复保留时会静默丢弃早期轮次; - 防反馈循环:保留前会剥离
<hindsight_memories>/<relevant_memories>块(见 content.py),避免把回忆注入的内容当作新记忆再次存储。
一个上游竞态的绕行方案
Cursor 的sessionStartHook 虽然接受additionalContextJSON 输出,但在 Agent 的 composer 句柄就绪前会静默丢弃该内容——这是 Cursor 官方论坛确认的竞态问题,在 Cursor 3.6.31 中仍存在。插件的绕行方案(见 rules_file.py)是:把回忆到的记忆写入工作区.cursor/rules/hindsight-session.mdc,该文件带alwaysApply: true前置元数据,规则引擎会可靠地把内容注入 Agent 上下文。每次sessionStart开头会先轮换(删除)旧规则文件,避免上一会话的过期记忆残留;若工作区是 Git 仓库,还会把该规则文件追加进.gitignore。同时 Hook 仍会输出additionalContext以兼容未来修复后的原生路径。
Skill 与 Rule
init还会安装两个配套资产:
- 技能(Skill):hindsight-recall/SKILL.md——按需记忆查询;
- 规则(Rule):rules/hindsight-memory.mdc——常驻规则,指示 Agent 善用回忆到的记忆与 MCP 工具。
三种连接模式
插件通过 daemon.py 的get_api_url()按优先级解析 API 地址:
1. 外部 API(生产环境推荐)
连接一个正在运行的 Hindsight 服务器(云端或自托管)。无需本地 LLM——事实提取由服务端完成。
{ "hindsightApiUrl": "https://your-hindsight-server.com", "hindsightApiToken": "your-token" }对应源码中的 Mode 1:显式配置的hindsightApiUrl优先级最高,直接返回。
2. 本地守护进程(自动托管)
插件通过uvx自动启停hindsight-embed。本地事实提取需要 LLM 提供方的 API Key:
export OPENAI_API_KEY="sk-your-key" # 或 export ANTHROPIC_API_KEY="your-key"模型由 Hindsight API 自动选择,可用HINDSIGHT_LLM_MODEL覆盖。注意这是需要显式开启的模式:useLocalDaemon: true(对应源码 Mode 3)。守护进程启动流程在 daemon.py 中分三步:profile create创建cursor配置(--merge --port <port>并注入 LLM 环境变量与 5 分钟空闲超时)→daemon --profile cursor start启动 → 每 1 秒探测一次/health,最多 30 秒等待就绪。macOS 上还会额外设置HINDSIGHT_API_EMBEDDINGS_LOCAL_FORCE_CPU=1与HINDSIGHT_API_RERANKER_LOCAL_FORCE_CPU=1强制 CPU 推理。
3. 已有本地服务器
如果hindsight-embed已在运行(对应源码 Mode 2),保持hindsightApiUrl为空、把apiPort设为服务器端口,插件会通过健康检查自动探测并复用,不重复启动守护进程。
兜底逻辑:当以上都不满足时(对应源码 Mode 4),插件回落到默认托管后端地址https://api.hindsight.vectorize.io(定义于 config.py)。这与全项目"默认上云"的跨集成约定一致:全新安装、零配置也能直连托管后端;自托管用户通过设置显式hindsightApiUrl或useLocalDaemon: true回到本地路径。
LLM 提供方检测
本地守护进程模式需要 LLM 做事实提取,检测优先级见 llm.py:
HINDSIGHT_API_LLM_PROVIDER等HINDSIGHT_API_LLM_*环境变量(最高优先级);- 插件配置
llmProvider/llmModel/llmApiKeyEnv; - 从标准环境变量自动检测:
OPENAI_API_KEY→ANTHROPIC_API_KEY→GEMINI_API_KEY→GROQ_API_KEY(ollama、openai-codex、claude-code、github-copilot无需 API Key,但必须显式指定); - 外部 API 模式——服务端处理 LLM,本地无需配置。
配置详解
所有设置都保存在~/.hindsight/cursor.json,每一项也都可以用环境变量覆盖。插件内置了合理的默认值(见 settings.json 与 config.py 中的DEFAULTS字典),通常你只需配置想要改变的部分。
加载顺序(后加载者胜出,见load_config()实现):
- 内置默认值(硬编码在插件中);
- 插件
settings.json(随插件分发,位于CURSOR_PLUGIN_ROOT/settings.json); - 用户配置
~/.hindsight/cursor.json(推荐在此覆盖); - 环境变量。
环境变量映射与类型转换定义在 config.py 的ENV_OVERRIDES:布尔值接受true/1/yes,数值做整数转换,转换失败则静默忽略该覆盖。
连接与守护进程
| 配置项 | 环境变量 | 默认值 | 说明 |
|---|---|---|---|
hindsightApiUrl | HINDSIGHT_API_URL | ""(空) | 外部 Hindsight API 服务器地址。为空时插件改用本地守护进程(或按上文兜底逻辑回落托管后端)。 |
hindsightApiToken | HINDSIGHT_API_TOKEN | null | 外部 API 的认证令牌,仅在设置了hindsightApiUrl时需要。 |
apiPort | HINDSIGHT_API_PORT | 9077 | 本地hindsight-embed守护进程使用的端口。 |
embedVersion | HINDSIGHT_EMBED_VERSION | "latest" | 通过uvx安装的hindsight-embed版本。 |
embedPackagePath | HINDSIGHT_EMBED_PACKAGE_PATH | null | 本地hindsight-embed开发目录路径(此时改用uv run --directory <path> hindsight-embed)。 |
useLocalDaemon | HINDSIGHT_USE_LOCAL_DAEMON | false | 是否让插件自动启动本地守护进程。默认 false:空hindsightApiUrl会回落托管后端;设为 true 则恢复"自动起本地 daemon"的经典行为。 |
daemonIdleTimeout | HINDSIGHT_DAEMON_IDLE_TIMEOUT | 300 | 守护进程空闲超时(秒),映射为HINDSIGHT_EMBED_DAEMON_IDLE_TIMEOUT。 |
useRulesFileFallback | HINDSIGHT_USE_RULES_FILE_FALLBACK | true | 是否启用.cursor/rules/hindsight-session.mdc规则文件绕行方案(针对 Cursor 的additionalContext竞态)。 |
appendToGitignore | HINDSIGHT_APPEND_TO_GITIGNORE | true | 是否把生成的会话规则文件追加进.gitignore。 |
LLM 提供方(仅本地守护进程模式)
这些设置配置本地守护进程用于事实提取的 LLM。连接外部 API 时被忽略(服务端负责 LLM)。
| 配置项 | 环境变量 | 默认值 | 说明 |
|---|---|---|---|
llmProvider | HINDSIGHT_LLM_PROVIDER | 自动检测 | LLM 提供方:openai、anthropic、gemini、groq、ollama。通过检测 API Key 环境变量自动判断。 |
llmModel | HINDSIGHT_LLM_MODEL | 提供方默认 | 覆盖所选提供方的默认模型。 |
llmApiKeyEnv | — | 提供方标准 | 存放 API Key 的环境变量名(非标准场景)。 |
记忆 Bank
Bank 是隔离的记忆存储——好比一个独立的"大脑"。
| 配置项 | 环境变量 | 默认值 | 说明 |
|---|---|---|---|
bankId | HINDSIGHT_BANK_ID | "cursor" | dynamicBankId为false时使用的 Bank ID。 |
bankMission | HINDSIGHT_BANK_MISSION | 通用助手提示 | 对 Agent 身份与用途的描述(settings.json中自带一段针对 Cursor 编程助手的默认使命文本)。 |
retainMission | — | null | 保留阶段的提取指令,如"提取技术决策、架构选择、用户偏好……忽略日常寒暄"。 |
dynamicBankId | HINDSIGHT_DYNAMIC_BANK_ID | false | 为true时,根据上下文字段派生唯一 Bank ID(见dynamicBankGranularity)。 |
dynamicBankGranularity | — | ["agent", "project"] | 用于派生动态 Bank ID 的字段组合:agent、project、session、channel、user。 |
bankIdPrefix | — | "" | 前缀字符串,加在一切 Bank ID 前做命名空间隔离。 |
agentName | HINDSIGHT_AGENT_NAME | "cursor" | 动态 Bank ID 派生中agent字段使用的名称。 |
动态 Bank ID 的派生实现见 bank.py:各字段取值后经 URL 编码,用::连接(如cursor::myproject);project取cwd的 basename、session取conversation_id、channel默认default、user默认anonymous(后两者可分别通过HINDSIGHT_CHANNEL_ID、HINDSIGHT_USER_ID环境变量注入)。
会话回忆(Session Recall)
会话回忆在每次会话开始时运行一次:向 Hindsight 查询项目相关记忆,以不可见的additionalContext注入 Agent 上下文。
| 配置项 | 环境变量 | 默认值 | 说明 |
|---|---|---|---|
autoRecall | HINDSIGHT_AUTO_RECALL | true | 会话回忆总开关。 |
recallBudget | HINDSIGHT_RECALL_BUDGET | "mid" | 搜索彻底程度:"low"、"mid"、"high"。 |
recallMaxTokens | HINDSIGHT_RECALL_MAX_TOKENS | 1024 | 回忆记忆块的最大 token 数。 |
recallTypes | — | ["world", "experience"] | 要检索的记忆类型。 |
recallMaxQueryChars | HINDSIGHT_RECALL_MAX_QUERY_CHARS | 800 | 查询字符串最大字符数。 |
recallContextTurns | HINDSIGHT_RECALL_CONTEXT_TURNS | 1 | 回忆时考虑的上下文轮数。 |
recallPromptPreamble | — | 见settings.json | 注入记忆块前的前缀提示词(默认提示 Agent 优先采纳近期记忆、只使用对继续对话有用的记忆)。 |
自动保留(Auto-Retain)
自动保留在 Agent 完成任务后运行:提取会话文本并发送到 Hindsight。
| 配置项 | 环境变量 | 默认值 | 说明 |
|---|---|---|---|
autoRetain | HINDSIGHT_AUTO_RETAIN | true | 自动保留总开关。 |
retainMode | HINDSIGHT_RETAIN_MODE | "full-session" | 保留策略:"full-session"或"chunked"。 |
retainEveryNTurns | HINDSIGHT_RETAIN_EVERY_N_TURNS | 10 | 保留频率。1= 每轮都保留。 |
retainOverlapTurns | — | 2 | 分块模式下,为保持连续性额外包含上一块的轮数。 |
retainContext | HINDSIGHT_RETAIN_CONTEXT | "cursor" | 保留记忆的来源标签(Hindsight 按来源聚类记忆,例如claude-code与手动保留区分)。 |
retainToolCalls | — | false | 保留的转录中是否包含工具调用。为true时输出完整 JSON 结构化消息(含 tool_use 输入与截断到 2000 字符的 tool_result);为false时输出带[role: ...]...[role:end]标记的文本格式。 |
retainTags | — | ["{session_id}"] | 附加标签,支持{session_id}、{bank_id}、{timestamp}模板变量替换。 |
retainMetadata | — | {} | 附加元数据,同样支持模板变量;插件还会自动写入retained_at、message_count、session_id。 |
分块模式的细节值得注意(见 retain.py):周期触发时按"用户消息边界"向后切出retainEveryNTurns + retainOverlapTurns轮的窗口;而sessionEnd冲刷时没有轮次窗口可切,直接保留水位线之后的新增消息,保证块之间互不重叠。
调试
| 配置项 | 环境变量 | 默认值 | 说明 |
|---|---|---|---|
debug | HINDSIGHT_DEBUG | false | 向 stderr 输出详细日志,以[Hindsight]前缀标记。 |
验证 Hook 是否生效
插件在每次 Hook 调用时都会写状态文件——即使没有找到记忆或保留被跳过。检查它们即可确认 Hook 在正常触发:
# 未设置 CURSOR_PLUGIN_DATA 时的默认位置: cat ~/.hindsight/cursor-state/state/last_recall.json cat ~/.hindsight/cursor-state/state/last_retain.json每个文件包含:
saved_at——上次调用的时间戳;status——success、empty、skipped或error之一;bank_id——使用的 Bank(success与empty时出现);mode——恒为plugin;hook——回忆文件为sessionStart;result_count(回忆)或message_count(保留)——success时出现。
如果使用 Cursor 时saved_at在更新,说明 Hook 在触发;再看status判断发生了什么。状态写入实现在 state.py,而各状态字段由 session_start.py 与 retain.py 填充——例如保留被轮次闸门拦下时会记录status: "skipped"、reason: "turn_window"、turn与next_at。
常见问题排查
插件未激活:检查插件目录下是否存在.cursor-plugin/plugin.json。在~/.hindsight/cursor.json中开启"debug": true,查看 stderr 输出。
Agent 窗口出现 "Ran Recall in hindsight"?那是 MCP,不是插件。插件式回忆是静默的——通过additionalContext注入上下文,没有可见的工具调用。如果看到显式的 Hindsight 工具调用,说明你在.cursor/mcp.json中配置了 MCP。两者可以共存协同工作。
回忆返回空:确认 Hindsight 服务器可达(curl http://localhost:9077/health)。记忆至少需要完成一次保留周期才会被检索到。
守护进程启动失败:确保设置了 LLM API Key。查看守护进程日志~/.hindsight/profiles/cursor.log。
会话启动延迟高:会话回忆 Hook 有 15 秒超时。可改用recallBudget: "low"或调低recallMaxTokens。
深入阅读
本集成的全部源码、默认配置与测试均位于仓库 hindsight-integrations/cursor:
- CLI 与安装逻辑:hindsight_cursor/cli.py——
init/uninstall、Hook 注册表生成、MCP 配置合并; - Hook 脚本:scripts/session_start.py、scripts/retain.py;
- 运行库:config.py(配置加载)、daemon.py(连接模式与守护进程)、client.py(REST 客户端,recall / retain / set_bank_mission 端点)、bank.py(Bank ID 派生)、content.py(转录格式化与记忆标签剥离)、rules_file.py(规则文件绕行方案)、llm.py(LLM 检测);
- 默认配置:settings.json;Hook 模板:hooks/hooks.json;
- 配套资产:rules/hindsight-memory.mdc、skills/hindsight-recall/SKILL.md;
- 测试用例:tests——覆盖配置加载与覆盖(test_config.py)、CLI 安装/卸载(test_cli.py)、Bank ID 派生(test_bank.py)、转录内容处理(test_content.py)、守护进程生命周期(test_daemon.py)、Hook 注册(test_hooks.py)、规则文件(test_rules_file.py)及端到端流程(test_e2e.py)。
如果你希望用同样的记忆能力打通其他编程工具,可在 hindsight-integrations/README.md 中查看本仓库支持的全部分支,例如 Claude Code、Codex、OpenHands、Continue、Cursor CLI 等;对应的文档均收录在 hindsight-docs/docs-integrations。
【免费下载链接】hindsightHindsight: Agent Memory That Learns项目地址: https://gitcode.com/GitHub_Trending/hindsight2/hindsight
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考