ironlaw

by porphyrioon

工具与能力github收录于 08-23

把真实工程会话中数万条血泪教训变成交付纪律,在编码助手之外强制执行;一套与宿主无关的层

Turn tens of thousands of hard-won lessons from real engineering sessions into delivery discipline, enforced outside the coding assistant. One host-agnostic layer for every…

安装

dsh plugin --profile web add github:porphyrioon/ironlaw

GitHub 源码安装:首次需按提示配置 allowBuilds 构建授权后重试

安装与环境配置指引、插件开发教程见 DSH 中文社区文档 ↗

安装即在你的机器上以你的权限运行第三方代码——它可读写文件、使用凭据、访问网络,DSH 的工具审批不会为插件代码加沙箱。「检测到 manifest」仅代表发现 dsh.bundle / dsh.plugin 清单,不构成兼容性或安全审查;安装前请审阅源码,不熟悉的插件先在不含密钥的环境试用。

README

目录

把上万条工程会话里的踩坑记录,变成编程助手外部的交付纪律。
面向多宿主编程助手的统一外挂;只盯三件事:少返工、不偏离、不接受奖励作弊式的假完成。

这是什么

IronLaw 不是新的编程助手,也不是把 OpenCode 重做一遍。它是一个挂在编程助手外面的效率工程组件:

DeepSeek Harness / OpenCode / Claude / Grok / Zcode / Codex / Qoder / 其它薄壳编程助手
          │
          └── IronLaw 外挂:任务约束、事实证据、完成闸门、有限纠偏

它的出发点来自上万条工程会话中反复出现的失败模式:模型并不一定没有能力,很多时候是缺少一套在长任务中持续约束它的外部机制。IronLaw 不试图把模型变成另一个模型,而是把任务过程变成可验证的工程流程。

用户仍然使用原来的 GUI、Provider、模型、工具和工作区。IronLaw 不要求用户切换工作台,也不要求用户理解 MCP;首发形态是统一 CLI 安装器、统一 sidecar 内核和按宿主加载的薄插件/Hook 适配器。

npx @ironlaw/cli install --host opencode

安装后,用户继续正常使用对应宿主。IronLaw 在后台记录事实、检查任务状态,并在必要时提醒、阻断或要求最小修复。这里描述的是可观测机制,不是对任何模型、宿主或任务结果的保证。

为什么开源的是 Plugin,而不是 Skill 或 MCP

理解 IronLaw 的接入形式,要先区分 Router、Skill、MCP 和 Plugin 的职责:

用户输入
   │
   ▼
Router:选择 Agent / Provider / Model / Skill
   │
   ▼
Agent + Skill:理解任务、规划步骤、提出工具调用
   │
   ▼
OpenCode Runtime:真正执行工具、写文件、跑命令、结束会话
   │
   └──── IronLaw Plugin:观察、约束、审计、纠偏
                         │
                         ▼
                    ironlawd sidecar

Skill:方法论载体,不是执行边界

Skill 适合固化“应该怎么做”的知识:检查清单、代码风格、某个框架的工作方法、某类任务的提示模板。Router 可以根据任务把 Skill 选择并加载给 Agent。

但 Skill 仍然属于模型上下文:

  • 模型可能没有选中它,或只部分遵循;
  • 上下文压缩后可能丢失或被后续内容覆盖;
  • 它不能确认命令是否真实执行;
  • 它不能读取独立的工作区指纹和产物哈希;
  • 它不能在工具执行前硬阻断危险动作;
  • 它不能给“完成”授予可信证据。

因此 IronLaw 的规则可以被 Skill 借鉴,但不能把 IronLaw 本身交付成 Skill。Skill 是建议层,IronLaw 要解决的是过程控制和交付判定。

MCP:模型可调用的能力,不是外部监督层

MCP 适合把搜索、数据库、外部 API 或人工查询能力提供给模型。模型需要看到工具 schema,并主动决定是否调用。

这不适合做 IronLaw 的主路径:

  • 工具描述和 schema 会增加上下文 Token;
  • 模型可以不调用治理工具;
  • 模型调用后的结果仍可能被包装成自报材料;
  • MCP 不天然拥有宿主的完整 session、tool、permission 和 compaction 生命周期;
  • 它不能可靠地阻止一个已经由宿主准备执行的工具调用。

所以 MCP 可以作为将来的人工查询接口,例如查看报告、批准待审动作,但不能承担 IronLaw 的完成闸门。

