espctl deposit — 把数据主权工作流变成“默认行为“
让每一次成功 build 自动变成签名三元组
这一页是什么
姊妹页《制作者数据资产存证操作指南》讲的是手工工作流——目录结构、manifest.yaml 模板、Zenodo + OpenTimestamps + minisign 的仪式步骤。它准确、可复用、可照抄。
但它也意味着六项纪律,制作者得在每一次 build 后都自觉去做、做完几年。操作指南里写得很直白:纪律会在典型项目走到中后期就衰减,到第 2 年资产目录就会散乱。
espctl deposit 就是把这个衰减点掉的工具。它把操作指南里的步骤自动化,让:
- 每一次成功的
espctl build都可以通过一条命令变成签名、可存证的三元组:espctl deposit add <build_id>。 - AI agent(Claude Code、Cursor,任何说 MCP 的客户端)可以在每次 build 成功后自动调用
deposit.add,只问制作者三个问题(结果、证据、备注),并且永远不会在没有显式确认的情况下把数据推到 Zenodo。 - 未来的买家可以用纯
minisign -Vm && ots verify,在没有装espctl的干净 Docker 容器里独立验证任意导出包。
这是把“主权当作家庭作业“翻译成“主权当作默认行为“。强烈建议先读操作指南理解为什么这件事重要,这一页讲的是工具怎么把摩擦消掉。
你拿到的东西
一套 CLI、一套 MCP 镜像、一套 schema。
| 表面 | 命令 / 工具 | 用来干什么 |
|---|---|---|
CLI (espctl deposit <sub>) | init、add、list、verify、milestone、sign、attest、export | 手动在终端里跑 |
MCP (deposit.*) | 8 个工具,与 CLI 1:1 镜像 | AI agent 在每次 build 成功后自动调用 |
| Schema | manifest.yaml v1 + deposit.toml + INDEX.toml + 自验证脚本 | 跨版本稳定;2031 年的买家工具应该能解析 2026 年的归档 |
CLI 和 MCP 走同一套编排器——两个表面行为不可能漂移。
所有本地操作都离线工作。唯一会访问公网的命令是 attest(Zenodo + OTS),并且必须有显式确认。
CLI 命令参考
8 个子命令分布在 4 个发行版里。首个版本(init/add/list/verify)就是独立的旗舰版本,单独发布就已经覆盖了约 90% 的价值——即使后续版本永远不发布,espctl deposit 也已经能用。
espctl deposit init — 初始化工作区(v0.6.0 起稳定)
创建 ~/maker-assets/{public,private,asset}/、写入默认 deposit.toml、探测 PATH 上的 minisign,首次运行时提示注册公钥指纹。幂等:第二次执行不会修改任何文件。
espctl deposit init # 全用默认值
espctl deposit init --root /data/maker # 自定义工作区根目录
espctl deposit init --contributor-alias myhandle
init 永远不会改你的 ~/.gitconfig、也不会动你已有的 SSH key。如果 minisign 没装,会立刻 fail-fast 并给出对应平台的安装提示。
espctl deposit add <build_id> — 把一次 build 转为签名三元组(v0.6.0 起稳定)
这是工具的心脏。给一个成功 espctl build 的 build_id,这条命令会:
- 从
espctl-core读 build 上下文(芯片、IDF 版本、源码 hash、二进制 hash、size、target)。 - 自动填充能推导出来的
manifest.yaml字段:时间戳、贡献者指纹、硬件段、固件段。 - 提示(或通过参数接收)需要人判断的三个字段:
--outcome passed|failed|partial--verification-evidence <path>(可重复,至少一个)--notes <string>(可以很短;一行就够)
- 解析 slug,如果同日同名冲突,自动加
-vN后缀。 - 写出三元组目录、用 minisign 签
manifest.yaml、更新INDEX.toml。
# 交互式(缺字段时通过 prompt 询问)
espctl deposit add abc123
# 非交互式(CI / 脚本)
espctl deposit add abc123 \
--slug crsf-parser \
--outcome passed \
--verification-evidence verification/monitor-capture.log \
--verification-evidence verification/oscilloscope-ch9.png \
--notes "16 通道跟杆灵敏;CRC 失败率 < 0.1%/60s"
outcome: failed 的三元组是一等公民。失败数据的训练价值很高——别删。
espctl deposit list — 查询你的三元组(v0.6.0 起稳定)
只读;永远不会修改磁盘。可以按日期范围、outcome、签名 / 存证状态过滤:
espctl deposit list # 所有三元组
espctl deposit list --since 2026-04-01 --outcome passed
espctl deposit list --unsigned --json # JSON 输出,方便管道
espctl deposit list --unattested # 还未做 milestone 存证的
espctl deposit verify [slug | --all] — 完整性校验(v0.6.0 起稳定)
重算证据文件 hash、重新验 manifest.yaml 的 minisign 签名、检查 INDEX 一致性。退出码 = 失败三元组数(0 = 全部通过):
espctl deposit verify # 当前目录的三元组
espctl deposit verify crsf-parser-v2 # 指名 slug
espctl deposit verify --all # 遍历 asset/triples/
espctl deposit verify --all --strict # 额外要求必须已 milestone 存证
证据、签名或指纹的任何一字节翻转都会产生 InvalidSignature —— 篡改检测是协议的一部分。
espctl deposit milestone <name> — 离线打包(v0.6.1 起稳定)
把 N 个三元组打包成确定性的 <name>.tar.gz,附带 metadata.json(Zenodo 草稿就绪)和 minisign 签名。纯离线 —— 不会联系任何外部服务。
espctl deposit milestone 2026-05 # 2026 年 5 月的所有三元组
espctl deposit milestone phase-3 --slugs slugs.txt # 显式给 slug 列表
espctl deposit milestone 2026-Q2 --include-failed # 把 outcome:failed 也打进来
打包是可重现的:同样输入两次会产生完全相同的 tarball 字节流。
espctl deposit sign <path> — 通用 minisign 包装器(v0.6.1 起稳定)
minisign -Sm / -Vm 之上的薄便利层。用来签三元组生命周期之外的任何东西(发行说明、blog 草稿、临时文件):
espctl deposit sign milestone-2026-05.tar.gz # 产出 .minisig
espctl deposit sign milestone-2026-05.tar.gz --verify
espctl deposit attest <milestone> — Zenodo + OTS(v0.7.0 起稳定)
**全局唯一的联网命令。**把 milestone 包上传到 Zenodo(拿 DOI)、用 OpenTimestamps 打时间戳(拿到 Bitcoin 锚定的 .ots),并把两份回执写进 asset/deposits/。
Zenodo 发布不可逆 —— DOI 是永久的。这条命令在没有显式确认时会拒绝执行:
espctl deposit attest 2026-05 --confirm # Zenodo + OTS 都做
espctl deposit attest 2026-05 --ots-only # 只 OTS(不需要确认,因为不是不可逆)
espctl deposit attest 2026-05 --zenodo-only --confirm
没加 --confirm 会以 ConsentRequired 退出。没有任何环境变量、配置项、agent 设置可以绕开这道闸。工具的每一层都在强制它。
espctl deposit export <slug | --slugs FILE> — 给买家的可验证包(v0.7.0 起稳定)
构造一个自包含的 export.tar.gz,里面打包三元组、minisign 公钥、Zenodo DOI 回执、OTS 时间戳、以及一份 VERIFY.md 说明文档——让买家不需要装 espctl 就能完成验证。包里附一份能在干净 Docker 容器里跑的 shell 脚本:
espctl deposit export crsf-parser-v2 --out crsf-parser-v2-export.tar.gz
espctl deposit export --slugs license-batch.txt --out 2026-Q2-license-bundle.tar.gz
espctl deposit export crsf-parser-v2 --redact-keys --out preview.tar.gz # 买家先看后签前的预审版
--redact-keys 会去掉制作者的标识 handle,做“先看后签“的远距预审。密码学签名和 Zenodo DOI 保留——买家仍能验出处,只是看不到身份。
MCP 工具表面
每个 CLI 子命令在 deposit.* 命名空间下都有一个 1:1 的 MCP 镜像。AI agent(Claude Code、Cursor、任何说 MCP 的客户端)直接调它们。CLI 和 MCP 共享同一套编排器——表面之间不可能漂移。
| 工具 | 权限类别 | 返回 |
|---|---|---|
deposit.init | 写(本地) | { root, created_new, signing_key_existing } |
deposit.add | 写(本地) | { slug, signed } 或 NeedsMakerInput 信封 |
deposit.list | 只读 | [ TripleRecord ] |
deposit.verify | 只读 | [ VerifyReport ] |
deposit.milestone | 写(本地) | { name, triple_count, tarball_path, sha256 } |
deposit.sign | 写(本地) | { signed } 或 { verified } |
deposit.attest | 写(不可逆,联网) | { doi?, ots_stamp? } 或 ConsentRequiredError |
deposit.export | 写(本地) | { output_path, sha256 } |
Agent 权限策略应当区分对待这三类:只读永远放行;本地写每次询问;deposit.attest 必须每一次都人工确认。同意闸做在工具层,无论 agent 自己的本地策略允许什么。
三问 Agent 流程
agent 用 auto_fill: true 调 deposit.add 时,会得到两种回应之一:
Ok { slug, signed }—— agent 有足够上下文(比如来自会话 prompt 历史)填齐了所有必填字段。三元组已签。完成。NeedsMakerInput { fields: [outcome, evidence_paths, notes], prompt: "..." }—— agent 把恰好三个问题转给制作者,拿到答复后重新调一次deposit.add。
这就是杠杆点。制作者敲三个短答案,剩下的全由 agent 做。字段列表恰好是三个,且这是协议的一部分——任何 agent / 模型都不能扩展它。
Agent 绝不会自动做的事
- 在没有
explicit_consent: true的情况下推到 Zenodo。这道闸在工具服务端、不在 agent 的 prompt 里。 - 凭空合成验证结论。如果 agent 没有 ground-truth 证据,必须调
NeedsMakerInput,不能猜outcome: passed。 - 修改你的
~/.gitconfig或 SSH key。deposit init自带这条不变量;测试套件强制它。
一次典型会话
制作者跑完一次 build,看了 monitor 输出,决定存证。Claude Code agent 在跑:
maker: build 看着没问题——通道跟杆、CRC 稳定。存了吧。
agent: [调 deposit.add build_id=abc123 auto_fill=true]
→ NeedsMakerInput { fields: [outcome, evidence_paths, notes] }
agent: 我需要三件事才能完成三元组:
1. 结果:passed / failed / partial?
2. 这次 build 哪些文件作为验证证据?
3. manifest 的一行备注。
maker: passed;monitor-capture.log 和 oscilloscope-ch9.png;
16 通道跟杆,CRC < 0.1%/60s。
agent: [带齐三个字段重新调 deposit.add]
→ Ok { slug: "2026-05-15-crsf-parser-v2", signed: true }
agent: 完成。三元组已签;INDEX 已更新。本月你有 23 个未存证三元组——
想打包时说 "milestone 2026-05"。
端到端钟表时间约 30 秒——大部分时间是制作者敲那三个回答。
配置
~/.config/espctl/deposit.toml 控制默认值:
[deposit]
root = "~/maker-assets"
default_contributor_alias = "myhandle"
auto_suggest = true # build 成功后打印 "提示:deposit add <id>"
[deposit.signing]
key_path = "~/.ssh/id_ed25519"
minisign_pubkey_path = "~/.config/espctl/minisign.pub"
[deposit.zenodo]
api_token_env = "ZENODO_API_TOKEN"
community = "" # 可选 Zenodo community
default_license = "all-rights-reserved"
[deposit.ots]
calendars = ["https://alice.btc.calendar.opentimestamps.org", "https://bob.btc.calendar.opentimestamps.org"]
[deposit.defaults]
include_failed_in_milestone = true
require_signature_on_add = true
顶层未知字段会被容忍(以便未来版本添加新设置不会弄坏你的配置)。段名与已存在字段名跨所有 0.x 版本保持稳定。
故意不在范围内的事
espctl deposit 是主权工具,不是市场。下列是有据可查的非目标——不会在后续版本里加,这是写在测试和 CI 里的架构承诺:
- 不做数据集交易、撮合。没有挂牌、没有托管、没有分润、没有价格发现。key 在你手里;谈判你自己谈。esphome.cloud 不抽任何制作者-买家交易的百分比。
- 不集中托管资产层。三元组永远不离开你的机器,除非是你亲自跑的命令并附完整回执。esphome.cloud 服务器不存你的 asset 目录。
- 不打质量分。工具不评断你的三元组“比另一份值钱“。这交给买家和参考价决定,不是工具。
- 任何
deposit-*crate 都不上传分析或遥测。1,000 次调用的审计必须显示零对 esphome.cloud 域名的 HTTP 请求。CI 用cargo deny+ grep 强制这条。 - 不用 GPG。SSH + minisign 是唯一签名路径。(操作指南 §4 解释了为什么。)
- 不把 IPFS 作为主存证。仅 Zenodo + OTS 双存证。IPFS 钉是不持久的、扛不住制作者疏忽。
- 永远不会自动推到 Zenodo,每一层都要显式确认。DOI 是永久的;闸是结构性的。
- 不在资产层内部做 RAG / 向量库索引。向量存储是消费层产物,不能写进
asset/triples/。无论你是否在跑 embedder,deposit add都正常工作。
这张清单不是建议 —— 它是架构栅栏。如果未来某个版本加了上面任何一项,那个版本就不是 espctl deposit,是另一个名字下的另一个产品。
发布路线
| 版本 | 主题 | 新增表面 | 状态 |
|---|---|---|---|
| v0.6.0 | 核心 CLI | init、add、list、verify + manifest.yaml v1 schema | 独立旗舰。约 90% 的价值在这里落地。 |
| v0.6.1 | milestone + sign | milestone、sign | 离线打包。 |
| v0.7.0 | attest + export | attest(Zenodo + OTS)、export(买家包) | 唯一联网版本。 |
| v0.8.0 | MCP 镜像 | 8 个 deposit.* 工具 + agent 流程 | 启用三问 agent 工作流。 |
| v0.9.0 | 生态钩子 | espctl build 成功提示、espctl monitor 归档 | 可选。2026-05-21 形式上跳过;如使用数据证明值得,可再入。 |
| v1.0.0 | — | SemVer 承诺全面生效 | v0.8.0 在真实制作者工作流跑过 ≥ 3 个月之后。 |
v0.6.0 独立可发的约束是结构性的:即便后续版本永不发布,v0.6.0 本身就是一个完整的主权工具。后续版本是叠加,不是必需。
不装 espctl 也能验出处
这是 2031 年买家在意的那道题:
# 买家展开一份由 espctl deposit export 导出的包
tar xzf 2026-Q2-license-bundle.tar.gz
cd 2026-Q2-license-bundle/
# 买家读 VERIFY.md,然后在干净 Docker 容器里跑包内附带的脚本
docker run --rm -v "$PWD:/work" -w /work alpine:latest sh ./verify.sh
# verify.sh 会在容器里装好 minisign 和 ots,然后执行:
# minisign -Vm manifest.yaml -p contributor.pub
# ots verify milestone-2026-Q2.tar.gz.ots
# 两者都必须以 0 退出。
如果两项都通过,买家在密码学层面证明了:
- 三元组由贡献者的公钥(离线由制作者持有)签发。
- milestone 包在某个 Bitcoin 区块之前就已存在(因此在某个日期之前已存在)。
- Zenodo DOI(也在包内)是当时作者身份的公开记录主张。
三条独立的账本,任何一个陌生人在多年之后、从干净容器里都能验。
这才是真正的产品。
另见
- 《制作者数据资产存证操作指南》 ——
espctl deposit所自动化的手工操作指南。没读过先读它。 - 《制作者数据主权宣言》 —— 解释为什么这件事重要。
- 构建生命周期 —— 成功的
espctl build是三元组的入口。
esphome.cloud / Aegis
2026 年 5 月