首先让我来讲讲它是怎么做的,以及我在几个关键位置上 做的取舍。
先说结论:Jin 的核心不是“让 AI 更聪明”,而是把提案权和决策权分开。
- Agent 可以创建提案、修改目标架构、执行校验;
- Agent 不能批准;
- 批准由服务器完成,带签名,并绑定到用户审阅时的目标哈希;
- 批准或拒绝之后,服务器给会话发一条合成消息,Agent 自动继续。
这四件事串起来,才是一个完整的闭环。少任何一环,流程都会退化成“聊天里说一声 可以”,然后靠用户自己记得催下一步。
一、架构模型:L0 和 L1
Jin 把架构保存成两层小型 YAML。
L0 回答“系统由哪些部分组成,它们允许怎样依赖”:
version: 1
project:
name: shop
languages: [typescript]
modules:
- id: mod-orders
name: orders
package: pkg-src
path: src/orders
public_entities: [fn-cancel-order]
L1 回答“每个模块对外暴露什么、位于哪里、依赖什么”:
version: 1
module: mod-orders
entities:
- id: fn-cancel-order
kind: function
name: cancelOrder
location:
file: src/orders.ts
symbol: cancelOrder
relations:
- type: uses
target: fn-order-total
这里有三个刻意的设计。
1. 不做“大一统架构图”
Jin 不试图把整个代码库的所有细节都建模。它只保留对决策最有用的部分:模块、 分层、公开实体、位置、字段、方法、关系。
原因很现实:图越大,维护成本越高;维护成本越高,越容易变成一次性海报。Jin 要的是每天都能更新、每次改动都能审阅的小模型。
2. 实体 ID 是稳定引用
fn-cancel-order 这种 ID 会同时出现在架构图、结构化差异、漂移检测和提案目标
里。名称可以改,位置可以移动,但 ID 不变,历史才能对齐。
3. 位置必须指向真实声明
location.file 和 location.symbol 不是装饰。校验会去真实代码里找它们。找不到
就是错误,不是警告。
这也是 Jin 和“让另一个模型给架构打分”最大的区别:它尽量用代码事实校验,而 不是用自然语言说服自然语言。
二、提案:一次结构改动就是一个版本化快照
目录结构大致是这样:
arch/
L0.yaml
L1/
<module>.yaml
proposals/
<REQ>/
meta.yaml
versions/
v1/
target-L0.yaml
target-L1/<module>.yaml
summary.yaml
decisions/
v1.yaml
history/
<REQ>.yaml
Agent 创建一个提案后,只能编辑当前版本的目标文件:
versions/vN/target-L0.yaml
versions/vN/target-L1/*.yaml
它不需要直接改 arch/L0.yaml 和 arch/L1/。批准之后,服务器才把目标写入正式
架构。
这样做有几个好处:
- 可回滚。 每个版本都是完整快照,不是一段无法还原的 diff。
- 可审阅。 用户看到的是目标架构与基线的结构化差异,而不是几百行 YAML。
- 可校验。 校验针对目标快照执行,失败不会污染正式架构。
- 可拒绝。 拒绝只保存决策和备注,不改
arch/。
提案状态大致会经历:
draft -> in_review -> applied
\-> rejected
jin_validate 是状态转换的关键点。校验不通过,Agent 继续修;校验通过,提案进入
in_review,同时发出审批事件,桌面端自动打开审阅面板。
三、校验:用代码事实约束架构声明
Jin 的校验器不是编译器,也不是完整的类型检查器。它做的是声明级检查:
- 声明的文件是否存在;
- 声明的符号是否存在;
- 模块的路径和公开实体是否对得上;
- 跨层依赖是否符合约束;
- 应用后真实代码里是否出现了未登记的公开符号;
planned实体是否已经提前存在。
扫描器目前支持:
| 语言 | 提取内容 |
|---|---|
| TypeScript / JavaScript | 导出声明的类、类型、函数、组件/页面/Store 实体、字段、方法和使用关系 |
| Python | 顶层类和函数、方法签名、字段、点号导入 |
| Java | 顶层类型 |
| Kotlin | 顶层类型和函数 |
这套扫描器是声明级的,故意保持近似。它不追求完整的 AST 语义,也不试图替代 TypeScript 编译器。原因是:
- 架构审阅需要稳定、可解释的结果,而不是“编译器说行就行”;
- 多语言支持要能渐进扩展,不能被某一种语言的类型系统绑死;
- 审批门关注结构,不关注每一行实现。
代价也很明确:它可能漏掉一些复杂语义,也可能对动态用法判断得比较保守。文档里 把这一点写得很清楚,避免用户误以为它是“架构正确性证明器”。
漂移检测也是同一套思路。应用之后,Jin 会把架构里声明的实体和真实代码声明做 对比:
- 缺少位置或符号:错误;
- 未登记的公开符号:警告;
- 模块外位置:警告;
planned实体已经存在:提示。
它不是要消灭所有警告,而是让“架构和代码不一致”这件事可见。
四、审批门:为什么不能只做一个前端按钮
这是整个项目里最容易被低估的部分。
如果审批只是桌面端的一个按钮,那么它仍然只是 UI 约定。Agent 可以绕过 UI 直接
改 arch/,脚本也可以伪造一个“已批准”的 YAML。对于一个要给 Agent 设定边界的
系统来说,这不够。
Jin 把决策权放在服务器:
- 服务器持有 HMAC 密钥;
- 桌面端只发送决策和用户审阅过的目标哈希;
- 服务器验证签名、目标哈希和基线架构,才允许应用;
- 手动修改
meta.yaml或decisions/*.yaml不会批准提案; - 审阅后目标被改了,哈希不匹配,批准失效;
- 提案创建后正式架构已经变了,基线不一致,默认也不能直接应用。
签名密钥按优先级解析:
JIN_APPROVAL_SECRET;JIN_APPROVAL_KEY_FILE;$XDG_DATA_HOME/opencode/jin/approval.key,否则~/.local/share/opencode/jin/approval.key。
自动生成的密钥文件权限是 0600。如果希望之前签名的决策长期可验证,就不要随便
换密钥。
这套设计的目标不是“防住所有攻击”。它解决的是一个更具体的问题:让 Agent 的 提案权和人类的决策权在系统层面分开,而不是靠提示词约束。
Agent 可以很聪明,也可以很主动,但它不能替用户按下那个批准按钮。
五、自动继续:审批完不能让流程断掉
很多审批工具死在一个细节上:批完之后,用户还得再发一句“继续”。
Jin 的处理方式是:决策写入后,服务器向会话发送一条合成继续消息。批准和拒绝都会 继续,区别在于 Agent 拿到什么上下文:
- 批准:目标已应用,Agent 接着做实现、测试或后续步骤;
- 拒绝:备注回到会话,Agent 基于反馈修订提案。
这听起来像一个小功能,但它直接决定了审批是“流程的一部分”,还是“流程里的一个 收费站”。
当然,自动继续也可能失败。比如会话已经关闭,或者服务器在审阅和决策之间重启。 这时决策已经持久化,面板会提示“决策已保存,但会话未能自动继续”,用户正常发一条 消息就能接着处理。这个失败路径也写进了文档,而不是假装永远不会发生。
六、界面:让结构差异可读
Jin 的审阅界面有两个模式。
审阅模式
- 项目状态、模块/实体/提案数量、校验摘要;
- 应用后漂移;
- 提案队列和版本切换;
- 模块、实体、变更文件的结构化差异;
- 琥珀色审批卡:批准并应用、拒绝、可选备注;
- 应用历史。
架构图模式
- 系统和分层构成外层结构;
- 模块响应式排布,实体卡内联显示字段和方法;
- 跨层模块依赖是蓝色虚线,跨层实体依赖是青色实线;
- 悬浮或选中节点时,只保留直接关系,其余淡出;
- 新增、删除、变更、移动节点分别用绿、红、琥珀、紫标注;
- 选中实体后,右侧栏显示完整检查器。
这些视觉设计不是为了好看,而是为了回答审阅时最常出现的三个问题:
- 这次改动到底动了哪些结构?
- 有没有新的跨层依赖?
- 这个实体的字段、方法和关系是什么?
如果一张图不能回答这三个问题,它就只是装饰。
七、我做的取舍
Jin 现在还有很多不完美的地方,其中一些是刻意取舍:
- 桌面端优先。 先把审批闭环跑通,再考虑独立应用和更多入口。
- 声明级扫描。 不追求完整语义,优先稳定、可解释、可扩展。
- 不做测试执行器。 审批门只管架构决策,测试和 CI 仍然必要。
- 不做模型内置。 模型由用户通过 OpenCode 提供,Jin 不绑定 Provider。
- 不追求“全自动”。 结构性改动就是要停下来让人看一眼,这是设计目标,不是 缺陷。
如果你问我,AI 编码接下来最值得补的是什么,我的答案不是“让模型再快一点”,而是 让它在关键决策上停下来,并且停下来的方式足够顺滑。
Jin 是我对这个答案的一次尝试。
项目与下载
Jin 是 OpenCode 的社区分支,不是 OpenCode 官方产品;模型由用户自行配置。
项目地址:
v2.0.32-jin.1 下载(macOS / Windows / Linux):
中文完整指南(架构模型、审批契约、安全、排错):
如果你对提案生命周期、签名审批或扫描器实现有更好的想法,欢迎直接开 issue 或 PR。这个项目还很早期,很多设计值得被挑战。