Plugin:唯一适合做宿主级治理的薄层

Plugin 运行在 OpenCode 的宿主生命周期内,能接触到 Router 之后实际发生的消息、工具、权限、文件和 session 事件。它可以:

  • 在工具执行前检查和阻断;
  • 在工具执行后记录真实返回;
  • 在消息请求或压缩时注入短任务锚点;
  • 在 session idle 后触发完成审计;
  • 把事实交给独立 sidecar,而不是让模型自己给自己评分。

因此三者的关系是:

Router 负责“把任务交给谁、用什么模型和 Skill”
Skill 负责“模型应该采用什么方法”
MCP 负责“模型可以主动调用哪些外部能力”
Plugin 负责“宿主实际发生了什么,哪些动作可以继续,是否真的完成”

IronLaw 不和 Router 抢路由,不和 Skill 抢方法论,也不和 MCP 抢工具生态。它补的是三者都不负责的交付控制面:减少返工、防止偏离、识别奖励作弊式假完成。这里描述的是插件的机制和观测边界,不是结果保证。

三个核心目标

1. 减少返工

让每一轮执行都对准最终交付,而不是先做一个“看起来能跑”的最小框架,再由用户补规格、补测试、补构建、补部署。IronLaw 用任务契约、需求-证据映射和交付链检查,把返工风险尽量前移暴露。

2. 防止偏离

让模型在上下文压缩、长时间执行和 handoff 之后仍然回到原始 spec,而不是把相邻问题当成新目标。IronLaw 保存原始要求、约束和允许范围,并在检测到漂移时用短锚点纠偏。

3. 识别奖励作弊式假完成

不接受“测试通过”“构建完成”“已经修好”这类自然语言作为交付事实。IronLaw 要求工具事件、退出码、文件变化、工作区指纹、真实构建和最终旅程形成独立证据;证据不足时,任务只能是未验证、待修复或失败,不能标成完成。

为什么这三件事会反复发生

验证通过,不等于可交付

一条测试命令退出码为 0,只能说明某个命令成功结束,不能证明:

  • 测试真的覆盖了原始需求;
  • 没有把真实路径替换成 mock;
  • 不是错误的测试子集或空测试;
  • 测试通过后源文件没有再次变化;
  • 构建产物真的存在并能启动;
  • 用户要求的安装、部署、重开或交付旅程已经完成。

这正是奖励作弊最容易发生的地方:模型优化了“让当前测验通过”,却没有完成用户真正要交付的东西。IronLaw 把“测试通过”与“交付完成”分开判定。

最小框架、最短路径,常常换来多轮返工

模型容易选择眼前最短的实现路径:先写一个最小框架、先让测试变绿、先生成一个中间产物。这个策略短期看起来高效,但可能遗漏约束、改变边界或绕开最终用户旅程,最后由用户补充说明、重新测试、重新打包。

IronLaw 不禁止合理的最小实现,而是要求实现路径持续映射到原始 spec 和最终验收项:没有减少交付缺口的动作,不能被当作有效进展。这样做的目的不是让模型多写代码,而是减少“做完一轮又推倒重来”的返工。

中长程任务容易在压缩后漂移

上下文压缩、长时间工具调用和多轮 handoff 之后,模型可能忘记原始目标,开始解决一个相邻但没有被要求的问题。模型的 todo、handoff 或“我记得用户想要……”不能替代原始任务。

IronLaw 保存原始任务契约,并在真正需要时注入一个很短的任务锚点,而不是每轮重复整份历史。任务锚点的作用是守住边界,不是把新的长提示词塞回模型。

模型可以声称做过,但没有做过

“测试已通过”“构建已完成”“文件已更新”都只是模型文本。若事件流里没有对应工具调用、退出码、文件变化或产物哈希,这些内容只能算待核验声明,不能成为完成证据。这是 IronLaw 对奖励作弊机制的直接防线:模型可以汇报,但不能自己颁发交付证书。

任务结束后还在无休止地继续

没有外部完成边界时,模型可能在汇报之后继续推理、反复修改或顺手扩展范围,消耗 Token 却没有增加交付价值。

IronLaw 把续写变成有条件、可计数、必须有进展的修复动作;没有新证据或没有减少硬缺口,就停止自动续写。

IronLaw 的功能,用通俗的话说

