Beads Wisps 使用指南:用 vapor 相分子管理一次性运维工作
【免费下载链接】beadsBeads - A memory upgrade for your coding agent项目地址: https://gitcode.com/GitHub_Trending/beads1/beads
运营类工作流——发布检查清单、健康巡检、诊断任务——一旦关闭,它们产生的 bead 就失去了任何审计价值。Wisps(蜃景分子)正是在这种场景下诞生的:它们是实例化于vapor 相(气态相)的分子(molecule),是你能用正常bd命令照常推进的真实 bead,只是被打上了Ephemeral=true标记,从而不参与同步、也不进入共享审计轨迹,之后可以整体批量删除。
本文以 docs/workflows/wisps.md 为核心,结合 Beads 仓库的 CLI 实现(主要位于 cmd/bd)与存储层代码,系统讲解 Wisps 的定义、与持久分子(Pour)的差异、完整生命周期操作、批量管理与回收策略,以及何时该"提升"(squash)而非"焚毁"(burn)一个 Wisp。
什么是 Wisps
从概念上讲,Wisp 具备三个核心特征:
- 本质是普通 issue:Wisp 是主数据库中设置了 ephemeral 标记的 issue,你可以用所有常规
bd命令(bd ready、bd update、bd close)正常推进它,它只是"活不过"自己的使命。 - 本地优先设计:默认被排除在联邦推送之外(
federation.exclude_types默认为[wisp]),也不属于共享审计轨迹的一部分。 - 批量删除:关闭后由
bd purge或bd mol wisp gc批量清理。
这一设计在配置层有直接印证:在 internal/config/config.go 中,Beads 显式设置了默认值v.SetDefault("federation.exclude_types", []string{"wisp"}),其注释说明这正是"从联邦推送中排除的 issue 类型(隐私过滤器)"。也就是说,Wisp 从配置层面就是一个刻意与共享审计轨迹隔离的隐私安全区——巡检、排障、发布执行这些过程数据不会污染主审计流。
在存储与 API 层,同样存在完整的 ephemeral 支持:例如 internal/storage/dolt/ephemeral_routing.go 专门负责 ephemeral 记录的读写路由,internal/httpapi/reads.go 等 HTTP API 也提供对 ephemeral 记录的处理,说明 Wisp 机制贯穿 CLI、存储与 HTTP API 三层。
Wisp 与 Pour:气态与液态的选择
bd mol命令族用"物相"来区分两种分子实例化方式(见 cmd/bd/mol.go 的命令总览):
- Pour(浇铸):
bd mol pour—— 液态相(liquid phase),实例化出持久分子,写入历史、参与同步,适合任何日后值得回引用的工作。 - Wisp(蜃景):
bd mol wisp—— 气态相(vapor phase),实例化出临时分子,用完即焚,适合发布执行、运维循环、健康检查。
两者在实现上的分水岭就是spawnMolecule函数中的ephemeral参数(见 cmd/bd/mol.go):它把Ephemeral: ephemeral写进CloneOptions,再交给底层的cloneSubgraph去实例化整个子图。也就是说,bd mol pour与bd mol wisp共享同一套子图克隆与变量替换机制,唯一的差异就是这一个 ephemeral 开关。
| 维度 | 分子(bd mol pour) | Wisp(bd mol wisp) |
|---|---|---|
| 持久性 | 永久,属于历史的一部分 | 临时,任务结束即清除 |
| 同步 | 像普通 bead 一样同步 | 默认排除在联邦推送之外 |
| 适用场景 | 功能开发、任何日后值得引用的事 | 发布执行、运维循环、健康检查 |
Formula 的 vapor 相声明
Formulas(配方)可以声明phase = "vapor"来推荐 wisp 实例化——此时如果仍然执行 pour(浇铸一个 vapor 相配方),Beads 会给出警告。这给了团队一种"把运维流程固化成模板,并默认以临时实例落地"的标准化手段:同一个发布配方,既可以被浇铸成带审计的持久分子,也可以被实例化成用完即删的 wisp,取舍权交给操作者。
Wisp 的完整生命周期
Wisp 的生命周期可以拆成"创建 → 执行 → 收尾"三个阶段,官方文档给出的操作序列如下:
# 1. 创建 —— 从 proto 模板实例化,或临时即兴创建 bd mol wisp <proto-id> [--var key=value] bd create "One-off check" --ephemeral # 2. 执行 —— 常规 bd 操作对 wisp issue 完全可用 bd ready --mol <wisp-id> bd update <id> --claim bd close <id> # 3a. 保留:squash 提升为持久记录(清除 ephemeral 标记) bd mol squash <wisp-id> # 3b. 焚毁:直接删除,不生成 digest bd mol burn <wisp-id>创建:模板实例化与即兴创建
两条创建路径各有适用场景:
bd mol wisp <proto-id> [--var key=value]:从一个 proto(模板)实例化出整套工作子图,--var用于替换模板中的{{key}}变量。适合把标准化流程(发布、巡检)快速展开为一次性执行副本。bd create "One-off check" --ephemeral:即兴创建一个带 ephemeral 标记的单一 issue,适合临时想到的快速检查。
在 cmd/bd/create.go 中可以看到,--ephemeral与--no-history是互斥的(--ephemeral and --no-history are mutually exclusive),而--storage-class ephemeral则是--ephemeral的完整拼写形式,同样与--no-history互斥;如果显式指定了其他 storage-class(如versioned/unversioned)又与 ephemeral 语义冲突,命令会直接拒绝。这说明 ephemeral 是一个独立的"wisp-plane"(气态平面)记录概念,与 durable(持久)类记录是正交的两套语义,不能混用。
执行:与普通 issue 无异
Wisp 是"真实的 bead"这一设计决定了它的执行路径零学习成本:bd ready、bd update --claim、bd close等所有常规命令都直接作用于 wisp issue。这也正是文档所称"real beads you work through normally"的工程落地——CLI 层没有为 wisp 另起一套命令,只是在其生命周期收尾时提供专用操作。
收尾的两种结局
每个 wisp 最终都要面对二选一:
bd mol squash <wisp-id>:把 wisp 的临时子 issue 汇总成一份摘要 digest,并将子项提升为持久记录(清除Ephemeral=true标记)。从 cmd/bd/mol_squash.go 的实现看,squash 会:收集分子下所有 ephemeral 子 issue → 生成摘要 digest(Ephemeral=false,永久保留)→ 清除子项的 wisp 标记完成提升 → 若根节点也是 wisp 则自动关闭它并清除其标记,避免该根节点在每个 wisp 表导出周期中被反复重新发射。bd mol burn <wisp-id>:不生成 digest 直接删除,且不可逆。
burn 的细节与安全护栏
cmd/bd/mol_burn.go 的实现给出了 burn 的完整行为:
- 按相分流:Wisp(ephemeral)走直接删除路径(
burnWispMolecule),持久分子(mol)走级联删除路径(burnPersistentMolecule,会同步到远端)。 - 批量支持:
bd mol burn bd-a1 bd-b2 bd-c3可一次焚毁多个分子,并自动按 ephemeral/持久分类处理。 - 安全选项:
--dry-run预览将删除的内容、--force(或-y)跳过确认、不传--force时会有Continue? [y/N]交互确认;wisp 焚毁在单个事务内原子完成(burnWisps通过transact包裹),任一删除失败则整体回滚,杜绝部分删除。 - 明确提示:burn 前会提醒"不会生成 digest,若想保留摘要请用
bd mol squash"。
从源码注释看,burn 的典型适用对象包括:废弃的巡检循环、崩溃或失败的工作流、以及不想保留的测试/调试分子。
管理 Wisps:列表、GC 与全量清除
官方文档给出三个管理命令:
bd mol wisp list # 列出当前上下文中的所有 wisps bd mol wisp gc # 垃圾回收陈旧/废弃的 wisps bd purge --force # 删除所有已关闭的 ephemeral beadsbd purge的实现位于 cmd/bd/purge.go,其定位是"删除已关闭的 ephemeral beads 以回收空间",并且与处理持久记录的bd prune明确分工、互不越界。值得注意的几个细节:
- 默认安全:
bd purge不带--force时只是预览(DryRun: dryRun || !force),必须显式加--force才真正执行删除。 - 时效过滤:
bd purge --older-than 7d --force只清理关闭 7 天以上的记录。 - 模式过滤:
bd purge --pattern "*-wisp-*"只清除 ID 匹配 glob 的记录,适合只清理某一批特定命名的 wisp。
这些参数让bd purge从"一刀切"变成"可精细控制的批量回收",可以在运维节奏中定期执行。
强制物相:用 bond 覆盖相位
bd mol bond在组合工作时接受相位覆盖。官方文档的示例非常典型:
bd mol bond mol-critical-bug wisp-patrol --pour # 把巡检中发现的 bug 持久化为正式记录这个场景精准体现了 wisp 的价值:在一次 wisp 巡检(wisp-patrol)中发现了严重 bug,你并不想让这次巡检本身进入审计轨迹,但 bug 本身必须被正式记录。--pour覆盖让组合结果以持久相位落地,实现了"过程临时、成果永久"的完美分工。
最佳实践:什么该 wisp,什么该 pour
- Wisps 用于运维循环——巡检、发布执行、诊断任务这类"结束即无价值"的工作。
- Molecules 用于受跟踪工作——任何有审计价值的内容都应该 pour,而不是 wisp。
- 删除之前先 squash——如果 wisp 暴露出了值得保留的成果,用
bd mol squash提升它;burn 不可逆。 - 定期垃圾回收——
bd mol wisp gc或bd purge --force,防止临时记录堆积占用存储。
从仓库的测试覆盖也能看出这条工作流是被认真对待的一等公民:例如 internal/storage/dolt/count_include_wisps_test.go 验证统计是否包含 wisp、internal/storage/dolt/demote_to_wisp_test.go 验证降级为 wisp 的路径、cmd/bd/import_promoted_wisp_embedded_test.go 验证被 squash 提升后的 wisp 在导入导出中的表现。这些测试共同确认了 wisp 在创建、计数、降级、提升、导入导出各环节的行为一致性。
小结
Wisps 是 Beads 为"过程无价、结果归零"的运维类工作设计的轻量记录形态:以Ephemeral=true标记与持久记录区隔,默认不参与联邦推送与审计轨迹,配合bd mol wisp(创建)、bd mol squash(提升)、bd mol burn(焚毁)、bd purge(批量回收)组成完整的生命周期闭环。理解 Wisp 与 Pour 的分工、掌握 squash/burn 的取舍,是让 Beads 仓库在长期演进中保持审计轨迹干净、存储不膨胀的关键实践。
【免费下载链接】beadsBeads - A memory upgrade for your coding agent项目地址: https://gitcode.com/GitHub_Trending/beads1/beads
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考