Flatcode(软件二向箔)¶
把任意一个仓库压成一棵可读的 .spec 树,一条本地命令,不需要服务器,也不需要账号。
成品是一个目录:里面是仓库的克隆(spec 树提交在 flatcode 分支上)和一份读数。加一条命令就能得到一个静态站,任何静态托管都能服务它。
已经压好的例子在 flatcode.spexcode.net。
它为什么是一条命令,而不是一次「活动」¶
「让 agent 通读一个陌生代码库、把意图写下来」这件事本来就在发生——只是今天它的停止条件是一个人觉得差不多了。那个条件在无人盯着的时候不成立。
所以 Flatcode 的循环停在一个量出来的信号上,这也是它敢无人值守跑的唯一理由。
闸门¶
一轮 = 一次非交互 agent turn + 一次读数。闸门是三个既有信号,agent 自己的报告不在其中:
spex spec lint错误必须为零。 integrity、one-govern、id-format、living、mention 都是关于这棵树的结构性事实;任何一条不过,说明树是错的,而不只是薄。- 覆盖率必须达到下限。 lint 本来就会报出每一个没有被任何节点认领的受管源文件。未覆盖数 ÷ 受管文件数,是「这个仓库到底有没有被写完」唯一诚实的度量。
spex doctor的 altitude / breadth 发现会成为下一轮的指令。 它点名那些在复述机制而不是陈述意图的节点。这是质量信号,因为一棵树完全可以在 lint 上全绿,同时读起来只是代码的改写。
没过闸的轮次不会重放同一个 prompt——发现本身就是下一轮的 prompt。轮数有上限;预算耗尽会报出一个 PARTIAL 结果并列出还差什么,退出码非零。它永远不会报告一个它没有测量过的成功。
受管集是确认出来的,不是断言出来的¶
外部仓库没有 spexcode.json。而 lint 在没有 governedRoots / sourceExtensions 的情况下会找到零个源文件——覆盖率于是空洞地满分,闸门会放行世界上任何一个空 .spec。
所以 Flatcode 会先从仓库实际跟踪的文件里推导出受管根和源扩展名。但读文件树只是提议:lint 会在上面再套一层产品自己的源策略(它的 test glob 会整体丢掉 tests/、test_*、*.test.*),所以一个根可能被提议、被写进配置、然后什么都不治理。
Flatcode 因此会拿提议去对照 lint 的实际账目做确认:它一个文件都没留下的根会被丢掉、配置被重写、读数在生效配置下重新取一次,最后报出的计数是 lint 的,不是文件遍历的。确认后为空则直接拒绝,而不是放行。
常用参数¶
| 参数 | 作用 |
|---|---|
--out <dir> |
产物目录,默认 <repo>.flat |
--launcher <name> |
用哪个 agent。必须是一个具备非交互 turn 的 harness;不具备的会被指名拒绝,而不是悄悄换一个 |
--rounds <n> |
轮数上限,默认 6 |
--coverage <pct> |
覆盖率下限,默认 90 |
--lang <code> |
spec 正文的语言,例如 --lang zh。它只影响散文:节点 id 是目录名、也是 URL 的一部分,始终保持小写 ASCII |
在线预览¶
写出 <flat-dir>/site:只读的图谱界面、每个节点一份文档、.spec 压缩包,以及一份逐文件带 SHA-256 的 release manifest。纯静态文件,没有后端,所以任何静态主机都能服务它;一个没收敛的 flat 也照样能预览——它的 About 面板带着覆盖率,所以一棵没写完的树不会被读成写完了。
这个目录是可重定位的:它引用的每一样东西都相对于它自己,所以同一份字节既能挂在域名根上,也能挂在任意路径前缀下。
发布出去的是仓库自己的 spec:spex init 播下的那些 SpexCode 工作流节点(.plugins)是转化过程需要的机器件,不是对目标仓库的解读,所以图谱、文档和压缩包都会排除它们。
多个仓库放在一起¶
把多个 flat 组装成一棵静态树:每个 flat 落在 <out>/<owner>/<repo>/,加一个索引页,再加一份 gallery.json——它点名每一个条目并记录各自 release manifest 的 SHA-256,所以主机上服务的东西随时可以和当初构建的东西对照。
条目的路径来自 flat 读过的源,而不是你的 --out 名字:两个人压同一个仓库必须落在同一个路径上。
它不是什么¶
Flatcode 不部署、不拥有域名、不给任何人做认证。它产出目录;托管是另一件事,有自己的信任边界。