用户看到的功能 背后的机制 主要遏制/预防
记住任务真正要求了什么 Task Contract、原始输入哈希、任务锚点 spec 漂移、压缩后忘记目标、handoff 改写需求
知道模型到底做没做 Event Ledger、工具事件、退出码、文件和 Git 事实 自报完成、捏造测试、虚构命令
不把绿灯误认为交付 CompletionGate、需求-证据映射、交付链检查 测试通过但不可交付、构建缺产物、只做中间文件
危险动作先停下来 确定性 Policy Engine、工作区边界检查 越界删除、危险 Git 操作、未授权发布
发现正在跑偏或空转 Drift Score、进展检测、缺口变化比较 长程偏离、重复修改、无效循环
需要继续时只补最小缺口 有限 Repair Loop、修复指纹、预算上限 尿不尽、无限续写、无效重试
插件坏了也不拖垮宿主 sidecar watchdog、能力握手、降级策略 插件故障导致 OpenCode 无法使用

技术原理

1. 外部状态机,而不是隐藏的第二个 Leader

IronLaw 不让另一个大模型每轮点评 Worker。它把单 Agent 任务放进一个模型外部的有限状态机:

OBSERVING
    ↓ 识别到代码任务
ACTIVE
    ↓ 模型停止 / 声称完成
VERIFYING
    ├─ 全部硬验收有有效证据 → VERIFIED
    ├─ 缺口可修复             → REPAIR_REQUIRED
    ├─ 危险或越界动作         → BLOCKED
    └─ 预算耗尽 / 无进展       → FAILED_UNVERIFIED

模型不能直接把任务写成 VERIFIED,todo 不能直接把任务写成 VERIFIED,单个命令退出码为 0 也不能直接把任务写成 VERIFIED。只有 CompletionGate 能授予交付状态。

2. 证据账本与证据等级

每条证据记录来源、时间、工作区指纹、命令摘要和相关验收项。证据产生后,如果相关源文件再次变化,旧证据自动失效。

E0  模型自然语言声称完成
E1  todo / handoff / 自报文件列表
E2  OpenCode 工具调用及返回值
E3  sidecar 独立执行的文件、Git、命令和哈希检查
E4  sidecar 执行的真实测试、构建、启动、重开和产物检查

E0 和 E1 不能升级为 E3/E4。一个典型的“奖励作弊”路径是:修改测试让它通过、只运行错误子集、声称运行了命令、或只生成了配置文件。IronLaw 会把这些行为拆成事实检查,而不是接受模型的总结。

3. 需求-证据图,而不是单一测试开关

原始任务被拆成硬验收项、禁止事项、允许范围和期望证据。完成判定按交付链逐项检查:

需求映射
  → 实现变更
  → 有效测试
  → 真实构建/启动
  → 用户旅程
  → 持久化/重开
  → 最终产物

缺少其中任一硬环节,状态就是未完成或被阻塞,而不是“通过但有保留”。

4. 低成本 Re-anchor 与漂移检测

IronLaw 不在每一轮重复注入整份 spec,而是在任务建立、上下文压缩、证据过期或明显漂移时注入约 200–400 tokens 的任务胶囊:

[IronLaw task anchor]
Objective: 修复刷新后登录态丢失。
Open requirements: AC-2 过期 token 错误;AC-3 真实刷新旅程。
Constraints: 不换认证框架;不得声称未执行的测试已通过。
Current evidence: unit=pass;build=stale;journey=missing。
Completion rule: 全部硬验收有有效证据后才能报告完成。

漂移分数只负责触发提醒或阻断策略,不作为完成证据。检测信号包括:修改范围与未完成验收项无关、连续修改但没有新证据、压缩后目标消失、handoff 与原始 spec 冲突等。

5. 有限修复与成本控制

自动修复不是泛泛地让模型“继续努力”,而是只发送当前最小缺口:

  • 默认最多 1 轮;
  • 后续 Managed 模式最多 2 轮;
  • 每轮必须减少至少一个硬缺口;
  • 同一个决策指纹不得重复续写;
  • 用户停止、预算超限或没有进展时立即终止;
  • 修复消息带防递归标记,不重新创建任务。

因此 IronLaw 的目标不是让每个任务都多跑几轮,而是用很小的固定开销,减少整项任务失败后的人肉返工。

5.1 Sidecar/子进程生命周期护栏(不是多 Agent 席位)

