Engineering Execution Control Plane
ExecRelay
ExecRelay 是一个面向软件工程执行过程的本地工具,把命令执行、进程结果、验证结果和代码变更记录为彼此独立、又可以追踪关联的工程事实。它不从终端文本或 AI Agent 的描述中“推测”任务是否成功,而是保留真实的进程结果和可核查的工程证据。
- 状态
- v0.1.2 · Developer Preview · macOS on Apple Silicon
- 技术栈
- Rust
- Tauri
- TypeScript
- React
- PTY
- Shell 集成
- 结构化证据
- 验证
- Git 证据
- Agent 适配器
ExecRelay 是什么
ExecRelay 看起来像一个终端,但它关心的不只是“命令跑完了没有”。它把一次工程任务里经常被混为一谈的几件事分开记录:
- 执行了什么:哪条命令、在哪个目录、以什么方式运行。
- 进程实际发生了什么:生命周期、退出码,以及这个结果从哪里来。
- 验证了什么:明确的验证条件是否被可信的进程结果满足。
- 代码仓库发生了什么变化:在一段时间窗口前后,仓库里观察到了哪些改动。
这些都是相关但彼此独立的工程事实。ExecRelay 分别记录它们,再通过明确的引用关系把它们连接起来。
为什么需要它
开发者、脚本和 AI 编程 Agent 都会给出同样的说法:命令成功了,测试通过了,构建是干净的,这些文件改过了,任务完成了。
这些都是“声明”。大多数时候它们是真的,正因如此,人们很容易不再核对。终端输出会滚走或被截断,总结描述的往往是“打算做什么”而不是“实际运行了什么”,而 Agent 的收尾消息,本身就是被评估的那个系统写出来的文字。
传统终端和 AI 编码工具通常把命令、输出、验证和代码修改放在同一个交互流程里:
- Agent 说“测试通过”,并不等于测试进程真的以成功状态退出;
- 命令执行成功,也不等于修改后的代码已经通过验证;
- Git diff 是代码变化的证据,但不是执行成功的证据。
随着越来越多的工程工作交给 Agent 完成,真正有用的问题从“它说了什么”变成了“实际发生了什么,这些事实能支持什么结论”。ExecRelay 用记录而不是叙述来回答后一个问题。
- Agent 的声明is not the same as进程结果
- 终端输出is not the same as结构化证据
- 执行is not the same as验证
- 仓库变化is not the same as变更归因
AI 生成的文字永远不会被当作进程事实。这是一条关于“每个事实从哪里来”的建模原则,并不是防篡改承诺,也不是通用的安全保证。
v0.1.2 当前提供什么
v0.1.2 是面向 macOS(Apple Silicon)的开发者预览版(Developer Preview)。公开版本包含四个相互配合的功能区:
| 功能区 | 作用 |
|---|---|
| Terminal | 在真实 PTY 中运行命令,支持分屏和日常命令行工作流。 |
| Capture | 记录每次执行的真实进程结果和执行证据。 |
| Verify | 按明确的验证条件运行检查,并单独保留验证结果。 |
| Changes | 以只读方式观察 Git 仓库变化,并与对应的执行和验证关联起来。 |
终端本身被设计为独立于采集工作:观察工作的过程,不应该破坏工作本身。
Capture
每条命令都会成为一条 Execution 记录,包含生命周期、结果、退出码,以及这个结果的来源。
- 结果默认为“未知”。 只有在拿到来自可信来源的真实退出码时,结果才会变成成功或失败;退出码从不靠推断得出。
- 不读文字判断成败。 看起来像报错的输出只能作为提示,不能把结果改成失败。
- Shell 集成按会话关联。 终端使用标准的提示符与命令标记,并带有每个会话独有的随机值;没有正确随机值的标记会被视为不可信,因此仅仅模仿标记的输出无法设定结果。这是会话关联,不是密码学认证。
- 保留原始证据。 原始终端输出(包括控制序列)按证据块保存,阅读用的整洁文本由它派生。确定性的、带版本的解析器会从中提取 Jest、Vitest、pytest、
cargo test和 TypeScript 编译器的结构化结果,并注明来源证据块;未知的数值保持未知,不会被补全。
结构化证据用来解释结果,而不是决定结果。
Verify
执行回答的是“运行时实际发生了什么”,验证回答的是“可信证据是否满足某个具体要求”。两者是不同的事实。
验证配置是一组命令条件,每条都写明期望的退出码。运行它会生成一条 VerificationRun:
- 验证条件会被快照进这次运行,之后修改配置也不会改写历史结果;
- 每个条件作为普通执行运行,并按明确的身份匹配回来,用户在运行中途手动输入的命令无法满足某个条件;
- 条件只依据可信退出码判定通过或失败;结果未知、不可信或被中断时,记为无法评估,而不是猜一个结论;
- 判定过程中没有启发式规则,也没有模型判断,只有确定性的比较;
- 每个条件可以有自己的工作目录,因此适用于 monorepo。
Changes
仓库状态由只读的 Git 采集器收集,并且有意加了限制:
- 不经过 shell,只允许运行
git和批准过的子命令,带有修改性质的参数会在执行前被拒绝; - 输出有上限,运行有时限;
- 只收集摘要(分支、HEAD 提交、工作区状态、按文件的 diff 统计),默认不保存完整 diff 内容;
- 每条记录都注明采集器、版本、采集批次和仓库根目录。
ChangeAttribution 比较时间窗口前后的两个仓库快照。它会先对基线分类(干净、本来就有改动、部分可用、不是 Git 仓库),再对每个文件分类,并把局限性一起记录下来,例如同一时间窗口内可能有其他进程也改动了仓库。
它说明的是仓库在这段时间内发生了变化,而不是某次执行是唯一原因。采集器出错,也不会改变任何执行结果或验证结论。
工程模型
无论是开发者输入的命令、验证检查、只读的 Git 采集器,还是 Agent 发出的命令,最终都会成为同一种 Execution 记录。证据、验证和变更归因是各自独立的记录,通过 id 指回执行。
谁在运行
开发者
真实 PTY 中的交互式终端会话。
验证运行
执行明确验证条件里的命令。
AI 编程 Agent开发中
AgentRun 与 AgentEvent 关联到执行记录,而不是取代它们。
每条命令都成为
进程事实
Execution
每条命令一条记录:生命周期、结果、退出码,以及结果来源。
产生
证据
原始证据块
原始终端字节,以及由此派生的整洁文本。
结构化证据
解析出的测试与类型检查结果,注明来源证据块。
仓库快照
只读的 Git 状态:分支、HEAD、状态、diff 摘要。
支撑
结论
VerificationRun
可信退出码是否满足这次运行快照下来的验证条件?
ChangeAttribution
在前后两个快照之间,仓库里发生了什么变化?
为什么“执行事实”很重要
决定结果的
- then
命令
- then
Execution
- then
可信退出码
条件结果
解释结果的
- then
Execution
- then
原始证据块
- then
解析器
结构化证据
只有可信的进程结果能决定成败;输出、解析结果和 Agent 的描述只能帮助理解这个结果。这样做的代价是界面要能坦然地显示“未知”,而不是一个绿色的对勾;换来的是每个结论都能追溯到它的来源。
面向 AI 编程 Agent 的设计
这一部分描述的是正在开发中的架构,不属于当前公开版本。
ExecRelay 的领域模型包含一套与厂商无关的 Agent 模型。AgentRun 表示 Agent 对某个任务的一次尝试,它引用这次尝试中发生的执行、验证和变更归因,而不是复制它们的状态;AgentEvent 是 Agent 时间线上的一个标准化步骤。
- Agent 运行的命令就是普通的
Execution,不会出现第二套“Agent 专用”的执行事实; - Agent 说“完成了”,只会被记录为一条消息事件,它不会结束运行、设置退出码,也不会让任何验证条件通过;
- 原始的适配器数据会和标准化后的事件一起保留。
Claude Code 和 Codex 的适配器存在于开发代码库中,标准化逻辑有基于样例数据的测试覆盖。对正在运行的 Agent 进程的原生监管仍在开发中,公开版本不包含 Agent 界面。这个边界是有意的:先发布执行、证据和验证这一层,Agent 再接入它。
实现概览
运行时边界
- then
Workbench
React / TypeScript,负责界面与领域状态。
- then
Tauri 边界
命令向下,事件向上。
- then
Rust 运行时
PTY 会话、进程生命周期、采集器。
操作系统
Shell、进程、代码仓库。
- 原生进程管理。 PTY 分配、退出状态和只读采集器运行在 Rust 运行时中,界面层只订阅它们报告的结果,从不持有长期运行的进程。
- 受限采集。 采集器的输出有上限、运行有时限,大型仓库也不会耗尽内存。
- 明确的来源。 结果、证据、结构化记录和 Agent 关联都各自记录来源。
- 故障隔离。 解析器或采集器出错时,执行记录和验证结论不受影响;采集失败被设计为不影响终端本身。
- 本地优先。 不需要账号;除非你运行的命令主动发送数据,执行记录、终端内容和证据都留在本机。
- 有测试覆盖的边界。 自动化测试覆盖执行证据、Shell 集成的信任边界、验证、结构化证据解析器、Git 采集器和变更归因。
当前状态与限制
- 开发者预览版。 v0.1.2 仍是 Developer Preview,仅支持 macOS(Apple Silicon)。
- 公开范围。 当前版本包含终端、Capture、Changes 和 Verify;更深入的 Agent 运行时集成仍在开发中,公开版本不包含 Agent 界面。
- 证据没有加密签名。 来源记录是建模上的约束,不是防篡改保证。
- 归因不等于因果证明。 变更归因只说明时间窗口内观察到的变化。
- 验证条件有限。 目前的验证条件是“命令加期望退出码”,任何不可信的结果都会被记为无法评估,而不是通过。