CLI-Anything Harness 预览方法论:bundle/session/trajectory 三层模型与 Agent 命令契约
本文解读 CLI-Anything 的 Harness 预览方法论(cli-anything-plugin/guides/preview-methodology.md):当一个 Harness 能够通过图片、视频片段、检查包等“真实软件产出的中间态”向 Agent 反馈时,应该如何设计 preview 命令族。读完本文,你将掌握 producer/consumer 角色分离原则、bundle/session/trajectory 三层数据模型、推荐的 CLI 表面(含 diff/live/poll 可选能力)、面向 Agent 的 preview live status --json 契约,以及真实性约束与落地检查清单;并以仓库中已落地的 Blender、Shotcut、FreeCAD、RenderDoc 等 Harness 源码作为实现级佐证。
1. 适用场景与文档定位
这份方法论适用于能够通过图像、视频片段、检查包或其他来自真实软件的诚实产物暴露有意义的中间状态的 Harness。它与 docs/PREVIEW_PROTOCOL.md 是互补关系:
- 协议文档定义 bundle/session/trajectory 的格式(
preview-bundle/v1、preview-live/v1、preview-trajectory/v1); - 本文(方法论)定义 Harness 侧的实现方法与面向 Agent 的命令契约。
协议文档明确了设计边界:预览产物仍必须来自真实软件及其真实后端,协议只标准化“预览产物契约”,不替代渲染器;cli-hub 成为所有 bundle 的通用查看器,而不是让每个 Harness 各自发明监控 UI。
2. 角色分离:Producer 与 Consumer
方法论的第一条硬规则是把预览的生产与预览的消费保持为两个独立角色:
| 角色 | 命令入口 | 职责 |
|---|---|---|
| Producer | cli-anything-<software> preview ... |
与真实后端通信、计算源指纹、选择 recipe、发布 bundle/session/trajectory |
| Consumer | cli-hub previews ... |
只读取已存在的预览状态,提供 inspect、html、watch、open;从不渲染或合成预览产物 |
这个分界在仓库中是真实落地的。cli-hub 的 previews 命令组帮助文本直白地写明了消费侧边界(cli-hub/cli_hub/cli.py):
@main.group(name="previews", invoke_without_command=True)
def previews(ctx):
"""Inspect existing preview bundles or live sessions; this command does not publish previews."""
消费侧的四个子命令在 cli-hub/cli_hub/cli.py 中实现:
cli-hub previews inspect <bundle-or-session>:自动识别引用是 bundle 目录还是 live session 目录(通过是否存在session.json判定,见 cli-hub/cli_hub/preview.py 的is_live_session_ref),输出 manifest 元数据、源标识、summary 的 headline/facts/warnings、产物表格,以及可用时的 trajectory 摘要;cli-hub previews html <bundle-or-session> [-o output.html]:生成静态 HTML 页,先展示 summary,再渲染hero/gallery图像、内嵌preview-clip的<video>、链接 JSON 产物,并在存在trajectory.json时渲染会话历史(HTML 渲染逻辑见 cli-hub/cli_hub/preview.py);cli-hub previews watch <session-dir> [--open] [--poll-ms 1500]:通过 localhost 静态服务器托管 live session 并自动刷新页面(cli-hub/cli_hub/cli.py);cli-hub previews open <bundle-or-session>:为 bundle 打开生成的 HTML 文件,或为 session 启动带浏览器后端的 watcher(cli-hub/cli_hub/cli.py)。
方法论要求这个 producer/consumer 区分在命令帮助、README 示例、SKILL.md、live-session 查看器提示中都清晰可见。一句话总结:
发布用
cli-anything-<software>,检查用cli-hub。
3. 三层模型:bundle、session、trajectory
能预览的 Harness 应当显式建模历史,而不是把“最新的 bundle 目录”当作永久对象。三层各司其职:
3.1 bundle_dir:不可变快照
一个 bundle 目录对应一次具体的预览结果:一次静态抓取、一次 diff 抓取、或一次 live session 的发布步骤。它应实现 preview-bundle/v1 并包含:
<bundle_dir>/
manifest.json # 机器契约
summary.json # 面向人/Agent 的摘要
artifacts/ # hero.png、gallery_*.png、preview.mp4 等
bundle 一旦发布即视为不可变。这一约定在 canonical helper 中得到强制:prepare_bundle 创建新目录时使用 exist_ok=False 确保不覆盖已发布的 bundle,finalize_bundle 只负责写入 manifest.json 与 summary.json(cli-anything-plugin/preview_bundle.py)。
Bundle ID 采用 <UTC 时间戳>_<短指纹>_<recipe> 形式(如 20260419T104530Z_9f0a2c4b_quick),指纹派生自源指纹、recipe、归一化后的预览参数、harness 版本与协议版本,使 bundle 可缓存、可复现。canonical helper 中的实现为:
bundle_id = f"{now}_{cache_key.split(':', 1)[-1][:8]}_{_slug(recipe)}"
(cli-anything-plugin/preview_bundle.py)
3.2 session.json:可变的 live 头部
session.json 代表某项目某 recipe 的当前 live 视图,是“现在是什么”的稳定入口。典型字段包括:当前 bundle id 与路径、session 根目录与 recipe、查看器命令(watch_command、inspect_command 等)、当前 step id、trajectory 位置。
以仓库中最完整的参考实现 Blender Harness 为例,其 _publish_live_session 写入的 session 负载覆盖了方法论列出的全部字段,并额外携带可直接复制执行的命令提示(blender/agent-harness/cli_anything/blender/core/preview.py):
"current_bundle_id": bundle_manifest.get("bundle_id"),
"current_bundle_dir": bundle_manifest.get("_bundle_dir"),
"current_manifest_path": bundle_manifest.get("_manifest_path"),
"current_summary_path": bundle_manifest.get("_summary_path"),
"current_step_id": trajectory.get("current_step_id"),
"trajectory_path": trajectory_rel,
"publish_command": f"cli-anything-blender{project_flag} preview live push --recipe {recipe}{root_flag}",
"watch_command": f"cli-hub previews watch {session_dir} --open --poll-ms {current_refresh_hint_ms}",
"inspect_command": f"cli-hub previews inspect {session_dir}",
从源码结构看,这些 *_command 字段正是方法论中“live-session viewer hints”要求的落地:session 自己告诉 Agent“下一步该跑什么命令”。
3.3 trajectory.json:append-only 的永久历史
trajectory.json 是持久的可重放对象,它必须能超越当前头部存活,让后续工具重建产物是如何演进的。方法论要求每个 trajectory step 至少捕获:
step_id、step_index、commandcommand_started_at、command_finished_atpublish_reasonsource_fingerprintbundle_id、bundle_dir、manifest_path、summary_path- 可选:
stage_label、note
方法论特别强调:把 Agent 动作绑定到预览状态应该发生在这里,不要指望 _bundle_dir 独自承担这个角色。canonical helper 提供了现成的实现:append_live_trajectory 读取既有 trajectory、按 len(steps) + 1 生成 step-000N 编号、追加新 step 后整体重写 trajectory.json(cli-anything-plugin/preview_bundle.py);step 字段装配由 build_live_history_item 完成,它会自动从 bundle manifest 中兜底解析 command 与 source_fingerprint(cli-anything-plugin/preview_bundle.py)。
消费侧同样为这种 append-only 结构做了容错解析:cli-hub/cli_hub/preview.py 的 _pick_trajectory_events 会依次尝试 preview_events/events/publishes/entries/history/steps/timeline 等键名,_normalize_timeline_row 则归一化多种命令/时间戳命名,保证不同 Harness 写出的 trajectory 都能被统一展示。
4. Canonical helper:发布流程的复用模式
协议文档与仓库共同确立了一个“把 canonical helper 复制进 Harness”的落地模式(与 repl_skin.py 同款):canonical 版本位于 cli-anything-plugin/preview_bundle.py,试点 Harness 将其 vendored-copy 为 utils/preview_bundle.py,避免为所有 harness 包引入新的共享运行时依赖。当前仓库中已存在的 vendor 副本包括:
- shotcut/agent-harness/cli_anything/shotcut/utils/preview_bundle.py
- openscreen/agent-harness/cli_anything/openscreen/utils/preview_bundle.py
- blender/agent-harness/cli_anything/blender/utils/preview_bundle.py
- freecad/agent-harness/cli_anything/freecad/utils/preview_bundle.py
- renderdoc/agent-harness/cli_anything/renderdoc/utils/preview_bundle.py
这个 helper 承担了方法论检查清单中“发布 preview-bundle/v1 bundle”所需的全部脏活:bundle 目录创建、manifest/summary 写入、相对路径的产物描述符、缓存键生成。preview capture 的典型调用链为:
prepare_bundle(cli-anything-plugin/preview_bundle.py):用build_cache_key对protocol_version + software + recipe + bundle_kind + source_fingerprint + options + harness_version做 sha256 得到缓存键(cli-anything-plugin/preview_bundle.py);除非--force,先调用find_cached_manifest扫描同cache_key且状态为ok/partial的既有 manifest,命中即返回cached: True,否则创建新 bundle 目录。- 真实后端渲染:这是 Harness 自己的逻辑,产物写入
artifacts/。 artifact_record(cli-anything-plugin/preview_bundle.py):把产物文件转换为带相对路径的 manifest 描述符,自动猜测media_type、记录bytes。finalize_bundle(cli-anything-plugin/preview_bundle.py):先写summary.json再写manifest.json,并回挂_manifest_path/_bundle_dir/_summary_path供后续 live 发布引用。
bundle 的默认位置也在此实现中固化(cli-anything-plugin/preview_bundle.py):
# 有项目路径:<project_dir>/.cli-anything/previews/<software>/<recipe>/
# 无项目路径:~/.cli-anything/previews/<software>/<recipe>/
这与协议文档“产物尽量留在项目附近、bundle 便于垃圾回收、cli-hub 可扫描可预测的根”的理由一致。
5. 推荐的 CLI 表面
5.1 基线表面
当软件拥有有意义的可预览状态时,应暴露三个基础命令:
| 命令 | 推荐行为 |
|---|---|
preview recipes |
列出支持的预览 recipe 及其产物 |
preview capture |
从当前源状态产出新的或缓存复用的 bundle |
preview latest |
返回该项目与 recipe 的最新已存在 bundle,不重新渲染 |
preview latest 必须只读。Blender 的实现印证了这一点:latest 直接调用 find_latest_manifest 按时间序倒排扫描 manifest 并返回第一个 status 为 ok/partial 的条目,找不到则抛出 FileNotFoundError(blender/agent-harness/cli_anything/blender/core/preview.py),全程不触发渲染。
5.2 可选 diff 表面
当软件适合直接的 A/B 对比时才暴露 preview diff。适合场景:GPU 抓取工具、具有 before/after 检查状态的工具、以及差量比当前 hero 帧更重要的工作流。RenderDoc Harness 就是协议文档中规划的 diff 试点:preview capture --event-id N 输出缩略图 + 输出目标 + pipeline JSON,preview diff --event-a A --event-b B 则把 A 侧输出标为 before、B 侧标为 after,并附带 diff-json 载荷(设计见 docs/PREVIEW_PROTOCOL.md 的 PR4 章节)。
5.3 可选 live 表面
当迭代式 live 检查有价值时,暴露四件套并遵循以下语义:
| 命令 | 语义 |
|---|---|
preview live start |
初始化 session 根目录并发布首个 bundle |
preview live push |
向既有 live session 追加一个新 bundle |
preview live status |
只报告当前状态,不渲染 |
preview live stop |
标记 session 非活跃,但保留全部已发布历史 |
Blender 的实现完整覆盖了这四条:live_start 先 capture 再 _publish_live_session(blender/agent-harness/cli_anything/blender/core/preview.py);live_push 读取既有 session 的 mode 与 poll 参数后复用 live_start 通路,publish_reason 为 manual-push(blender/agent-harness/cli_anything/blender/core/preview.py);live_status 只读 session.json 并附加 trajectory 摘要(blender/agent-harness/cli_anything/blender/core/preview.py);live_stop 终止 poller 进程、置 status: "stopped" 并落盘,但不动任何已发布 bundle(blender/agent-harness/cli_anything/blender/core/preview.py)。
5.4 可选 poll-first 刷新
当事实源是文件型、且 Agent 可能在预览调用之间通过其他命令保存文件时,使用 poll-first 刷新。适合:JSON 项目文件、XML 时间线、以及指纹重算廉价的抓取/场景文件。Poll 支持的典型形态:
preview live start --mode poll
# + 内部后台 monitor 循环
# + 渲染前先做源指纹检查
方法论同时给出明确警告:只有当 poll 模式确实降低 Agent 摩擦时才加它。不要添加会发布无意义重复 bundle 的后台循环。 指纹检查机制在 canonical helper 中即有支撑:fingerprint_file 基于 path + size + mtime_ns 计算 sha256(cli-anything-plugin/preview_bundle.py),Blender 侧则用 _project_file_fingerprint 在每次发布时更新 source_state.last_seen_fingerprint/last_rendered_fingerprint 供 monitor 对比(blender/agent-harness/cli_anything/blender/core/preview.py)。
6. 面向 Agent 的 preview live status --json 契约
这条命令存在的目的,是让 Agent 的 live 循环足够廉价。它应当回答五个问题:
- live session 是否存在?
- 是否处于 active 状态?
- 当前 bundle 是什么?
- 最近一次发布原因(publish reason)是什么?
- 最近一次“命令 → 预览”的映射是什么?
方法论推荐 --json 输出包含:
status, active, _session_dir, _session_path,
current_bundle_id, current_bundle_dir, current_manifest_path, current_summary_path,
_trajectory_path, current_step_id, latest_command, latest_publish_reason,
trajectory_summary
其中 trajectory_summary 必须紧凑且解析廉价,包含:
step_countcurrent_step_idlatest_commandlatest_publish_reasonlatest_bundle_idrecent_steps
这样 Agent 无需在每次循环中打开完整 trajectory 文件就能判断 session 是否在推进。canonical helper 的 summarize_trajectory 正是按此契约实现:取最后 recent_steps(默认 3)步,每步仅保留 step_id/step_index/bundle_id/publish_reason/command/command_finished_at/status/cached,并清理 None 字段(cli-anything-plugin/preview_bundle.py);Blender 的 live_status 在检测到 trajectory.json 时自动注入 payload["trajectory_summary"](blender/agent-harness/cli_anything/blender/core/preview.py)。
此外,Blender 的 session 负载还把 _session_dir 等带下划线前缀的内部引用统一通过 _with_live_refs 注入——这解释了推荐字段中为何出现 _session_dir/_session_path/_trajectory_path 这类下划线键:它们是给 Agent 定位文件用的机器字段,与人类可读字段区分。
7. README 与 SKILL 文档指引
支持预览的 Harness 必须在 README.md 和 SKILL.md 两处都讲清预览。
README.md 应覆盖:
- 存在哪些预览模式;
- 每个 recipe 产出什么;
- 如何发布 bundle;
- 如何用
cli-hub previews ...检查/watch/open; - live session 的行为方式;
- 真实性注意事项(如注入的预览相机、辅助 rig)。
SKILL.md 应覆盖:
preview下的 producer 命令表面;diff、live、poll 模式是否可用;cli-hub previews ...是只读消费者这一事实;- 面向 Agent 的
--json使用指引; - 预期的产物角色(
hero、gallery、clip、diff 输出等)。
方法论要求每个预览示例都必须同时展示两侧:
cli-anything-<software> --project demo.ext preview capture --recipe quick --json
cli-hub previews inspect /path/to/bundle
仓库中各 Harness 的 SKILL.md(如 skills/cli-anything-blender/SKILL.md、skills/cli-anything-freecad/SKILL.md)即是该规范在技能层的具体体现。
8. 何时添加 diff、live 或 poll:决策表
方法论给出的取舍标准:
| 能力 | 添加条件 | 避免条件 |
|---|---|---|
preview diff |
对比本身就是产品 | 当前状态 bundle 已能回答该问题 |
preview live |
迭代式 Agent 工作受益于稳定的“当前头部” | 工具只产出偶发的一次性导出 |
| poll-first 刷新 | 项目指纹会在 preview 命令之外发生变化 | 源指纹昂贵或更新很少 |
收尾原则同样重要:不要为了对齐另一个 Harness 而增加复杂度。只有在能力匹配软件真实迭代节奏时才添加。
9. 真实性规则(Truthfulness)
预览必须“诚实到足以支撑 Agent 决策”。数据来源按优先级排序:
- 真实后端的原生渲染/导出;
- 真实工具的原生检查或回放输出;
- 真实项目的离屏抓取辅助。
必须避免:
- 在工具之外合成的假渲染;
- 把 GUI 录屏作为主要预览产物;
- 与软件真实输出悄悄偏离的近似。
如果 Harness 需要临时辅助状态,应诚实暴露:
- 将 bundle 标记为
partial或等价状态(canonical helper 的finalize_bundle原生支持status参数,且缓存命中也接受partial,见 cli-anything-plugin/preview_bundle.py); - 在 summary/context 输出中注明注入的预览相机、灯光或辅助件;
- 在可能时把项目指纹与注入的预览 rig 分开计算。
这与协议文档的渲染规则一脉相承:允许用真实应用/后端做低分辨率预览、用 ffmpeg/RenderDoc API 等原生工具从真实渲染中提取帧,但禁止发明玩具渲染器,也禁止以无关 GUI 窗口的截图作为唯一事实源。
10. 实施检查清单
落地前逐条核对:
- [ ] 判断预览对该软件是否真正有意义;
- [ ] 定义一个或多个输出明确的 recipe;
- [ ] 发布
preview-bundle/v1bundle; - [ ] 保持 bundle、session、trajectory 三者相互独立;
- [ ] 所有 preview 命令支持
--json; - [ ]
preview latest只读; - [ ]
preview live status --json对 Agent 足够廉价; - [ ] 在 README 与 SKILL 中记录 producer vs consumer 命令;
- [ ] 验证输出确实来自真实后端。
11. 相关参考
- Harness 总纲:cli-anything-plugin/HARNESS.md
- 技能生成指南:cli-anything-plugin/guides/skill-generation.md
- 预览协议(格式契约):docs/PREVIEW_PROTOCOL.md
- 方法论原文:cli-anything-plugin/guides/preview-methodology.md
- canonical helper 源码:cli-anything-plugin/preview_bundle.py
- 消费侧查看器实现:cli-hub/cli_hub/preview.py、cli-hub/cli_hub/cli.py
- 参考 Harness 实现:blender/agent-harness/cli_anything/blender/core/preview.py
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0631
MiniCPM5-2BMiniCPM5-2B 是一款面向端侧、本地部署和资源受限场景的 2B 稠密 Transformer,能够达到同尺寸开源模型 SOTA 水平。Markdown00
video-shotcraftAI宣传片skill,使用 Remotion 制作电影级产品视频:提供106 张镜头配方卡和可复用的视频魔板。适用于 Claude Code 与 Codex以及所有其他智能体Markdown00
HivisionIDPhotos⚡️HivisionIDPhotos: a lightweight and efficient AI ID photos tools. 一个轻量级的AI证件照制作算法。Python09
DragonOSDragonOS is an operating system developed from scratch using Rust, with Linux compatibility. It is designed for **Serverless** scenarios. 使用Rust从0自研内核,具有Linux兼容性的操作系统,面向云计算Serverless场景而设计。Rust00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