这里的“子进程”只指插件 sidecar 或宿主明确启动的 OS 进程,不指另一个 Agent,也不代表 Leader/Worker 席位。插件本身不创建多 Agent、不分配席位、不派发角色。需要防的是同一会话/同一外部启动请求重复拉起进程、父进程退出后子进程继续运行,最终积累大量 Bun/OpenCode 进程。

因此统一内核必须把 sidecar/子进程生命周期当作 P0 问题处理:

  • 每次启动绑定 lease_id、父进程、session、启动时间和任务预算;
  • 同一 handoff_id 幂等,禁止重复启动;
  • 每个受 IronLaw 管理的子进程有 wall-clock TTL、空闲 TTL 和最大重试数;
  • 父进程退出、心跳丢失或任务进入失败态时回收子进程树;
  • 启动前检查同一项目/会话是否已有活动 lease;
  • status 显示活动 lease、孤儿 lease、累计 CPU 和内存;
  • doctor --workers 能列出并安全回收 IronLaw 自己启动的子进程;
  • 不得按全局 bun 名称粗暴杀进程,必须按 lease、命令摘要和父子关系精确识别。

本机曾出现 25 个持续运行的 opencode run --format json --pure 子进程,累计约 2GB 内存;这类事件优先于任何新的宿主适配器。没有生命周期护栏,插件运行时本身就会制造返工和成本问题。

6. Hook + sidecar,而不是默认 MCP

OpenCode 插件负责接收宿主事件、执行快速前置策略和注入短锚点;本地 sidecar 负责状态机、证据账本、工作区检查和完成审计。

OpenCode GUI / Provider / Agent
            │
      IronLaw Plugin
            │ stdio NDJSON
            ▼
       ironlawd sidecar

首发不把十几个治理工具注册给模型。这样可以避免固定的 MCP schema Token 税,也避免把“是否完成”的判断交给模型主动调用工具。MCP 将来可以作为人工查询或跨宿主兼容接口,但不是首发主路径。

7. 把“铁律”翻译成可执行算法

Hackathon 方案里讨论的铁律,不是再写一段更长的 system prompt,而是把几种方法论变成可执行的编排算法:

方法论 在外挂中的技术化表达 解决的问题
VDDG 熵减 意图编译、Task Contract、需求-证据映射 输入发散、目标模糊、最短路径误解需求
边界守恒 allowed scope、must/must-not、工具前置策略 任务边界被扩大、handoff 改写原始要求
循环控制 有限状态机、进展评分、修复预算、幂等指纹 长程空转、反复修改、无休止续写
证据守恒 Event Sourcing、证据等级、工作区哈希、stale invalidation 自报结果冒充事实、旧测试冒充新证据
受控熵增 受约束的方案探索和候选比较 只追求眼前最短路径、没有论证就进入执行

首发统一内核实现的是前四项的单 Agent 外挂闭环;受控熵增、模型认证和多 Agent 协作属于其它组件,不在本插件承诺范围内。

8. 不是所有模型都用同一种护栏

长期方向是从真实工程会话中提炼模型行为标签,例如:跳步倾向、工具调用准确率、边界意识、讨好型输出和长程稳定性。标签不是用来给模型打分炫技,而是让编排层选择不同的任务粒度、检查点和审查强度。

这一层称为 CertifyGate,目前只保留接口和研究结论,不作为当前插件的隐藏模型评测服务,也不会默认增加额外模型调用。

多宿主使用方式

首发按多宿主通配设计:统一内核通过宿主适配器接入。当前已实现 OpenCode(hooks + sidecar)与 DeepSeek Harness(原生 Cordis 插件:证据记录 + 破坏性阻断 + 完成闸门);Claude、Grok、Zcode、Codex、Qoder 等具备可验证 hooks 的宿主进入首发支持面,但每个宿主都必须单独通过能力探针和验收矩阵。没有 hooks 的宿主不进入首发接入承诺。

没有 hooks 的宿主怎么办?首发不把它们伪装成已接入。README 和 CLI 只提供一个可复制的 MCP 最小工具集 Prompt,由用户自行转发给该宿主的 Agent:

请在本次任务中使用 IronLaw MCP 的最小工具集:
1. il_status:开始前读取当前任务状态;
2. il_check:每次修改或危险命令前提交检查;
3. il_report:结束前提交实际执行的命令、退出码和未完成项。
不要把工具返回或自然语言声称当作交付证据;未执行的检查必须标记为未执行。

