# MetaBoard **给编码以外的工作,留下可检视的执行轨迹。** [English](README.md) | 简体中文 编码 agent 有一样别的工具几乎都没有的东西:一份可回溯、可检视的记录,说明这件事**究竟是怎么做成的**。 每一次检索、每一次工具调用、每一次重试都是一条结构化事件——因为执行器自己会掉出来, 不是靠谁记得去记一笔。 内容创作没有这份记录。看板能告诉你一篇稿子从 `todo` 挪到了 `in_review`, 但告诉不了你大纲是从哪二十篇同题材里提炼的、第二次改稿花了多久、编辑打回时具体说了什么。 而这些恰恰是数据不好时你要回头查的东西。 MetaBoard 把 agent 轨迹带到非编码业务上,首个业务域是内容生产。 --- ## 当前状态 **设计完成,实现未开始。** 这个仓库现在没有产品代码。有的是一份建立在已验证约束之上的设计——见 [已经验证过什么](#已经验证过什么)。 想找现在就能装的东西,过段时间再来。对「执行轨迹如何脱离软件领域」这个问题感兴趣,可以往下读。 --- ## 想法 MetaBoard 是 [DeepSeek Harness](https://github.com/deepseek-ai/deepseek-harness)(`dsh`)的插件。 它复用 `dsh` 里真正难写、也真正与领域无关的那一部分——会话节点装配器,替换掉与编码绑定的那一层。 装配器把原始事件流变成物化的业务对象:每个注册的 Definition 从单个事件里抽出稳定业务 ID, 在匹配到的事件上折叠状态,产出视图节点。旧一页历史加载进来时,只有答案发生变化的 Context 会被重放。 这套增量重放是长轨迹能保持流畅的原因,也是最不该自己重写一遍的部分。 这套机制里没有任何一处知道 token、工具 schema 或 TTFT。那些在上面一层, 在轨迹 UI 自己的 Definition 里。换掉那一层,同一个引擎渲染的就是另一个领域。 ### 内容轨迹长什么样 内容轨迹:两个轮次的工具调用,中间夹一次人工评审,蓝色派生边显示每个产物来自哪些上游 竖向顺序是时间。蓝色的边是看板表达不了的东西:这一稿来自哪几条素材、这一版改的是哪一稿。 它们不是推断出来的——每个工具在自己的结果里就记下了。 选中一行打开完整载荷:检索到的素材、稿件全文、它从哪几条来、花了多久。 --- ## 怎么做的 架构:MetaBoard 的工具和评审写入器产生核心会话事件,共享的会话装配器供给 Chat、Trajectory、MetaBoard 三套 Definition,各自渲染自己的标签页 MetaBoard 是一个普通的、仓库外的 npm 包,两半: **host 半**注册内容生产工具。每次调用产生核心的 `tool/call` 和 `tool/result` 事件, 领域载荷挂在 `tool/result.meta` 上——那是 `dsh` 本来就提供的、工具私有、核心不透明、 持久化保存的 JSON 通道。 **client 半**注册自己的会话 Definition 和一个视图标签页。Definition 只认领 MetaBoard 自己的调用, 把它们装配成领域对象再渲染。 不 fork,不改宿主,不加新事件类型。 最后这条不是审美偏好,是测出来的边界,而且它塑造了整个设计。 --- ## 已经验证过什么 在写产品代码之前,先直接对着上游代码库把可行性边界探了一遍——测试写进真实的 JSONL 日志, 再用全新挂载的栈读回来。六条命题,全部确认: | # | 命题 | 结果 | |---|---|---| | 1 | `Session.append` 能否让插件把自己的事件标成可忽略 | **不能。** 公开写入 API 打不了这个标记 | | 2 | 含插件自定义事件类型的日志会怎样 | **整份拒收**——`SessionFormatUnsupportedError`,不是跳过那一行 | | 3 | 同一条事件带上可忽略标记呢 | **完整读回**,一字不差。存储层支持,只是写入侧没开口 | | 4 | 50KB 的 `tool/result.meta` 经真实文件往返 | **能**。没被 spill,没被截断 | | 5 | 插件直接 append 的 `user/message` 能否往返 | **能**——不需要模型参与 | | 6 | 插件事件类型会不会进模型上下文 | **不会**。它不是 surface 事件类型 | 第 2 条是 MetaBoard 不定义自己事件类型的原因。第 4、5 条是它不需要定义的原因。 第 3 条记录了一个存在于存储层、但在写入 API 上被有意关闭的口子—— 上游文档写明 `Session.append` 会「在第一个使用者出现时」补上这个入口。 --- ## 设计 完整设计文档暂时不在这个仓库里。要紧的几个决定: **数据落点只看一个问题——它是事件还是状态。** | 类别 | 例子 | 落点 | |---|---|---| | 事件,模型发起 | 检索到的素材、稿件全文、改稿 diff | `tool/result.meta` | | 事件,人发起 | 编辑打回、临时指令 | `user/message`(plugin 来源) | | 状态 | 选题状态、负责人、看板位置、播放量 | MetaBoard 自有存储 | **Context 身份是一次调用,不是一个选题。** 一次调用一个 Context, 让 live append 保持 `O(1)`,也让 prepend 不会让整个选题的历史失效。 选题 ID 放在节点载荷里,分组在快照装配时做。 **失败的调用也必须写信封。** `tool/result` 的载荷里不带工具名——只有 `tool/call` 带—— 而匹配时不能查历史。信封是唯一的认领依据。工具失败时省掉它,账本上就留下一行永远显示 「运行中」的记录,重新加载也不会好,因为日志里存的就是这个。 **引用在渲染时解析,不走依赖 reader。** 走 reader 会记下窗口缺口依赖, 每次往回翻都触发链式重放。而引用指向的目标其值从不改变,只是有时还没加载。 渲染一个未解析的引用,代价是它灰一下;另一条路的代价是每条长轨迹的滚动性能。 --- ## 路线 **第一阶段 · 可行性切片。** 三个工具、两个 Definition、一个标签页、一张最简行表。 没有检视面板、没有时间轴、没有看板、没有存储层。及格线:层级装得出来、引用解析得出来、 50KB 载荷重开还在、失败的调用渲染成一行完整的失败记录而不是卡住的行。 **第二阶段 · 工作项。** 看板视图、自有存储、跨会话汇总、平台数据接入。 **第三阶段 · 其他领域。** 数据落点规则和信封不是内容生产专用的。 法务审查、研究综述、设计迭代是同一个形状:一个多步过程,中间产物比最终状态更值得看。 --- ## 来源与致谢 MetaBoard 来自两个项目: - [**deepseek-ai/deepseek-harness**](https://github.com/deepseek-ai/deepseek-harness)—— 装配器、事件流、轨迹账本,这份设计从中学习。MIT。 - [**chuspeeism/dashi-taskboard**](https://github.com/chuspeeism/dashi-taskboard)—— 本地优先的任务看板,带工作流图和第三方发布节点。它把字段级审计和 AI 会话记录分成两套的做法, 让中间缺的那一层变得明显。 MetaBoard 与这两个项目均无隶属关系。 --- ## 许可 MIT