@openspec-opc/opencode-plugin
v0.3.0
Published
OpenCode runtime guard plugin for OpenSpec OPC workflows
Maintainers
Readme
opencode-spec-opc
opencode-spec-opc 是 OpenSpec OPC 在 OpenCode 里的 runtime enforcement 插件。
它不负责初始化脚手架,也不负责帮你生成 planning 工件。它只负责一件事:
在执行期阻止 AI 绕过 OpenSpec OPC 流程,直接修改业务代码。
如果说 OpenSpec 负责 planning,OpenSpec OPC 负责 execution discipline,那么这个插件就是把 execution discipline 真正落到工具层的那一层。
它现在在整体结构里的位置
当前仓库已经拆成三层:
packages/opc-guard-core- 平台无关的 guard 核心
plugins/opencode-spec-opc- OpenCode 运行时接线
plugins/codex-spec-opc- Codex 运行时接线
也就是说,opencode-spec-opc 现在故意只保留 OpenCode 侧 glue code。
质量门、phase 规则、workflow 扫描、state 读写这些共享逻辑,已经不再堆在这个目录里。
它解决什么问题
只靠提示词和文档约束,AI 很容易在下面这些时候失控:
proposal.md、design.md、test-contract.md、tasks.md还没准备好,就直接开始改代码- 测试还没立住,就先把实现写进去了
- 会话压缩后,AI 忘了当前 work item,开始写错文件
- 文档上看起来走了流程,执行时却没有硬约束
- 已经进入实现阶段,但没有当前 session 的明确授权,AI 还是继续写业务代码
这个插件的目标就是把这些风险压下去。
它做什么
1. 识别当前 work item
插件会扫描:
openspec/changes/*/.openspec.yamlopenspec/bugs/*/.openspec.yaml
并据此识别当前活跃 work item。
它还会从这些操作里推断当前 session 正在处理哪个 work item:
bash中的openspec --change .../--bugfix ...- 读取或修改
openspec/changes/<name>/... - 读取或修改
openspec/bugs/<name>/...
2. 判定是否 apply-ready
当前实现不再只看“文件是否存在”,而是做一层最低质量门。
change 默认会检查:
proposal.md是否达到最小长度proposal.md是否包含至少 2 个关键 sectiondesign.md是否达到最小长度design.md是否包含Affected Modules、Constraints等设计信号test-contract.md是否达到最小长度test-contract.md是否包含Purpose、Derived From、Negative Obligations、Boundary Obligations、Verify Evidence等结构信号specs/下是否至少存在一个带 Requirement/Scenario 结构的 spectasks.md是否至少包含 2 个 checklist itemtasks.md是否仍有未完成任务tasks.md是否不是todo、fix这类占位任务
bugfix 默认会检查:
bug-report.md是否达到最小长度bug-report.md是否包含复现、现象、预期/实际、环境等结构信号fix.md是否达到最小长度fix.md是否包含根因、修复方案、验证等结构信号
只有通过这些最低质量门,才允许进入业务代码变更阶段。
3. 阻止绕过流程的写操作
如果 AI 试图直接使用这些工具改业务代码:
editwriteapply_patch- 明显带副作用的
bash
插件会在执行前检查:
- 当前 session 是否已经选中了 work item
- 该 work item 是否
apply-ready .openspec-opc/.openspec-opc-state.json是否由当前 session 的/opsx-apply刷新- 显式锁是否仍在 TTL 内
- 如果存在
tasks.md,其中是否仍有未完成任务 - 当前 phase 是否使用了对应的独立 session id
red是否只写测试,green是否只写实现,verify是否停止业务代码写入- 当前 phase 是否已经满足进入下一步所需的最小证据
任一条件不满足,就直接拦截。
4. 允许文档和规则层继续推进
以下路径默认不拦:
openspec/**.opencode/**AGENTS.mdCLAUDE.mdopencode.json
原因很简单,proposal、specs、test-contract、design、tasks、规则配置本来就应该继续写,不应该和业务代码混在一起管。
为什么这和普通 planning 工具不同
大多数 planning 工具做到这里就停了:
- 生成 proposal
- 生成 design
- 生成 tasks
- 给 AI 更多上下文
但它们通常不负责真正拦住 AI 写代码。
opencode-spec-opc 的价值不在于“再生成一份文档”,而在于:
把 spec-first 和 test-first 从文档约定变成 runtime enforcement。
这才是它存在的理由。
当前 enforcement 模型
Work item selection
session 必须先进入明确的 work item 上下文。
Apply-ready gate
没有达到最基本的 planning 条件,不能进入业务代码修改阶段。
这一步现在不只是“文件齐了”,而是“文档至少有最低有效内容”。
Explicit apply lock
即使已经 apply-ready,没有当前 session 的 /opsx-apply 显式锁,仍然不能直接改业务代码。
Phase isolation
当前 phase 约束:
red- 必须使用
redSessionId - 只允许测试相关文件写入
- 必须先写过至少一个测试文件,才能继续 doc-only 更新
- 必须使用
green- 必须使用
greenSessionId - 只允许实现代码写入,不允许继续改测试
- 必须先有 red 阶段的测试写入证据
- 第一次进入时必须先写过至少一个实现文件
- 必须使用
verify- 必须使用
verifySessionId - 不允许继续写业务代码,只负责验证和总结
- 必须先有 green 阶段的实现写入证据
- 必须先跑过至少一个验证命令,才能继续写总结类文档
- 必须使用
Phase evidence
插件会把阶段证据写回 .openspec-opc/.openspec-opc-state.json。
当前会记录:
redTouchedTestFiles- red 阶段真正写过的测试文件
greenTouchedImplFiles- green 阶段真正写过的实现文件
verifyCommands- verify 阶段跑过的验证命令
当前会识别的 verify 命令包括:
npm test/pnpm test/yarn test/bun testpytest/vitest/jestgo test/cargo testeslint/ruff check/tsc/biome checkmake test/make check/just test/just check
Session continuity
在会话压缩后保留当前选中的 work item,减少上下文折叠后“失忆绕流程”的情况。
已知边界
这个插件解决的是“执行期硬约束”,不是“模型永远不会胡来”。
它能做的是:
- 阻止未到阶段就落盘
- 阻止没有显式 apply 锁就直接写业务代码
- 阻止拿着过期锁继续写业务代码
- 在
tasks.md已经全部完成后,使旧锁自动失效 - 阻止会话失焦后直接改业务文件
- 保证流程最少要经过 OpenSpec 工件准备
- 保证
red -> green -> verify至少留下基础阶段证据 - 保证 verify 不是空转状态,而是真的跑过验证命令
它不能完全解决的是:
- 模型在回复文本里胡说
- 用户明确要求跳过流程时的组织策略
- 对所有
bash写操作做 100% 精准静态判定
当前版本对 bash 采用的是保守启发式拦截,不是 shell parser。
运行时实现
当前 OpenCode 插件运行时代码主要在:
src/index.tsdist/index.js
共享 guard 逻辑来自:
../../packages/opc-guard-core/dist/guard-engine.js../../packages/opc-guard-core/dist/state-io.js../../packages/opc-guard-core/dist/tooling.js../../packages/opc-guard-core/dist/workflow-state.js
这一步的目的是让 OpenCode 适配层保持薄,不再承担多运行时共享核心。
依据的 OpenCode 插件机制
根据 OpenCode 官方文档,插件通过 JavaScript/TypeScript 模块导出函数工作,主要使用这些点:
- npm 插件入口:
.opencode/opencode.json里的plugin数组 - 运行时 hook:
tool.execute.before - 运行时 hook:
tool.execute.after - 压缩期 hook:
experimental.session.compacting
参考:
- https://opencode.ai/docs/plugins/
- https://opencode.ai/docs/tools/
安装方式
这个目录里放的是一个可复用插件包。当前推荐的消费边界就是包本身,而不是目标项目里的桥接 loader 文件。
如果后面你把这个包发布到 npm,那么在 opencode.json 里加:
{
"$schema": "https://opencode.ai/config.json",
"plugin": ["@openspec-opc/opencode-plugin"]
}这里的字段合法性以官方 schema https://opencode.ai/config.json 为准。
如果是 workspace 或本地源码消费,也应该直接引用:
plugins/opencode-spec-opc/dist/index.js可调项
如果你想自定义行为,可以改成工厂函数形式:
import { createOpenSpecOPCPlugin } from "/absolute/path/to/index.js"
export const OpenSpecOPCPlugin = createOpenSpecOPCPlugin({
failClosed: true,
allowDocWrites: true,
allowConfigWrites: true
})当前支持的选项:
failClosedtrue:没有apply-ready工作项时直接拦截业务代码写入false:没有工作项时先放行,只对已识别会话做约束
allowDocWrites- 是否允许继续写
openspec/与规则文档
- 是否允许继续写
allowConfigWrites- 预留位,当前实现保守保留
applyLockTtlMs- 显式 apply 锁的有效期,默认
1800000毫秒,也就是 30 分钟
- 显式 apply 锁的有效期,默认