这只是用户自行转发的操作指引,不是宿主适配器、不是自动注入,也不是首发功能支持。只有能够提供可验证 hooks 的宿主,才进入 IronLaw 首发适配矩阵。

npx @ironlaw/cli install --host opencode
npx @ironlaw/cli install --host claude
# DeepSeek Harness 原生插件:
#   npm install --global @deepseek-ai/dsh
#   dsh plugin --profile web add @ironlaw/adapter-dsh
npx @ironlaw/cli doctor
npx @ironlaw/cli status
npx @ironlaw/cli report --last
npx @ironlaw/cli uninstall --host opencode

产品模式分为:

  • Observe:记录会话、任务和证据,不注入、不阻断、不续写;
  • Guarded:启用危险操作阻断、任务锚点、完成闸门和一次最小修复;
  • Managed:后续再考虑两轮修复和可选 verifier。

未知版本、能力探针失败或真实宿主验收未通过时,只能进入 Observe,不能把配置写入成功冒充成已启用编排。

它在效率工程中的位置

IronLaw 是效率工程的一块基础组件,关注“任务是否按要求一次性交付”,不是完整的编程助手产品。

围绕它还可以形成更大的工程效率组件体系:

创意
  → 论证
  → 规划
  → 执行
  → 审查
  → 交付

可能的其它组件包括:

  • 定制化编程工具:面向特定语言、框架、部署环境和企业规范;
  • UnionAgents:多 Agent 联动工作台,负责角色协作、任务分派和结果合并;
  • A2A 通信协议:让不同 Agent、工具和工作台交换任务、状态和证据;
  • 固化创意、论证、规划、执行、审查方法论的工作流组件;
  • 面向团队的报告、指标、回放和工程知识库。

可以把这套组件理解为一条完整的工作方法链:

创意 → 论证 → 规划 → 执行 → 审查 → 交付
  │       │       │       │       │
  └─ 受控熵增 ─────┴─ VDDG/边界守恒 ─┴─ IronLaw 完成闸门

这些是效率工程生态的其它方向,不属于当前插件的承诺范围。当前只开源 IronLaw Plugin、统一 CLI/协议原型及其必要的本地 sidecar;其它组件是否公开、何时公开,将根据 Hackathon 评委结论和后续产品边界再决定。

与 Hackathon 作品的关系

当前开源插件与 Hackathon 参赛作品是两个边界清晰的交付物:

  • IronLaw Plugin 是宿主外部的通用交付治理外挂;
  • 它不替代、不打包、不复制 Hackathon 参赛作品;
  • 它不依赖参赛作品的私有代码、数据或运行环境;
  • 它可以独立安装、独立卸载、独立验证;
  • 后续多 Agent 工作台、A2A 协议和方法论组件的安排,待赛事评委结论后再确定。

当前开源范围

本次公开一个 monorepo(npm workspaces),三个 npm 包:

ironlaw/
├── packages/cli/          # @ironlaw/cli:install / doctor / status / 通配 sidecar 内核
├── packages/memory/       # @ironlaw/memory:Git 版本化共享记忆 MCP
└── packages/adapter-dsh/  # @ironlaw/adapter-dsh:DeepSeek Harness 原生 Cordis 插件

目前 monorepo 全量测试 32 项通过(cli 6 + memory 13 + adapter-dsh 13)。这只是协议、本地 sidecar 与 DSH 插件原型证据,不代表所有宿主、所有版本、所有 Provider 或任何任务结果已经验收,也不构成对用户的交付保证。

如何判断项目是否成功

不以“模型输出更长”或“测试绿灯更多”为成功标准,而看:

指标 含义
一次交付率 第一次任务运行就通过全部真实验收的比例
虚假完成率 模型声称完成但硬验收失败的比例
spec 漂移率 最终实现违反或遗漏原始要求的比例
有效任务成本 Provider 总成本 / VERIFIED 任务数
额外 Token 比 IronLaw 相对 baseline 的 Token 增幅
修复轮收益 自动修复后减少的真实验收缺口
误阻断率 合法工具调用被 IronLaw 错误阻断的比例

如果外挂只能让汇报看起来更完整,却不能提高真实交付率、降低虚假完成率或减少返工,它就不应继续堆叠更多编排角色。

原始 README: https://github.com/Porphyrioon/ironlaw/blob/master/README.zh.md ↗