OpenViking ZCode 记忆插件实践指南:基于 Hook 生命周期的长期记忆适配与增量会话捕获
OpenViking ZCode 记忆插件实践指南基于 Hook 生命周期的长期记忆适配与增量会话捕获【免费下载链接】OpenVikingSelf-evolving Context Database for AI Agents. Unify Agent Memory, Knowledge RAG and Skills.项目地址: https://gitcode.com/GitHub_Trending/op/OpenViking本文是一份针对 OpenViking 长期记忆系统在 ZCode 编程 Agent 上的接入指南。ZCode 是一款类 Claude Code 的 CLI Agent其 Hook 扩展面与 Claude Code 存在差异因此 OpenViking 以“复用共享运行时 薄适配层”的方式提供了zcode-memory-plugin通过SessionStart、UserPromptSubmit、PreToolUse、Stop四个生命周期事件实现用户画像注入、记忆召回、viking://URI 防护与会话增量提交。读完本文你将掌握该插件的安装方式、Hook 事件语义、配置式 Hook 的安装原理以及基于 rollout 文件的去重与游标推进机制。插件定位与适用前提examples/zcode-memory-plugin是一个“生命周期适配器lifecycle adapter”它不重复实现任何记忆逻辑而是直接复用examples/memory-plugin-shared共享运行时——所有召回recall、批量写入、待处理队列、凭据解析和 MCP 代理能力都来自共享库本插件新增的只是一层 ZCode 专属的薄适配层。前置要求需要部署支持viking://~home-alias 的 OpenViking 服务端。插件通过viking://~/memories和viking://~/skills定位调用者自身的上下文空间新版本服务端已拒绝无 uid 的viking://user/memories简写形式。插件元数据定义在 openviking.integration.jsonid为openviking-memoryversion为0.1.2面向客户端zcode声明能力为hooksmcp。四个 Hook 事件ZCode 生命周期下的记忆闭环ZCode 共支持 7 个 Hook 事件SessionStart、UserPromptSubmit、PreToolUse、PermissionRequest、PostToolUse、PostToolUseFailure、Stop但不支持PreCompact、SessionEnd、Notification、SubagentStart、SubagentStop。因此本插件只接入其中 4 个事件构成完整的记忆闭环事件触发时机插件行为SessionStart会话开始注入用户画像、偏好与实体到上下文UserPromptSubmit用户提交 prompt搜索 OpenViking 相关记忆并注入PreToolUseRead\|Glob\|Grep工具调用前拦截viking://URI 直接访问引导使用 MCP 工具Stop会话一轮结束立即返回在 detached worker 中捕获增量用户/助手对话并提交 OpenViking 会话其中Stop事件承担了最关键的任务由于 ZCode 缺少PreCompact/SessionEnd这类“结束”信号插件采用在Stop时 commit的策略来补偿——Stop触发时父进程先 detachmaybeDetach让网络写入在子进程中异步进行避免阻塞 ZCode 本身。安装使用共享安装器插件通过examples/memory-plugin-shared/install.sh统一安装该脚本同时支持 claude、codex、cursor、trae、trae-cn、trae-cli、zcode、opencode、pi、dsh 共 10 种 harnessbash examples/memory-plugin-shared/install.sh --harness zcode安装器的工作流程如下检测通过~/.zcode/目录或 PATH 中的zcode二进制判断 ZCode 是否可用合并配置将 hooks 与 MCP 配置合并写入~/.zcode/cli/config.jsonuser scope 的mcp.servers与hooks区块写入凭据将 OpenViking 服务地址与 API Key 写入~/.openviking/ovcli.conf文件权限 600。脚本还支持丰富的非交互参数适合 CI 或脚本化部署bash examples/memory-plugin-shared/install.sh \ --harness zcode \ --dist github \ --lang en \ --url http://127.0.0.1:1933 \ --api-key KEY \ --account ACCOUNT \ --user USER常用参数说明参数含义默认值--harness LIST逗号分隔的客户端列表自动检测--dist CHANNEL分发渠道github默认或tos火山引擎 TOS 镜像适用于无法访问 GitHub 的区域github--lang LANG交互提示语言en/zh自动检测--url URLOpenViking 服务端 base URL交互询问--api-key KEYOpenViking API Key传空字符串表示本地免鉴权模式交互询问--account/--user可选的 OpenViking 账号与用户标识空--source MODE高级选项remote/archive/dev自动检测--uninstall移除 ZCode 集成文件与配置否架构剖析vendored 共享运行时 事件分发插件将共享运行时通过sync.mjsvendor拷贝到本地的scripts/shared/目录——这与 Claude Code、Codex 插件保持一致TRAE/Cursor 则使用跨目录相对路径引用。之所以选择纯 vendor 而非相对路径是因为 ZCode 的配置驱动安装模型会把文件拷贝到~/.openviking/agent-integrations/vendor 模式让插件自包含、可重定位。scripts/ ├── shared/ # vendored 共享运行时召回/批量写入/待处理队列/凭据/MCP 代理 │ ├── agent-hook-runtime.mjs │ ├── agent-uri-guard.mjs │ ├── async-writer.mjs # maybeDetach / readHookStdin │ ├── recall-core.mjs │ ├── pending-queue.mjs │ ├── credentials.mjs │ └── ... ├── zcode-hook.mjs # 事件分发器按 OPENVIKING_HOOK_EVENT 分支 ├── zcode-capture.mjs # ZCode 专属确认与游标状态转换 ├── zcode-turns.mjs # 会话转录解析rollout 文件 stdin 回退 ├── session-start.mjs # shim设置事件后 import 分发器 ├── auto-recall.mjs # shim ├── auto-capture.mjs # shim ├── uri-guard.mjs # URI 防护独立入口 └── *.test.mjs # 回归测试调度器zcode-hook.mjs 是核心入口它读取OPENVIKING_HOOK_EVENT环境变量或第二个命令行参数决定事件分支。三个 shim 脚本session-start.mjs、auto-recall.mjs、auto-capture.mjs各自设置对应事件名后await import(./zcode-hook.mjs)即“一个入口、按事件分支”的镜像 TRAE 模式。Hook 配置见 hooks/hooks.json{ hooks: { SessionStart: [ { hooks: [{ type: command, command: node \${ZCODE_PLUGIN_ROOT}/scripts/session-start.mjs\, timeout: 30 }] } ], UserPromptSubmit: [ { hooks: [{ type: command, command: node \${ZCODE_PLUGIN_ROOT}/scripts/auto-recall.mjs\, timeout: 20 }] } ], PreToolUse: [ { matcher: Read|Glob|Grep, hooks: [{ type: command, command: node \${ZCODE_PLUGIN_ROOT}/scripts/uri-guard.mjs\, timeout: 5 }] } ], Stop: [ { hooks: [{ type: command, command: node \${ZCODE_PLUGIN_ROOT}/scripts/auto-capture.mjs\, timeout: 30 }] } ] } }注意timeout单位为秒ZCode 的command类型 Hook若用process类型则需timeoutMs毫秒。同时ZCode 的async字段没有运行时效果——Hook 永远以内联方式运行。关键不变量Hook group 必须省略 matcher keyPreToolUse的 matcher 为Read|Glob|Grep。而其他事件如SessionStart的 group必须省略matcher字段绝不能写成matcher: ——严格解析器会把空字符串视为非法值从而静默丢弃整个配置源。这是插件对接 ZCode 时最容易踩的坑之一。严格输出 SchemaZCode 规范键值ZCode 对 Hook 的 stdout 采用严格 JSON 解析任何未识别的 key 都会导致校验失败、整个输出被丢弃。因此调度器绝不输出 Claude Code 风格的{ decision: approve }只输出两类 ZCode 认可的键值上下文注入SessionStart/UserPromptSubmit{ hookSpecificOutput: { hookEventName: UserPromptSubmit, additionalContext: openviking-context ....../openviking-context } }URI 防护拒绝PreToolUse由 uri-guard.mjs 单独处理{ hookSpecificOutput: { hookEventName: PreToolUse, permissionDecision: deny, permissionDecisionReason: ... 请使用 OpenViking MCP 工具 ... } }无内容需要注入时直接输出空串并以 exit 0 放行。这一约束被 zcode-hooks.test.mjs 作为首要回归断言覆盖例如断言输出中decision字段必须为undefined因为它是对抗性审查中排名第一的静默失败模式。会话事件语义与防重细节SessionStart画像注入与 pending 重放session-start分支在互斥锁内先做 2 秒窗口防重lastSessionStartAt距上次不足 2000ms 则跳过随后replayAgentPending重放上次未提交的待处理消息再通过buildAgentProfile从 OpenViking 拉取用户画像与偏好/实体最终以openviking-context sourcesession-start块注入。UserPromptSubmit记忆召回user-prompt-submit分支从多种字段名prompt/user_prompt/userMessage等中提取 prompt先经cleanZcodeText清理剥离openviking-context、relevant-memories、system-reminder等注入块再做两级去重若输入带generation_id/request_id等事件 ID则按promptEventId去重否则按stableHash(prompt) 500ms 时间窗口去重。命中的recallBlock会缓存到 Hook 状态中同一 prompt 重复触发时直接复用避免重复请求。Stop增量捕获与提交stop分支是整个插件正确性的核心由 zcode-capture.mjs 负责buildZcodeCapturePlan(turns, state, cfg)对每个 turn 执行shouldCaptureText内容过滤并以去重键过滤已捕获项addAgentMessages批量发送 payload每条含role、content有turnId时附带turn_id传给 OpenViking若本批确有新捕获captured 0调用commitAgentSession提交会话applyZcodeCaptureResult更新持久状态已确认的capturedTurnIds滑动保留最近 1000 个去重键与推进的lastTurnId游标。去重键设计zcodeTurnDedupKey优先使用${turnId}:${role}无turnId时退化为stableHash(role, content)。注意去重键始终锚定原始 turn 内容——这样即便调高captureMaxLength也不会重发服务端已以截断形式持有的旧 turn。游标推进acknowledgedCursor只会在同一turnId下所有候选 turn 都被确认后才把游标推进到该turnId。这意味着lastTurnId永远指向“完整确认”的边界后续Stop能据此恢复任何漏掉的回合。权威转录源rollout 文件与 stdin 回退ZCode 的StopHook stdin 字段未被官方完整文档化zcode-turns.mjs 的注释说明其字段来自社区逆向工程且transcript_path指向的临时文件只包含最后一条助手消息并非完整对话。因此插件采用双重策略rollout 文件优先权威来源~/.zcode/cli/rollout/model-io-sessionId.jsonl包含完整对话每行结构为{ sessionId, turnId, type: model_io, request: { messages: [...] }, response: { text, toolCalls, finishReason } }。readUnseenRolloutTurns从lastKnownTurnId之后的位置开始增量解析提取最后一条 user 消息与 assistant 文本首次捕获时若没有游标则读取全部条目避免丢失先前回合。stdin 回退兼容路径当 rollout 文件不可读时从responseText/responsePreview等字段提取助手内容从prompt/user_prompt等字段或状态中的pendingPrompt提取用户内容。rollout 中稳定的 hostturnId正是整个去重与恢复机制的基础它被作为 OpenViking 的turn_id传递并驱动lastTurnId游标。已验证的 ZCode 扩展面事实DESIGN.md 记录了针对真实 ZCode 安装内置zcode-guide插件文档 实际~/.zcode/cli/config.json 已安装插件验证过的事实方面验证结论支持的事件SessionStart、UserPromptSubmit、PreToolUse、PermissionRequest、PostToolUse、PostToolUseFailure、Stop恰好 7 个不支持的事件PreCompact、SessionEnd、Notification、SubagentStart、SubagentStopManifest 探测顺序.zcode-plugin/plugin.json→.claude-plugin/plugin.json→.codex-plugin/plugin.json插件 Hook 模板变量${CLAUDE_PLUGIN_ROOT}、${ZCODE_PLUGIN_ROOT}、${CLAUDE_PROJECT_DIR}、${ZCODE_PROJECT_DIR}、${CLAUDE_SESSION_ID}配置式 Hook 模板变量无——config-file 中的 Hook 不做模板展开Hook 输出 schema严格 JSON任何额外 key 导致校验失败、输出被丢弃MCP 配置位置~/.zcode/cli/config.json→mcp.serversuser scope插件 MCP 命名空间plugin:plugin:server本插件为plugin:openviking:openvikingMCP 自动连接所有 scope 在会话启动时自动连接Hook runner 启用任一插件贡献 Hook 时自动启用超时单位command类型为秒process类型timeoutMs为毫秒为什么选择配置式 Hook 而非插件 Manifestinstall_zcode()将 Hook 与 MCP 配置直接写入~/.zcode/cli/config.jsonconfig-file scope而非走插件市场注册——这与 Cursor/TRAE 的安装模式一致。由于 config-file Hook不展开模板变量源文件hooks/hooks.json中的${ZCODE_PLUGIN_ROOT}会在安装时由install.sh的renderHookCommand()替换为绝对路径从而规避该限制。同时合并脚本会自动设置hooks.enabled: true否则 config-file Hook 不会生效。为什么偏好.zcode-plugin/plugin.jsonManifest 探测顺序中.zcode-plugin/是文档化的首选位置.claude-plugin/虽然也能工作但.zcode-plugin/才是规范命名这是适配 ZCode 生态时的命名一致性要求并有测试强制 hooks 与 MCP 配置必须使用${ZCODE_PLUGIN_ROOT}而非${CLAUDE_PLUGIN_ROOT}。配置进阶工作区 Peer 与召回范围插件继承共享运行时的工作区身份能力详见 examples/memory-plugin-shared/README.mdPeer 来源默认peer.source: git一个 git 仓库无论克隆在哪台机器、哪个子目录、哪个 worktree都共享同一 peer 命名空间如github.com-volcengine-openviking实现“项目记忆跟随项目”cwd可恢复旧行为none则不发送 peer。召回范围默认宽召回不发送peer_scope服务端可召回全局记忆、当前工作区及其他工作区记忆其他工作区被降权、后置渲染配置recallPeerScope: actor进入隔离模式只召回全局记忆与当前工作区适合一个 bot 服务多个真实用户如 vikingbot的场景防止他人记忆串入当前会话。工作区配置仓库可提交.openviking/config.json团队共享.openviking/config.local.json私有忽略叠加机器级~/.openviking/workspaces/slot.json配置优先级为环境变量 机器注册表 local 提交文件 ovcli.conf 内置默认。可配置项包括recall.enabled、recall.max_items、recall.score_threshold、capture.enabled、capture.commit_token_threshold等。测试与验证插件自带基于 Node 内置测试运行器的回归套件node:test覆盖三类重点node --test scripts/*.test.mjszcode-hooks.test.mjs断言 URI guard 输出只含 ZCode 认可键不含decision等 Claude-Code-ism、拒绝原因包含 MCP 引导文案、非viking://路径放行、支持tool_name/toolInput等替代字段名以及hooks.json使用${ZCODE_PLUGIN_ROOT}的源文件约定zcode-capture.test.mjs覆盖捕获计划构建、去重键、游标推进与确认逻辑zcode-async.test.mjs覆盖 detached 慢写入场景。此外回归套件专门覆盖了 rollout 优先恢复、确认与游标状态、重复 Stop 投递、detached 慢写入等边界情况并复用 TOS 发布工作流所用的同一市场 staging 脚本进行安装测试。已知边界与注意事项根据 DESIGN.md 中记录的“主要未知项”使用插件时需留意以下边界Stop stdin 字段未官方文档化用户内容不在 stdin 中插件依赖 rollout 文件~/.zcode/cli/rollout/model-io-sessionId.jsonl作为权威对话源stdin 仅为兼容回退hookSpecificOutput包装是否被完整接受需要针对真实 ZCode 会话验证MCP 工具名命名空间形如plugin:openviking:openviking需确认与预期工具名一致turn 身份rollout 条目携带单调递增的turnId插件只在消息发送成功或持久入队后才记录去重键且只通过完整确认的 rollout 条目推进lastTurnId。综上zcode-memory-plugin以最小侵入的方式把 ZCode 的 7 事件 Hook 面收敛为 4 个高效事件借助 rollout 文件的权威性实现了可恢复、可去重、不丢回合的增量会话捕获为 ZCode 用户提供了与 Claude Code/Codex 等客户端一致的 OpenViking 长期记忆体验。【免费下载链接】OpenVikingSelf-evolving Context Database for AI Agents. Unify Agent Memory, Knowledge RAG and Skills.项目地址: https://gitcode.com/GitHub_Trending/op/OpenViking创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
上一篇/下一篇内容由系统自动关联
返回资讯列表 →