examples/claude-code-memory-plugin/README_CN.md
为 Claude Code 提供长期语义记忆,由 OpenViking 驱动。每次用户输入前自动召回相关记忆,每轮对话结束后自动捕获上下文——模型不需要主动调用任何 MCP 工具。
插件可直接从仓库自带的 marketplace catalog 安装,无需单独的分发仓库。两条命令的远程安装方式见下文手动安装。
bash <(curl -fsSL https://raw.githubusercontent.com/volcengine/OpenViking/main/examples/memory-plugin-shared/install.sh) --harness claude
仅支持 macOS 和 Linux。Claude Code 和 Codex 共用这一个安装脚本(去掉 --harness claude 可交互勾选):它会依次询问界面语言(English/中文)、下载源(GitHub,或 GitHub 受限地区用 TOS 镜像——传 --dist tos)和 OpenViking 凭据,然后从远程 marketplace 安装 openviking-memory。stdio MCP 代理运行时读取 ovcli.conf,不再需要 shell wrapper 或 .mcp.json 渲染。重复执行安全。
如果你更喜欢手动操作,按下面四步走。
本地起一个或者指向远程:快速开始指南 涵盖两种模式,也讲了远程使用时怎么签发 API key。默认端口 1933;本地模式无需鉴权。
验证服务能通:
curl http://localhost:1933/health # 或者你的远程 URL
最简单的方式——写 ~/.openviking/ovcli.conf(也是 ov CLI 用的同一个文件):
{
"url": "https://your-openviking-server.example.com",
"api_key": "<your-api-key>",
"account": "my-team",
"user": "alice"
}
如果是纯本地模式(http://127.0.0.1:1933,无鉴权),这一步可以跳过——插件会静默走本地默认值。
如果你已经在维护 ov.conf,插件也读它——完整优先级链和按字段覆盖见下方 配置。
远程 marketplace(推荐) —— 无需 clone 仓库。仓库根目录自带 .claude-plugin/marketplace.json,其条目通过 git-subdir 拉取本插件:
claude plugin marketplace add https://raw.githubusercontent.com/volcengine/OpenViking/main/.claude-plugin/marketplace.json
claude plugin install openviking-memory@openviking
(claude plugin marketplace add volcengine/OpenViking 也可以,但会把整个仓库 clone 下来作为 marketplace。)
如果跳过了第 2 步,装完后再配置连接:手写 ~/.openviking/ovcli.conf、运行插件自带的交互向导 node <插件目录>/scripts/setup.mjs,或直接跑一行安装脚本。
本地目录(开发用) —— 注册当前 checkout,scripts/、hooks/ 的修改下次 hook 触发即生效、无需重装。在 OpenViking 仓库根目录:
claude plugin marketplace add "$(pwd)/examples"
claude plugin install openviking-memory@openviking
两条命令默认都装在 user scope —— 插件在任何目录下都生效。这里不显式传
--scope user,因为老的 Claude Code 2.0.x(比如 2.0.76)不识别这个 flag 会直接报错。在支持--scope的新版本上,如果装完发现落到了 local scope,可以跑一次claude plugin enable openviking-memory@openviking --scope user提升到 user scope。目录模式注意:移动 / 重命名 / 删除源码目录,或
git checkout到不含这些文件的分支,会立刻让插件失效。两种模式注册的 marketplace 都叫openviking,插件 id 恒为openviking-memory@openviking;切换模式时先移除 marketplace 再添加另一个来源(安装脚本会自动处理)。
claude plugin 子命令是 Claude Code 2.0(2025-10)才引入的。再老的版本只有 claude mcp add 和 hooks 系统,但仍然能手动接出同样的功能:
PLUGIN_DIR="$(pwd)/examples/claude-code-memory-plugin"
# stdio MCP 代理 —— 自己读 ovcli.conf / OPENVIKING_*,不再需要拼 header。
claude mcp remove openviking -s user 2>/dev/null
claude mcp add --scope user openviking -- node "$PLUGIN_DIR/servers/mcp-proxy.mjs"
# 把插件 hooks 合并进 ~/.claude/settings.json(自动备份)
mkdir -p ~/.claude && [ -f ~/.claude/settings.json ] || echo '{}' > ~/.claude/settings.json
cp -p ~/.claude/settings.json ~/.claude/settings.json.bak.$(date +%s)
sed "s|\${CLAUDE_PLUGIN_ROOT}|$PLUGIN_DIR|g" "$PLUGIN_DIR/hooks/hooks.json" > /tmp/ov-hooks.json
jq --slurpfile h /tmp/ov-hooks.json '.hooks = ((.hooks // {}) * $h[0].hooks)' \
~/.claude/settings.json > /tmp/ov-settings.json
jq -e . /tmp/ov-settings.json >/dev/null && mv /tmp/ov-settings.json ~/.claude/settings.json
rm -f /tmp/ov-hooks.json
一行安装脚本在检测到 2.0 之前的版本时会自动执行以上流程(并在 ~/.openviking/openviking-repo 保留一份源码 checkout 供上面的绝对路径引用)。
claude
如果插件似乎没在工作,开 OPENVIKING_DEBUG=1 看 ~/.openviking/logs/cc-hooks.log。
插件的 hook 和 MCP 条目现在使用同一条配置链。仓库里的 .mcp.json 会把 servers/mcp-proxy.mjs 作为本地 stdio MCP server 启动;这个代理读取 OPENVIKING_*、~/.openviking/ovcli.conf 和 ~/.openviking/ov.conf,再把 JSON-RPC 转发到 OpenViking 服务端原生 /mcp endpoint,并补齐认证与身份头。
正常插件安装不需要额外 export,也不需要渲染 .mcp.json。更新 ovcli.conf 或相关 OPENVIKING_* 环境变量后重启 Claude Code,代理会和 hook 脚本命中同一个 OpenViking 目标。
代理要求 Node.js 18+。只有在 OPENVIKING_DEBUG=1 或 claude_code.debug=true 时才写 debug log;stdout 严格保留给 MCP 协议输出。
每个插件字段按从高到低:
OPENVIKING_*——见下方表格)ovcli.conf — CLI 客户端配置(~/.openviking/ovcli.conf 或 OPENVIKING_CLI_CONFIG_FILE);只承载连接字段(url、api_key、account、user)ov.conf — 服务器配置(~/.openviking/ov.conf 或 OPENVIKING_CONFIG_FILE);插件读 server.url、server.root_api_key,以及可选的遗留 claude_code 块(见 遗留 claude_code 块)http://127.0.0.1:1933,无鉴权)同一组连接与身份字段也会被 stdio MCP 代理使用。
插件全部行为均可通过 env vars 配置。连接 / 身份变量同时影响 hook 和 MCP 代理;调优变量仅影响 hook。
| 环境变量 | 说明 |
|---|---|
OPENVIKING_URL / OPENVIKING_BASE_URL | 完整服务器 URL(如 https://remote.example.com) |
OPENVIKING_API_KEY / OPENVIKING_BEARER_TOKEN | API key;以 Authorization: Bearer <key> 发送 |
OPENVIKING_ACCOUNT | 多租户 account(X-OpenViking-Account 头) |
OPENVIKING_USER | 多租户 user(X-OpenViking-User 头) |
OPENVIKING_PEER_ID | 可选的稳定 peer,用于自动召回和 session message 写入 |
设置 OPENVIKING_PEER_ID 后,数据面的 recall/profile 请求会把它作为 X-OpenViking-Actor-Peer 发送;捕获到 session message 时仍写入 body peer_id。未显式配置 peer 时,subagent 捕获会回退到 Claude 的 agent_id,让不同 subagent 默认落到不同 peer memory。
| 环境变量 | 默认值 | 说明 |
|---|---|---|
OPENVIKING_AUTO_RECALL | true | 启用每轮自动召回 |
OPENVIKING_RECALL_LIMIT | 6 | 每轮最多注入的记忆条数 |
OPENVIKING_RECALL_TOKEN_BUDGET | 2000 | 内联内容的 token 预算;超出预算的项降级为 URI hint |
OPENVIKING_RECALL_MAX_CONTENT_CHARS | 500 | 单条记忆内容字符上限 |
OPENVIKING_RECALL_PREFER_ABSTRACT | true | 有 abstract 时优先用 abstract 而非完整 body |
OPENVIKING_SCORE_THRESHOLD | 0.35 | 最低相关度得分(0–1) |
OPENVIKING_MIN_QUERY_LENGTH | 3 | 短于此长度的 query 跳过召回 |
OPENVIKING_LOG_RANKING_DETAILS | false | 每候选打分日志(很啰嗦) |
| 环境变量 | 默认值 | 说明 |
|---|---|---|
OPENVIKING_AUTO_CAPTURE | true | 启用自动捕获;同时 gate 写 hook(PreCompact / SessionEnd / SubagentStop) |
OPENVIKING_CAPTURE_MODE | semantic | semantic(总是捕获)或 keyword(基于触发词) |
OPENVIKING_CAPTURE_MAX_LENGTH | 24000 | 捕获判定时 sanitized 文本的长度上限 |
OPENVIKING_CAPTURE_ASSISTANT_TURNS | true | 捕获 assistant 回合(文本 + tool 输入/输出)。设为 0 可退回仅用户 |
OPENVIKING_COMMIT_TOKEN_THRESHOLD | 20000 | client-driven commit 的 pending-token 阈值 |
OPENVIKING_RESUME_CONTEXT_BUDGET | 32000 | resume 时拉取 archive overview 的 token 预算 |
| 环境变量 | 默认值 | 说明 |
|---|---|---|
OPENVIKING_TIMEOUT_MS | 15000 | 召回 + 通用请求 HTTP 超时(ms) |
OPENVIKING_CAPTURE_TIMEOUT_MS | 30000 | 捕获路径 HTTP 超时(须低于 Stop hook 超时) |
OPENVIKING_WRITE_PATH_ASYNC | true | 把写 hook detach 到后台 worker,避免 CC 等待 commit RTT |
OPENVIKING_BYPASS_SESSION | false | 一次性:1/true=当前进程所有 hook 直接放行 |
OPENVIKING_BYPASS_SESSION_PATTERNS | "" | CSV 的 glob 模式,匹配 session_id 或 cwd |
OPENVIKING_MEMORY_ENABLED | (auto) | 0/false/no=强制禁用;1/true/yes=强制启用 |
OPENVIKING_DEBUG | false | 1/true=向 ~/.openviking/logs/cc-hooks.log 输出 debug 日志 |
OPENVIKING_DEBUG_LOG | ~/.openviking/logs/cc-hooks.log | 覆盖日志路径 |
OPENVIKING_CONFIG_FILE | ~/.openviking/ov.conf | 覆盖 ov.conf 路径 |
OPENVIKING_CLI_CONFIG_FILE | ~/.openviking/ovcli.conf | 覆盖 ovcli.conf 路径 |
纯环境变量启动(无需配置文件):
OPENVIKING_MEMORY_ENABLED=1 \
OPENVIKING_URL=https://openviking.example.com \
OPENVIKING_API_KEY=sk-xxx \
OPENVIKING_ACCOUNT=my-team \
OPENVIKING_USER=alice \
OPENVIKING_RECALL_LIMIT=8 \
claude
OPENVIKING_MEMORY_ENABLED 环境变量 — 0/false/no 强制禁用;1/true/yes 强制启用(无配置文件时强制启用,连接信息须由环境变量提供)ov.conf 的 claude_code.enabled — false 禁用ov.conf 或 ovcli.conf 存在则启用;否则静默禁用(不报错,hook 直接放行)在 /tmp PoC 目录里用 Claude Code 而不污染长期记忆:
# 持久:任何 session_id 或 cwd 命中模式的会话
export OPENVIKING_BYPASS_SESSION_PATTERNS='/tmp/**,**/scratch/**,/Users/me/Dev/throwaway/*'
# 或一次性:
OPENVIKING_BYPASS_SESSION=1 claude
bypass 命中时所有 hook 直接放行,不联系 OpenViking。
claude_code 块(在 ov.conf 里)早期插件版本把调优字段配在 ~/.openviking/ov.conf 的 claude_code 块里。出于向后兼容,这种方式仍能用——上面每个 env var 都有对应的 camelCase 字段(OPENVIKING_RECALL_LIMIT → claude_code.recallLimit、OPENVIKING_BYPASS_SESSION_PATTERNS → claude_code.bypassSessionPatterns JSON 数组等)。env vars 优先级更高。新部署应优先使用 env vars + shell rc——服务端配置文件不应承载每开发机自己的调优偏好。
hooks/hooks.json 默认值:
| Hook | 超时 | 备注 |
|---|---|---|
SessionStart | 120s | 充裕,因为 resume / compact 可能拉一个较大的 archive overview |
UserPromptSubmit | 8s | 自动召回必须快,prompt 提交不能被 hook 阻塞 |
Stop | 45s | 自动捕获要解析 transcript + 推 turn;async detach 让用户感知接近 0 |
PreCompact | 30s | 同步 commit,CC 紧接着会改 transcript |
SessionEnd | 30s | 最终 commit;async detach |
SubagentStart | 10s | 轻量:只持久化隔离 state |
SubagentStop | 45s | 读子 agent transcript 并 commit;async detach |
claude_code.captureTimeoutMs 须低于 Stop hook 超时,让脚本能优雅失败并仍能更新增量 state。
插件会在 Claude Code 输入框下方渲染一行 OpenViking 状态。安装脚本会把它注册到 ~/.claude/settings.json(CC 插件 manifest 不支持 statusLine 字段,必须走这条路)。
示例:
OV ✓ │ Fable 5 · ctx 42% │ ↩ 6 mem (0.92) · 50ms 注入 6 条记忆;模型 + 上下文占比
OV ⚠ slow 探针超过 1s 预算(服务器可能在抽风)
OV ✗ offline 服务器不可达
OV ⚡ bypass │ Fable 5 · ctx 42% 命中 OPENVIKING_BYPASS_SESSION*
OV ✓ │ ✎ 573/20k · 2 arch 待提交进度 + 本 session 已归档 2 次
OV ✓ │ 🔗 resumed │ +3 today session 已恢复上下文;今日累计归档 3 次
ctx 百分比复刻 Claude Code 原生上下文指示器(自定义 statusLine 会替换掉原生那条),配色阈值与原生一致:<70% 灰、70–89% 黄、≥90% 红。不想显示可设 OPENVIKING_STATUSLINE_CTX=off。
完整段位说明 + 个性化 recipe(隐藏段位、改色、与已有 statusline 组合、自定义段位),见 STATUSLINE.md。
数据来源:
auto-recall.mjs / auto-capture.mjs / session-start.mjs 每轮写快照到 ~/.openviking/state/{last-recall,last-capture,last-session-event,daily-stats}.json。scripts/statusline.mjs 读快照,再加 5 秒共享缓存的 GET /health。关闭 / 调整:
OPENVIKING_STATUSLINE=off ——不删注册,仅静默。NO_COLOR=1 或非 TTY ——自动去 ANSI 颜色。jq 'del(.statusLine)' ~/.claude/settings.json > t && mv t ~/.claude/settings.json。设置 claude_code.debug: true 或 OPENVIKING_DEBUG=1,hook 日志写到 ~/.openviking/logs/cc-hooks.log。
auto-recall 默认输出关键阶段 + 紧凑的 ranking_summaryclaude_code.logRankingDetails 设为 true,否则非常啰嗦scripts/debug-recall.mjs / scripts/debug-capture.mjs 单跑示例输入,不要长期开 hook 日志| 症状 | 原因 | 解决方案 |
|---|---|---|
| 插件没激活 | 找不到 ov.conf / ovcli.conf | 创建一个;或设 OPENVIKING_MEMORY_ENABLED=1 加上 URL/API_KEY 等环境变量 |
| Hook 触发但召回为空 | OpenViking 服务器没起 / URL 不对 | curl http://localhost:1933/health(或你的远程 URL) |
| 自动捕获抽取出 0 条记忆 | ov.conf 里 embedding/extraction 模型配错 | 检查 embedding / vlm 配置;看服务器日志 |
MCP 工具命中本地 127.0.0.1 而不是远程 | .mcp.json 仅解析 ${VAR},不读 ovcli.conf | 见 配置 MCP — export 环境变量或编辑 .mcp.json |
| 远程鉴权 401 / 403 | API key / account / user 头错配 | 核对 OPENVIKING_API_KEY、OPENVIKING_ACCOUNT、OPENVIKING_USER(或 ov.conf 对应字段) |
Stop hook 超时 | 服务器慢 + 同步写路径 | 保持 writePathAsync: true(默认),或调大 hooks/hooks.json 里的 Stop 超时 |
| 旧上下文反复出现在 OV 里 | 早期版本把召回块当成用户消息回写了 | 升级到当前版本——auto-capture 现在推送前会剥离 <openviking-context> |
| 日志太吵 | logRankingDetails: true 没关 | 设为 false;按需用 debug-recall.mjs / debug-capture.mjs |
Claude Code 自带 MEMORY.md 文件系统,本插件与之互补:
| 特性 | 内置 MEMORY.md | OpenViking 插件 |
|---|---|---|
| 存储 | 扁平 markdown | 向量数据库 + 结构化抽取 |
| 搜索 | 整体加载进上下文 | 语义相似度 + 排序 + token 预算 |
| 范围 | 单项目 | 跨项目、跨会话、peer 维度 |
| 容量 | ~200 行(受上下文限制) | 不受限(服务端存储) |
| 抽取 | 手写规则 | LLM 驱动的实体 / 偏好 / 事件抽取 |
| 子 agent | 与父共享 | 隔离 session + peer 维度捕获 |
┌────────────────────────────────────────────────────────────┐
│ Claude Code │
│ │
│ SessionStart UserPromptSubmit Stop PreCompact │
│ SessionEnd SubagentStart SubagentStop │
└────┬───────────────┬───────────────┬───────────┬───────────┘
│ │ │ │
│ ┌───────────▼───────────┐ │ │
│ │ hook 脚本 (.mjs) │ │ │ ┌──────────────┐
│ │ 读 transcript + │───┼───────────┼────►│ │
│ │ 调 OV HTTP API │ │ │ │ OpenViking │
│ └───────────────────────┘ │ │ │ Server │
│ │ │ │ (Python) │
│ ┌────────────▼───────────▼───►│ │
│ │ MCP tools (stdio proxy→/mcp) │
│ │ search / read / store / … │ │
└─────────────────►│ │ │
OV session └─────────────────────────────► │
context inject └──────────────┘
没有 TypeScript 编译步骤,也没有运行时 npm 引导。Hook 都是直接走 HTTP 调 OpenViking 的 .mjs 文件;MCP 使用 servers/mcp-proxy.mjs 作为零依赖 stdio 桥接,转发到 OpenViking 服务器自身的 /mcp endpoint。
首次接触时创建一个持久化的 OpenViking session,整个 Claude Code 会话期间复用。OV session ID 是 cc-<sha256(cc_session_id)>,所以 resume / compact / 多 hook 事件都打到同一个 session,OV 的 auto_commit_threshold 自然驱动归档与记忆抽取。
| Hook | 触发时机 | 行为 |
|---|---|---|
UserPromptSubmit | 每个用户回合 | 搜 OV → 排序 → 在 token 预算内注入 <openviking-context> 块 |
Stop | Claude 完成一次响应 | 解析 transcript → 把新的用户回合推到 OV session → pending tokens 超阈值时 commit |
SessionStart | 新建 / resume / compact 后的会话 | resume/compact 时拉取最新 archive overview 注入 |
PreCompact | Claude Code 重写 transcript 之前 | 在 CC 改 transcript 之前先把 pending 提交为归档 |
SessionEnd | Claude Code 会话关闭 | 最后一次 commit |
SubagentStart | 父 session 通过 Task 工具孵化子 agent | 为子 agent 派生隔离的 OV session ID,写 start state |
SubagentStop | 子 agent 结束 | 读子 agent transcript → 推到带子 agent peer 身份的隔离 session → commit |
Stop、SessionEnd、SubagentStop 用 detach-worker 模式:父 hook drain stdin,立刻向 stdout 输出 {decision:"approve"} 解封 Claude Code,然后 spawn 一个 detached 子进程做 HTTP commit。用户从不等 OV。PreCompact 必须保持同步,因为 Claude Code 紧接着会改 transcript。
调试时如果需要严格顺序,把 claude_code.writePathAsync 设为 false。
auto-capture 在把每个 turn 推给 OV 之前,会剥掉 <openviking-context>、``、<relevant-memories>、[Subagent Context] 这些注入块。否则插件本轮注入的召回上下文会在下一轮被当成"用户消息"再次写回 OV,形成自我引用的污染回路。
插件的 .mcp.json 启动本地 stdio 代理,代理再连到 OpenViking 服务器原生 HTTP MCP endpoint /mcp。服务器暴露 9 个 Claude 可按需调用的工具:
| 工具 | 说明 |
|---|---|
search | 跨 memories / resources / skills 的语义搜索 |
read | 读一个或多个 viking:// URI 的内容 |
list | 列出 viking:// 目录下条目 |
store | 把消息存到长期记忆(触发抽取) |
add_resource | 把本地文件 / URL 加为资源 |
grep | 在 viking:// 文件里做正则内容搜索 |
glob | 按 glob 模式匹配文件 |
forget | 删除任意 viking:// URI |
health | 检查 OpenViking 服务健康 |
工具参数详见 MCP 集成指南。
claude-code-memory-plugin/
├── .claude-plugin/
│ └── plugin.json # plugin manifest
├── hooks/
│ └── hooks.json # 7 个 hook 注册
├── servers/
│ └── mcp-proxy.mjs # stdio -> OpenViking /mcp 桥接
├── scripts/
│ ├── config.mjs # 共享配置加载(env > ovcli.conf > ov.conf)
│ ├── debug-log.mjs # 写 ~/.openviking/logs/cc-hooks.log
│ ├── auto-recall.mjs # UserPromptSubmit
│ ├── auto-capture.mjs # Stop
│ ├── session-start.mjs # SessionStart
│ ├── session-end.mjs # SessionEnd
│ ├── pre-compact.mjs # PreCompact
│ ├── subagent-start.mjs # SubagentStart
│ ├── subagent-stop.mjs # SubagentStop
│ ├── debug-recall.mjs # 召回独立诊断
│ ├── debug-capture.mjs # 捕获独立诊断
│ └── lib/
│ ├── ov-session.mjs # OV HTTP 客户端 + session 帮助 + bypass 检查
│ └── async-writer.mjs # 写路径 detach-worker 帮助
├── .mcp.json # MCP 配置(本地 stdio 代理)
├── package.json # 仅 type:module 标记,无运行时依赖
└── README.md
Apache-2.0 — 同 OpenViking。