背景
Claude Code、Codex 这类 coding 工具通常不是长期运行的服务进程。它们的插件 / hook 往往是在一次会话事件里短暂启动:读取本地 transcript、调用远程或自部署 OpenViking API,然后退出。
这意味着:如果 OpenViking server 在这次 hook 执行期间不可达,客户端没有常驻进程可以稍后自动补传,最近一次会话里尚未写入服务端的记忆就可能丢失。
使用场景
典型部署是:
- 本地电脑、SSH devbox 或 container 里运行 Claude Code / Codex。
- 本地启用
examples/claude-code-memory-plugin/ 这类 OpenViking coding-tool 插件。
- 插件通过 HTTP 调用自部署 OpenViking server 来保存会话记忆。
- OpenViking server 可能因为重启、断网、DNS、代理、部署升级等原因短暂不可达。
这里的“本地缓存”指的是运行 coding tool 和插件 hook 的那台机器,例如:
它不是远程 OpenViking server 上的缓存,也不是服务端级别的可靠队列。
问题
当前 claude-code-memory-plugin 在写入失败时缺少客户端本地持久化和重试机制:
auto-capture.mjs 调用 addMessage() / commitSession() 失败后,只能记录失败计数,实际 payload 没有可靠保存。
session-end.mjs 如果健康检查失败,会跳过最终 commit,最后一段 pending messages 可能无法进入 OpenViking archive。
- 由于插件 hook 是短生命周期进程,不能依赖“当前进程稍后再试”。
用户看到的症状可能是 statusline 出现 dropped 计数,或者重启 / resume 后发现最近一次会话没有被 OpenViking 记住。
目标
增加一个客户端本地 pending queue:
- 当 OpenViking server 暂时不可达时,将失败的写入操作保存到本机
~/.openviking/pending/。
- 下一次
session-start 时,如果 server 已恢复,自动回放 pending queue。
- 只自动重试“环境恢复后大概率能成功”的错误:网络错误、timeout、5xx、408、429。
- 对 401 / 403 / 404 / 422 这类客户端或配置错误,只输出明确 warn,不进入默认自动 replay 队列。
- 提供 TTL 和最大重试次数,避免 pending 目录无限增长。
- 通过
dedupKey 避免同一 payload 重复落盘,例如 sha256(sessionId + operationType + canonicalPayload)。
- 通过 replay 前的原子 rename / claim 避免多个
session-start 进程并发重复 replay 同一个 pending 文件。
- 每次
session-start 限制 replay 条数或做轻量限速,避免服务端刚恢复时一次性回放大量 pending;不做长阻塞式 exponential backoff。
非目标
- 不修改 OpenViking server 核心存储逻辑。
- 不实现服务端级别消息队列。
- 不引入长期后台守护进程。
- 不默认自动重放 4xx 失败请求。
- 不跨设备同步 pending queue。
- 不处理 hook 根本没有运行的场景,例如 Claude Code 被强杀、崩溃或系统直接清理进程。pending queue 只保护“hook 已经运行并尝试写入 OpenViking,但 HTTP 写入失败”的 payload。
建议方案
新增本地文件队列模块:
examples/claude-code-memory-plugin/scripts/lib/pending-queue.mjs
核心能力:
enqueue(type, sessionId, payload):将失败操作写入本地 JSON 文件。
listPending():按创建时间读取 pending 项。
replayPending(fetchJSON, log):在 session-start 时回放 pending 项。
dequeue(filename):成功回放后删除。
incrementRetry(filename, entry):失败后增加 retry count。
cleanStale():清理超过 TTL 的条目。
dedupKey:对 sessionId + operationType + canonicalPayload 生成稳定 hash,避免同 payload 重复落盘。
- atomic claim:replay 前将
xxx.json 原子 rename 为 xxx.processing,只有 claim 成功的进程执行 replay;成功后删除,失败后写回带 retry+1 的 pending 文件。
配置项:
| Env Var |
默认值 |
说明 |
OPENVIKING_PENDING_DIR |
~/.openviking/pending |
本地 pending queue 目录 |
OPENVIKING_PENDING_MAX_RETRIES |
3 |
单条 pending 最大重试次数 |
OPENVIKING_PENDING_TTL_DAYS |
7 |
pending 条目最长保留天数 |
错误分类
建议默认自动入队:
- 无
status 的网络错误 / timeout
5xx
408
429
建议只 warn、不自动入队:
401:API Key 缺失、错误或过期
403:权限 / account / user / agent 边界不匹配
404:baseUrl、API 路径、版本或资源不匹配
422:payload 校验失败
如果未来需要保留 4xx payload,可以单独设计 blocked / quarantine 队列,由用户在修复配置后手动确认 replay。
验收标准
- 服务端不可达时,
addMessage() 失败会在本地生成 pending 文件。
- 服务端恢复后,下一次
session-start 会 replay pending 文件并在成功后删除。
- replay 逻辑不依赖 profile/archive 是否注入;即使
OPENVIKING_NO_AUTO_INJECT=1,只要 session-start 执行且 health check 通过,仍应回放 pending queue。
401/403/404/422 不进入默认自动 pending queue,并有明确 warn。
5xx、网络错误、timeout、408、429 会进入 pending queue。
- 同一 payload 重复 enqueue 时,不会生成重复 pending entry。
- 同一 pending 文件被多个
session-start 进程同时看到时,只有一个进程能通过 atomic claim 执行 replay。
- 每次
session-start 不会无限制 replay 全部 pending;应有可预测的单次 replay 上限或轻量限速。
- pending 文件只保存在运行 Claude Code / Codex 插件的本机,文档中需提醒该目录可能包含原始记忆 payload,应按本地隐私数据处理。
后续增强
- pending queue 超过阈值时给出告警,例如超过 100 条提示用户检查网络、baseUrl、server 状态或认证配置。
- 为 4xx payload 设计
blocked / quarantine 队列,并提供用户手动确认 replay 的命令或流程。
关联
背景
Claude Code、Codex 这类 coding 工具通常不是长期运行的服务进程。它们的插件 / hook 往往是在一次会话事件里短暂启动:读取本地 transcript、调用远程或自部署 OpenViking API,然后退出。
这意味着:如果 OpenViking server 在这次 hook 执行期间不可达,客户端没有常驻进程可以稍后自动补传,最近一次会话里尚未写入服务端的记忆就可能丢失。
使用场景
典型部署是:
examples/claude-code-memory-plugin/这类 OpenViking coding-tool 插件。这里的“本地缓存”指的是运行 coding tool 和插件 hook 的那台机器,例如:
它不是远程 OpenViking server 上的缓存,也不是服务端级别的可靠队列。
问题
当前
claude-code-memory-plugin在写入失败时缺少客户端本地持久化和重试机制:auto-capture.mjs调用addMessage()/commitSession()失败后,只能记录失败计数,实际 payload 没有可靠保存。session-end.mjs如果健康检查失败,会跳过最终 commit,最后一段 pending messages 可能无法进入 OpenViking archive。用户看到的症状可能是 statusline 出现 dropped 计数,或者重启 / resume 后发现最近一次会话没有被 OpenViking 记住。
目标
增加一个客户端本地 pending queue:
~/.openviking/pending/。session-start时,如果 server 已恢复,自动回放 pending queue。dedupKey避免同一 payload 重复落盘,例如sha256(sessionId + operationType + canonicalPayload)。session-start进程并发重复 replay 同一个 pending 文件。session-start限制 replay 条数或做轻量限速,避免服务端刚恢复时一次性回放大量 pending;不做长阻塞式 exponential backoff。非目标
建议方案
新增本地文件队列模块:
核心能力:
enqueue(type, sessionId, payload):将失败操作写入本地 JSON 文件。listPending():按创建时间读取 pending 项。replayPending(fetchJSON, log):在session-start时回放 pending 项。dequeue(filename):成功回放后删除。incrementRetry(filename, entry):失败后增加 retry count。cleanStale():清理超过 TTL 的条目。dedupKey:对sessionId + operationType + canonicalPayload生成稳定 hash,避免同 payload 重复落盘。xxx.json原子 rename 为xxx.processing,只有 claim 成功的进程执行 replay;成功后删除,失败后写回带 retry+1 的 pending 文件。配置项:
OPENVIKING_PENDING_DIR~/.openviking/pendingOPENVIKING_PENDING_MAX_RETRIES3OPENVIKING_PENDING_TTL_DAYS7错误分类
建议默认自动入队:
status的网络错误 / timeout5xx408429建议只 warn、不自动入队:
401:API Key 缺失、错误或过期403:权限 / account / user / agent 边界不匹配404:baseUrl、API 路径、版本或资源不匹配422:payload 校验失败如果未来需要保留 4xx payload,可以单独设计
blocked/quarantine队列,由用户在修复配置后手动确认 replay。验收标准
addMessage()失败会在本地生成 pending 文件。session-start会 replay pending 文件并在成功后删除。OPENVIKING_NO_AUTO_INJECT=1,只要session-start执行且 health check 通过,仍应回放 pending queue。401/403/404/422不进入默认自动 pending queue,并有明确 warn。5xx、网络错误、timeout、408、429会进入 pending queue。session-start进程同时看到时,只有一个进程能通过 atomic claim 执行 replay。session-start不会无限制 replay 全部 pending;应有可预测的单次 replay 上限或轻量限速。后续增强
blocked/quarantine队列,并提供用户手动确认 replay 的命令或流程。关联