源码不再只是代码
今天 HN 上几篇内容,表面上方向不同:Zed 发布 DeltaDB,Coder 开源 Boo,Homebrew 6.0.0 引入 tap trust,还有一篇文章注意到 OpenAI 服务条款里出现了 on-prem 相关的 Licensed Materials。再加上一篇很短但很准确的团队协作文章《If You are Asking for Human Attention, Demonstrate Human Effort》,它们放在一起看,其实都在回答同一个问题:软件的"来源"到底是什么。
过去这个问题很好答。源码在 Git 仓库里。commit 是边界,pull request 是讨论场,CI 是验证场,release 是交付场。人写代码,人写说明,人 review diff。虽然现实也没这么整齐,但工具链默认软件是由一系列离散快照构成的。
AI agent 进入开发流程后,这个假设开始松动。
Zed 的 DeltaDB 直接把这个变化说出来:software is made between commits。它认为,越来越多代码不是在 commit 里突然出现的,而是在开发者和 agent 的对话、编辑、运行、修正过程中逐步成形。Git 记录的是某个时刻的快照,但真正的上下文在快照之间:为什么改这里,agent 根据哪段对话写了这行,后来谁又碰过它,当时 worktree 是什么状态。
DeltaDB 的设计是把 worktree 拆成细粒度 delta,而不是只记录 commit。每个 delta 有稳定身份,可以引用代码演化中的任意时刻。对话消息和它产生的编辑被并排记录。多人和多个 agent 可以同时编辑同一个 worktree。更重要的是,从代码可以追溯到产生它的对话,从过去对话也可以跳到当前代码或当时代码。
这不是普通的版本控制包装。它是在说:如果 agent 参与了写代码,那么"源"不只是文件内容,还包括生成文件的会话轨迹。
这点很重要。传统 code review 里,我们 review diff。diff 虽然不完整,但至少假设作者脑子里的上下文可以通过描述补出来。AI 生成代码后,这个假设变弱了。作者可能只是给了一个方向,agent 生成了几轮实现,中间运行了测试,改了错误,又接受了某个建议。最终 diff 看起来干净,但它隐含了一条生成路径。路径里可能有误解、删减、未验证假设、从旧代码里继承的错误。
如果只看 commit,很多关键问题会消失。为什么 agent 选择这个抽象?它有没有读错某个接口?它有没有因为测试失败而绕开约束?开发者有没有真正看过生成结果?这些东西不是注释,也不是 commit message 能稳定承载的东西。它们更像"源码旁边的意图日志"。
Tom Bedor 那篇短文从团队礼仪角度讲了同一件事。他提出一个原则:如果你要求别人付出人类注意力,就要展示人类努力。不要把自己没读过的 AI 输出转发给同事,然后让别人花时间判断它对不对。AI 文本可以有用,但你需要标注它,消化它,加上自己的判断。代码 review 也是一样,AI 生成的代码应该先由提交者自己 review。
这听起来像礼貌,其实是协作协议。注意力是团队里最稀缺的资源。AI 让生成成本下降,但阅读、判断和承担责任的成本没有同步下降。如果一个人把未消化的 AI 输出丢给另一个人,等于把验证成本外包给对方。软件团队需要新的信号:哪些内容是模型生成的,哪些是人确认过的,哪些假设还没验证,哪些地方需要真正 review。
所以 DeltaDB 记录对话,和"请求注意力要展示人类努力",其实是一件事的两面。前者解决机器层面的 provenance,后者解决人类层面的责任归属。代码从哪里来,不只是 Git hash 的问题,也是"谁理解过它"的问题。
Coder 的 Boo 则把"来源"扩展到运行状态。Boo 是一个类似 GNU screen 的终端复用器,基于 libghostty 的终端模拟核心。它的关键点不是又一个 terminal multiplexer,而是它会解析每个 session 的输出,保存精确屏幕状态:内容、样式、光标、scrollback、终端模式。这样重新 attach 时可以恢复画面,脚本和 AI agent 也可以通过 peek、wait、send 等命令稳定读取和驱动交互式程序。
这对 agent 很实际。很多开发工具不是纯文本命令,而是 TUI、REPL、watcher、调试器、安装器。传统自动化经常靠 sleep、grep 日志、硬拷贝输出,脆弱又不准确。Boo 的思路是把"人眼看到的终端状态"变成可查询对象。agent 不是读原始字节流,而是读渲染后的屏幕状态;不是盲等几秒,而是等屏幕出现某个文本或进入 idle。
这说明运行时状态也在变成一种 source。代码为什么这么改,不只来自对话,也来自某次终端里发生了什么:测试失败在哪里,迁移脚本问了什么,debugger 停在哪一行,watch mode 什么时候稳定。过去这些信息常常散落在人的记忆或 CI 日志里。agent 时代,它们需要被结构化,否则自动化只能在黑暗里敲键盘。
嗯,幽灵终端这个名字倒是贴切。很多 bug 本来就像幽灵,只有在某个会话状态里才出现。你不保存那个状态,它就飘走了。
Homebrew 6.0.0 的 tap trust 把来源问题带到供应链。第三方 tap 可以包含任意、未沙箱化的 Ruby 代码,会在用户机器上执行。Homebrew 现在要求第三方 tap,以及 tap-qualified formulae 和 casks,在代码被评估或运行前必须显式信任。官方 tap 默认可信,第三方 tap 需要用户确认。
这和 npm v12 默认不执行依赖安装脚本是同一条线:来源不能只靠包名和生态习惯隐式信任。以前安装工具追求顺滑,第三方源越容易接入越好。现在供应链攻击太常见,工具链开始把"这个源是否可信"从背景假设变成显式状态。
这也是源码概念的扩展。我们不仅要知道代码文件来自哪里,还要知道它所属的分发源是否被信任、信任是什么时候授予的、授予对象是官方还是第三方、执行前有没有跨过信任边界。对开发者来说,brew install foo/bar/baz 不再只是解析一个 formula,而是在本地执行第三方 Ruby 之前做一次来源确认。
OpenAI on-prem 条款则把来源和副本管理带到部署合同。那篇文章注意到 OpenAI 服务条款里出现了 Licensed Materials:包括软件、包、代码、容器或模块,可以被交付到本地机器、私有云或客户管理系统上运行。条款要求合同终止时,客户永久删除 Licensed Materials 及所有副本。
这可能只是为未来产品铺路,但它揭示了 on-prem AI 的一个常被低估的问题:本地部署不是"云 API 搬进机房"这么简单。一旦模型、容器、运行模块进入客户环境,它们就变成需要治理的物品:谁能复制,能不能修改,能不能再分发,合同结束后如何证明删除,备份、镜像、缓存、CI artifact、灾备系统里是否还有副本。
企业喜欢 on-prem,是因为数据边界、延迟、合规和控制权更清楚。但供应商也会在合同里重新定义软件边界。模型权重、runtime、container image、license key、更新包,每一个都是需要追踪的资产。你不能只问"推理跑在哪里",还要问"供应商材料在哪里留下了副本"。
这和 Homebrew tap trust 是同一类问题,只是层级不同。一个发生在开发者电脑上的包管理器,一个发生在企业 AI 部署合同里。共同点是:软件来源、授权和生命周期必须显式化。
把这些内容串起来,会看到软件工程里的 source 正在从四个方向扩展。
第一,意图成为 source。DeltaDB 记录对话和编辑的对应关系,是因为代码的理由不再总能从 diff 里推出来。agent 参与越多,意图日志越重要。未来的 review 可能不只是 review code diff,还要 review 关键 prompt、agent 决策、被接受和被拒绝的修改路径。
第二,状态成为 source。Boo 保存终端屏幕状态,是因为许多开发事实发生在运行过程中。测试输出、交互式命令、TUI 状态、watcher 稳定性,都会影响 agent 下一步行为。没有结构化状态,agent 自动化会退回脆弱的 sleep-and-poll。
第三,信任成为 source。Homebrew tap trust 说明,软件来自哪个源、是否被显式批准、是否能运行本地代码,已经是构建结果的一部分。供应链安全不是安装之后再扫描,而是安装之前就要定义信任边界。
第四,契约成为 source。OpenAI on-prem 条款说明,本地运行的软件材料有合同生命周期。代码能不能复制、何时删除、谁负责销毁副本,都会影响系统设计。法律条款听起来离工程很远,但它会决定镜像仓库、备份策略、访问控制和退出计划。
这些变化都和 AI 有关,但不是因为 AI 神奇地改变了一切。更准确地说,是 AI 把原本隐含的工程事实放大了。
以前人类写代码时,对话和意图在脑子里;现在 agent 生成代码,对话需要持久化。以前人类看终端,屏幕状态在人眼里;现在 agent 要操作终端,屏幕状态需要机器可读。以前第三方包偶尔执行脚本,风险可被经验压低;现在自动化高频安装和运行依赖,信任需要显式化。以前 on-prem 软件部署是少数企业采购问题;现在高能力模型和私有数据结合,本地 AI 运行会越来越常见,副本治理就变成工程问题。
这对团队有几个实际启发。
第一,不要把 AI 生成的代码只当普通 diff。至少要保留关键生成轨迹:需求、约束、模型修改过的区域、失败过的测试、人工确认点。不是每次对话都要永久归档,但重要变更应该能回答"这段代码为什么这样写"。
第二,给 agent 使用的终端和工具要有可观察状态。能返回 JSON 就返回 JSON,不能返回 JSON 的交互式程序也要有稳定的 screen state、wait condition 和超时机制。让 agent 读原始日志然后猜屏幕,迟早会出事。
第三,供应链工具默认值要从便利转向显式信任。第三方源、安装脚本、远程 tarball、Git dependency、tap、插件,都应该有可审计的批准记录。自动化越强,默认执行越危险。
第四,on-prem AI 要提前设计退出机制。很多人只关心部署成功,却忽略终止合同后的删除证明、镜像清理、备份过期、日志留存和密钥回收。真正的私有化部署,不只是进入客户环境,也要能干净地离开客户环境。
软件工程过去很依赖"代码即真相"。这句话仍然有用,但已经不够完整。代码当然重要,可现在还要看生成它的对话、运行它的状态、安装它的信任路径、部署它的合同边界。
源码不再只是代码。源码正在变成一组可追溯关系:人、模型、工具、状态、信任和契约之间的关系。
这听起来麻烦。嗯,是麻烦。但比起让未来的自己在一堆 AI 生成 diff、终端幽灵、未知第三方脚本和删不干净的 on-prem 镜像里考古,还是现在多记一点比较省事。