关于 vivac
vivac 是面向使用编码 Agent 的项目开发者的溯源树记忆服务。它记录工作与决策之间的关联,帮助会话恢复背景并了解当前进度。
主要功能
- 01沿父子溯源关系追踪工作
- 02生成精简的会话摘要
- 03跟踪未完成与已完成事项
- 04记录备选方案和被取代的决策
- 05在浏览器中查看项目树
适用场景
- 01使用不同模型继续项目
- 02查找决策背后的原因
- 03查看仍待处理的工作
MCP 相关
项目包含一个 MCP 服务,向 MCP 客户端提供 vivac 操作。README 还介绍了浏览器界面和命令行工具。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
$ vivac why 4
Why we are here -> t4
------------------------------------------------------------------
g1 Ship the 2.0 API
the first customer is waiting on it
(4 open / 1 closed below)
|
v
t2 Replace the cache adapter
the session bug traces back to it
(3 open / 1 closed below)
|
v
t4 No test for expiry [closed]
no way to reproduce the session bug
! the corpus run is what settled it
= reproduced: sessions expire at 300s, not 3600
^^^ you are here
In parallel, still open (3):
t3 Rate limiting is undecided
d5 Retry policy: three tries, then fail loudly
t6 Migrate the callers
t2 does not close until these close (1):
t6 Migrate the callers
为一个人的工作而打造
我同时维护八个项目——开源项目、工作项目和自己的项目,其中五个规模都很大。每次重新回到某个项目,我都得一点点拼凑出之前的决定;不止一次,我还眼看着 Agent 改掉我们已经敲定的内容,因为我们俩都忘了曾经定过这件事。过去我只能手动应对:每段工作结束时都请模型给一份检查点,方便我们稍后接着做,或者在项目根目录放一个 where_are_we.txt。
vivac 取代了这些做法,而且至今仍在这些项目中接受检验。这就是它全部的来历,也体现在它构建的功能上:这里的每种机制都源自一个曾让我损失数天的缺陷;本页上的每个数字都来自真实的树,而不是为了让 README 好看而专门设计的基准测试。
这个项目自身维护的树,运行 23 天后的数据:695 个节点,其中 315 个已关闭,176 项既定决策,最深 16 层。
其中三个缺陷,以及它们各自催生的功能:
- 一个标记为
DONE、但发现事项仍未关闭的运行——过了 26 天才有人发现。现在vivac done会拒绝执行,并指出缺少什么。 - 一份包含 109 个待处理事项、长达 224 行的阅读清单,昨天刚处理的事项却排在最底部。现在
open会按顺序告诉你有哪些事在等着你处理,并且最多显示十项。 - **三个已发布到 crates.io 的声明,与旁边的二进制程序相矛盾。**现在,每条本页展示的命令都会由测试运行,并将其列表与
--help的输出进行核对。
如今我最不愿放弃的并非某个单独的功能,而是查看记录了决策及其缘由的树;无论手头用的是哪个模型,都能接着处理某个项目,并让它知道上一个模型敲定了什么;以及随时了解工作进展到哪一步。根据我的经验,这些比这里的其他任何东西都更有价值,也希望它能同样帮到你。
欢迎提交 Issue,我想知道它在哪些方面让你感到不顺。Pull Request 暂未开放;CONTRIBUTING.md 说明了原因。
问题
使用 Agentic AI 开发时,一项工作会催生更多工作。过了三层,你就会忘记自己最初想做什么。
这不是记忆问题:通常所有内容都记录下来了。**这是溯源问题。**记录下来的内容没有说明自己源自何处,缺少这条边,就无法还原你为何身处此地。
在一款真实的编译器项目中测得:目标与当天工作之间的路径深达六层,散落在按时间顺序排列的 8,853 行跟踪记录、52 份规划文档和 21 个问题中。这里的结构是时间性的,恰恰与溯源背道而驰。
日志、决策记录、问题跟踪器和 Agent 会话记忆都会存储节点。如果其中某种方式也存储了边,那也只是需要有人记得添加的链接——因此,恰恰是在没人想到它会重要的那个节点上,它缺失了。它所处的位置按类别逐一介绍了这些方式,并说明了每种方式在哪些方面比本工具更好。
你将获得什么
**Agent 一开始就能了解上下文,无需任何人提醒。**会话打开时,钩子会运行 vivac session start,让它上下文中的第一条信息就是你目前所处的位置、已经做出的决定,以及哪些内容不能动:
$ vivac brief
vivac · project: demo · lane: main · 2026-09-21
------------------------------------------------------------
GOAL g1 Ship the 2.0 API
|
|-- t2 Replace the cache adapter
| why: the session bug traces back to it
|
`-- t6 Migrate the callers <== HERE
why: the old adapter had a different signature
STANDING DECISIONS
d5 Retry policy: three tries, then fail loudly
LAST VIVAC
v5 · push · 2026-09-21 · bcdba21
you were about to: Migrate the callers
------------------------------------------------------------
143 tokens · depth 3 · 0 parked
**用令牌数来衡量,这就是全部论据。**一个把状态保存在三个地方的项目被要求从上次中断处继续。手写计划给出了 9,252 个令牌的答案。记忆系统根据它将项目名称解析为两个名称之一,给出的答案是“也许”,约需 **12,720 个令牌”。树只用了 100 个令牌。简报会带有令牌预算,因为上下文窗口是每个会话都会消耗的一种资源。
**未解决的问题不会被一并封存。**模型中唯一会拒绝操作的操作,确实有充分理由:一次将仍有未解决发现的问题标记为已完成的运行,过了 26 天才被发现。
$ vivac done 2
t2 CANNOT close: 1 open closure condition(s)
t6 Migrate the callers
A run closes with its findings, not with its report.
Closing it anyway leaves a trace: vivac done 2 --force
每项决策都会保留它否决了什么,以及评判它的依据。--alternative 用于记录被否决的选项,--supersedes 将反转决定链接到它所反转的决定,--against 则记录作出决定时所依据的规则或支柱——这样,过了一年之后,人们仍能对这项决策提出质疑,而不是只能猜测。本项目自己的树中就有 176 项这样的记录。
一项被推翻的假设不会带走它的子节点。abandon 会将前提标记为已证伪,并连同其下所有内容一起废弃,但你选择挽救的内容除外——而获救的内容仍留在它诞生的位置,因为诞生于某处这件事,不会因为那个地方后来证明是错的而被抹去。
它不保证什么
**它能节省令牌,但不能节省所有令牌。**恢复项目上下文时,树只用了 100 个令牌,而手写计划用了 9,252 个,每次会话打开时都会再次体现出这种差异。Agent 仍然需要读取文件、推理并解释自己的结论,而这些都不会因此变得更省。
**它无法确保永远不会忘记任何事。**任何记忆系统都做不到,包括这个系统,因为它们仍然依赖模型的判断:*要不要保存这个?这是一个发现吗?回答之前需要重新读取树吗?*再出色的技能、再多的子 Agent 或守护进程,也只会改变判断发生的位置,无法消除判断本身。vivac 将捕获操作挂接在工作流程的衔接处,而不是依赖这种判断;同时,它仍会衡量遗漏发生的位置。
除此之外的原因,正是这棵树要为方便查看而构建的。
亲眼看看
vivac web
Agent 会写入这棵树,你随时都能查看,无需向 Agent 询问任何事情。运行 vivac web,即可在浏览器中打开这台机器上的每个项目:哪个项目有了进展,哪个一直停滞;你离开期间其中一个项目发生了哪些变化;某个节点的完整脉络;以及整棵树。Agents 页面会比较不同执行框架中的原生版本,并通过与 vivac agents sync 相同的操作,应用经过明确审核的同步计划。Artifacts 页面也在这里,它将留存的交付物关联到其生成者,以及引用了确切修订版本的决策。检查、捕获和恢复都使用制品引擎;下载前会验证所选修订版本,然后将其作为附件发送。静态 HTML、CSS 和 JavaScript 包会将所有声明的成员保留为一个修订版本,并恢复到新目录中。HTML 修订版本和软件包可以在独立于 Vivac 会话的受限浏览器预览中打开。请参阅制品保管。你可以在这里亲自查看每项内容的状态,也能发现 Agent 放过了什么。
四个示例项目均由真实的 vivac 命令写入,并由 tools/web-screenshots.py 生成;页面每次变更时,它都会重新截取这些图片。
启动后运行,并在关闭时退出的服务,绑定到 127.0.0.1,可通过它打印的一次性密钥访问。它没有自己的功能:页面所需的所有内容都必须先通过命令行构建。
→ Web 是什么,不是什么
一张地图
**vivac 的构建初衷并非与记忆系统竞争。**我用过 Alan Buscaglia 开发的 engram,也为它贡献代码。我想构建的是一份决策记录,而要走到那一步,后来发现还需要记忆;vivac 就这样开始发挥记忆的作用,并将其保存在项目文件中,这样无论你用哪个运行环境或模型打开它,读到的都是同一份内容。它并不比 engram 或其他任何记忆系统更好。它是为别的目的而构建的。
这就是为什么建议是双向的。如果你已经在用记忆系统,而且它适合你,就不要再加上 vivac。如果你想用 vivac 来管理树,就不要在它旁边再保留另一个系统——任何一个都不行。每个系统都会向模型注入自己的上下文,而两张地图会彼此冲突:每张地图都会引导 Agent 关注它所记录的内容;迟早,其中一张会以另一张不同的方式确定某件事,却没人察觉究竟是哪张地图影响了决策。
这是实际观察到的情况,并非假设:
- **写下的规则可能会创建一个任何工具都读不到的席位。**在一个项目中,一条指令要求 Agent 将每次更新都同步到它的记忆系统。这就让桌上有了三个席位,而真正起支配作用的那个,恰恰是唯一无法检查的。
- **运行环境自带地图,不管你是否选择它。**在构建 vivac 的项目中,为了准确测试仅靠这棵树能否延续工作脉络,我们特意关闭了其他一切;但运行环境的自动记忆仍不断向每次会话注入一份项目准则副本,持续了五天,才有人注意到。测量结果并没有错,只是测量无效,而且没有任何提示表明这一点。
那为什么不直接用运行环境?
它能提供会话,却无法提供以下三样东西;缺少的每一样都会导致具体的问题,而不只是少了某项功能:
- **没有边。**它会存储学到的内容,却不记录这些内容来自哪项工作,因此无从回溯。
- **没有焦点。**所有被回忆起的内容都同等显眼,却没有任何内容能告诉你你在这里——或者更重要的是,不要碰那个。
- **没有开放和关闭状态。**无法报告哪些内容仍未补齐。
而且,**运行环境的记忆属于运行环境。**更换工具,工作脉络就不会随你而来。.vivac/ 是项目中的一个文件:纯 JSON 行格式,只需一条命令即可导出,即使没有这个二进制文件也能读取。
vivac 不会关闭任何东西,安装配置也不会——其他系统不归 vivac 管。它提供的是一项技能,可以找出 Agent 收到的所有其他地图,并在你同意后逐一提议停用,而且整个过程可以撤销。
代价
衡量的是预算,而非愿景:读取分配 50 ms,写入分配 5 ms;达不到时会明确指出,而不是略过不谈。
测量于 2026 年 9 月 18 日进行,树中有一万个节点,每个单元格调用 200 次,使用两台机器和两种树形;因为 brief 和 open 的耗时取决于仍未关闭的分支数,而非节点总数。p99 耗时,单位为毫秒:
brief | why | open | find | |
|---|---|---|---|---|
| CLI,冷启动进程,Linux | 15.5 | 18.8 | 20.4 | 19.9 |
| MCP,常驻服务,Linux | 0.5 | 7.1 | 4.2 | 8.8 |
通过 MCP 写入的 p99 耗时为 0.6 ms,且不随树的大小变化。而且,由于上下文才是真正的限制因素,我们也测量了载荷:一万个节点时,vivac_open 的载荷从 1,993,053 字节降至 599,012;深层节点上的 why --json 则从 86,894 字节降至 7,139。
→ 完整数据——两台机器、两种树形、写入表格,以及 Windows 未达标的部分和原因。
它永远不会存储什么
溯源树是一张地图,标明系统的薄弱之处以及尚未修复的问题,这意味着有几条不可妥协的原则:
- 不存储密钥和秘密。 写入时进行脱敏检查。如有疑问,就拒绝并说明原因;绝不会悄无声息地存储。
- 不存储个人数据。 不存储邮箱、姓名或主目录路径。每个事件中的
actor都是一个不透明标识符。 - 溯源日志中不存储文件内容。 只存储路径、引用,以及关于所做决定的说明文字——因此,即使发生泄露,也只会暴露 正在处理什么,绝不会暴露 代码是什么。
- 不收集遥测数据。 该二进制文件不会主动连接外部服务器。永远不会。
这些原则源自支柱:安全有否决权,性能有预算,用户体验证明某个界面值得阅读,开发者体验负责评判。
安装
每个发布版本都附带预编译二进制文件——适用于 x86_64 和 aarch64 的 Linux 和 macOS,以及适用于 x86_64 的 Windows——文件列在 SHA256SUMS 中,并附有经过签名的构建溯源信息。解压后,将 vivac 放到 PATH 中。
如果已安装 1.89 或更高版本的 Rust 工具链,以及用于编译捆绑版 SQLite 的 C 编译器:
cargo install vivac
cargo install 并非备用方案:它从 crates.io 上发布的源代码构建,因此,对于关心读取其工作成果的工具供应链的人来说,它仍是可审计的途径。
SQLite 会编译进二进制文件;运行时无需安装系统版 SQLite 或 Python。发布压缩包中包含已编译的依赖项。
升级到较新版本时,运行 vivac update。它会显示当前 vivac 的安装方式,以及替换它所需的操作——构建它的 cargo install 命令,或它所来自的发布压缩包(并对照 SHA256SUMS 进行校验)——并在你回答“是”后执行。Windows 上会先将正在运行的副本移到一旁,因此安装无需等待会话结束。如果当前没有终端可供回答,它只会告诉你要输入什么。
→ 设置
前五分钟
1. 在你打开 Agent 的文件夹中运行。第一个命令会创建树,第二个会为你的 Agent 安装钩子、开场模块、服务和技能。两个命令都会展示将要修改的每个文件、每个钩子将运行的确切命令,然后询问:
vivac init
vivac setup claude-code
Codex 用户请使用 vivac setup codex。设置过程还会安装 vivac-artifacts,用于视觉或交互式预览:独立的 HTML 页面,或完整的 HTML/CSS/JS 前端,最好不依赖后端。每个捕获的修订版本都需要简短描述。内置 SQLite 的前端还需要已安装的 sqlite_application 能力,以及由 vivac 提供并随修订版本一同保留的固定 JavaScript 运行时。其他文件交付则需要由用户明确选择。
设置过程不会自动捕获文件。请参阅
制品保管。
2. 开始第一个线程。你本来就要说明自己在做什么;在这里说明,就能免费建立这条关联:
vivac push "Replace the cache adapter" --why "the session bug traces back to it"
vivac push "No test for expiry" --why "no way to reproduce it" --blocks
vivac pop "reproduced: sessions expire at 300s, not 3600"
3. 询问你现在处于什么状态,以及原因:
vivac brief where you are, and what NOT to touch
vivac why 2 the path from the root, narrated
vivac open what is waiting on you, and what has been sitting
vivac web the whole tree in a browser, on this machine only
这就是整个循环。→ 每个命令何时运行,以及 Agent 跳过某个命令时该怎么说 · 所有命令
引入项目
不会有任何内容自动进入 vivac。
如果你的项目已经保存了它学到的内容——在记忆系统、CLAUDE.md、AGENTS.md、MEMORY.md、harness 自带的记忆或内部文档中——执行 vivac setup 后,这些内容都不会出现在树中。 vivac 从不读取其他系统,也从不读取这些文件,因为从周围的叙述中辨别规则需要判断力,而一个靠猜测的工具会在第一天就用看似笃定的胡言乱语填满你的树。
因此,这项工作要由 Agent 来做,由你决定哪些内容要放进去。setup 会安装 vivac-migrate 技能,你只需说:
使用 vivac-migrate 技能,将这个项目知道的一切引入 vivac。
它会列出找到的每个来源,询问要引入哪些内容,在写入任何内容前展示计划,检查写入的内容——然后逐一询问是否停用其他知识地图。**最后这一步才是重点,而不只是整理工作:**如果旧记录仍在与 Agent 对话,那么即使树已完整,仍然是两张地图,而这正是你要摆脱的状态。
→ 引入项目,以及真实项目中的迁移情况:八次迁移,其中两次逐个来源进行测量,以及每次失败带来了哪些改变。
工作区
你可能会在多个文件夹中处理同一个产品:一个检出位于 main,另一个用于紧急修复,第三个用于审查别人的分支。也可能只有一个文件夹,却每天要处理十次分支变更。
文件夹可以分开,记录不能分叉。 它最初源自什么? 对这个产品来说只有一个答案,而不是每个检出各有一个——三棵树给出三种答案,就是三个错误答案。
因此,树属于产品,每个用于处理它的文件夹都是一个工作区。分支是每次写入时记录的一项事实,而不是树所驻留的地方。
这样做的好处是:简报会告诉你某个分支何时在你处理期间发生了变化,以及自从你上次在此处写入后,其他工作区做了什么。
| 你的情况 | 要运行的命令 |
|---|---|
| 同一棵树下的另一个文件夹 | 在那里也运行 vivac init,然后运行 vivac setup claude-code |
| 完全不同位置的文件夹 | vivac init --join <name>,然后运行 vivac setup claude-code |
| 树应存放在其他位置 | vivac relocate <destination> |
| 查看现有工作区及各自所在的分支 | vivac stack --lanes |
无论在哪里使用 claude-code,包括与其他 harness 一起在同一个文件夹中使用时,都可以换成 codex:harness 决定文件夹会获取哪些文件,但绝不会决定树的任何内容。
→ docs/LANES.md — 什么是工作区、什么不是工作区,以及四种常见的错误用法。
测量范围
| Claude Code | vivac setup claude-code 会写入开场模块、钩子、服务和技能。这是本页测量所用的执行环境;这些测量并未对新的开场模块进行基准测试。有关它的独立原生检查,请参阅指令传递。 |
| Codex | vivac setup codex 会让项目同样做好准备,供 Codex 读取。我们于 2026 年 9 月 22 日完整走查了一次真实的 Codex 会话:信任项目后,服务即可解析;技能会提供给模型;开场钩子会将简报放入 Agent 的上下文;结束钩子会留下停止标记。它会与现有内容合并,第二次运行时不会写入任何内容,并且可以自行撤回——与 Claude Code 端的方式相同,也使用同样的三个标志。目录树不属于任何一端:vivac init 只负责创建一次,两个执行环境都会读取它留下的内容。 |
| 其他环境 | 钩子会调用普通命令。任何能在会话开启时运行命令,并将其输出放入 Agent 上下文的执行环境,都能调用同一命令;任何 MCP 客户端都能运行 vivac mcp。它在 MCP Registry 中的名称为 mcp-name: io.github.JAAvila-Of/vivac。 |
这次走查中的一个步骤无法测量,也不能测量:在 Codex 中批准每个钩子是由人完成的一次性操作,而观察人并不属于测量。
尚未实现:团队模式。项目仍处于 0.x 阶段,次版本更新会造成破坏性变更。
文档
| 每条命令何时运行 | 会话中的各个时刻、每个时刻由谁操作,以及 Agent 跳过某一步时该怎么说 |
| 使用方法 | 按运行者分组的所有命令 |
| 设置 | 设置会写入什么、Codex、MCP 服务,以及内容的存储位置 |
| Agent 托管 | 清单、引导式同步、网页对比和明确的模型分配 |
| 引入项目 | 迁移流程,以及为什么这是迁移而非添加 |
| 通道 | 一个产品、多个文件夹、一棵目录树 |
| 成本 | 完整的测量结果及测量方法 |
| 版本管理 | 何时会有破坏性变更,以及什么会阻碍 1.0 |
| 定位 | 各类工具存储的内容,以及它们各自在哪些方面优于本项目 |
| 支柱 | 评判此处每项决策的四大准则 |
| 制品托管 | 保留选定文件和完整前端包,包括受支持的 SQLite 应用;引用并恢复确切的修订版本 |
许可证
由使用者选择,采用 MIT OR Apache-2.0。两种许可证的文本分别见
LICENSE-MIT 和 LICENSE-APACHE。
许可证涵盖代码,不涵盖名称:任何人都可以自由分叉,但分叉版本须使用自己的名称。TRADEMARKS.md 说明名称和徽标的使用方式。安全漏洞应私下报告,如 SECURITY.md 所述。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。