游乐游手机版
首页/AI教程/文章详情

Spec总在腐烂?OpenGeno开源库教你用树加Hook一招彻底解决

时间:2026-06-26 16:29
针对Spec驱动开发中文档易腐烂的问题,提出OpenGeno开源库,采用Geno-DrivenDevelopment反向思路。以代码为真理源,通过L1 L2 L3三层树结构按需加载,每个特性文档记录关联文件及已验证的Git提交哈希,并利用Stophook自动检测漂移,强制保持文档与代码一致,确保AI始终基于准确信息工作。

前言

近期,Spec-Driven Development(SDD)在开发社区引发了大量讨论。以 OpenSpec、Kiro 为代表的工具核心思路是:先编写一份详尽的规格说明(Spec),再由 AI 依据该规格实现代码。

但实际在多个项目中落地后,我发现每次都会卡在同一个环节:

这并非某个工具的 Bug,而是流程层面的根本问题——Spec 描述的是“打算做什么”,而 Code 描述的是“实际做了什么”。只要代码持续迭代,Spec 就会逐渐脱节。如果 AI 读取了一份过期的 Spec 来生成代码,其结果比不读 Spec 更危险,因为 AI 会基于错误的“事实”做出决策。

因此,我尝试了一个反向思路:Geno-Driven Development(GDD),开源仓库名为 OpenGeno。本文将拆解 GDD 的设计理念、与 SDD 的对比分析,以及落地后才真正领悟到的取舍权衡。

一、SDD 的失败模式:spec 鲜活期太短

抽象 SDD 的工作循环如下:

1. 人写 spec2. AI 读 spec → 写代码3. (代码合入)4. 下次任务 → AI 再读 spec → 写代码

在第 3 步与第 4 步之间,没有任何机制能保证 Spec 仍然与代码保持一致。维护 Spec 的责任被默认为“AI 应该顺手做”或“Reviewer 应该提醒”,这两个都是软约束,而软约束在时间面前不堪一击。

更糟糕的是,Spec 本身往往是一份大块文档:一份 200 行的 Spec 只改了 5 行,Diff 看起来很小,但语义上可能已经完全错误——而 AI 读取时根本察觉不到。

二、GDD 的赌注:把 code 当真理之源,让文档作为可验证的索引

GDD 的反向假设非常简单:

  • Code 是唯一会被强制一致的事实来源(CI 会跑、用户会使用);
  • 文档存在的意义不是“驱动开发”,而是为 AI 提供加载入口和语义注解;
  • 文档与代码的一致性不能依赖人的自觉,要靠机器自动化对账。

落实到实现层面,只需三件事:

1. 三层结构,按需懒加载

feat-tree/├── index.md# L1:项目根索引,列模块├── auth/│ ├── index.md# L2:模块索引,列 feature│ ├── sign-in.md# L3:单个 feature 的详情│ └── sign-out.md└── tasks/├── index.md└── list-view.md

当 AI 需要修改 sign-in 时,完全不必读取 tasks 模块下的 50 个 Feature。它会从 L1 索引发现目标在 auth/,然后进入 auth/index.md 找到 sign-in.md,最后仅读取那一篇文档。这样一来,无论项目包含 50 个 Feature 还是 5 个,单次任务所消耗的 Token 量几乎相同。

2. 每个 L3 都带一个“已对账”的 SHA

L3 的 frontmatter 结构如下:

---type: og-featurekind: uifeature: sign-inmodule: authschema: 1code:- lib/features/auth/sign_in_page.dart- lib/features/auth/sign_in_controller.dart- lib/api/auth_service.dartlast_synced_commit: a1b2c3dlast_reviewed: 2026-05-06---

两个关键字段:

  • code: 该 Feature 所依赖的代码文件列表;
  • last_synced_commit: 这份文档最近一次被人或 AI 真正对照代码核对通过的 Git SHA。

SHA 的语义不是“被编辑的时间”,而是“被验证的时间”。这一区分至关重要——仅仅是修改文档不算对账,必须读取代码、确认一致之后才能更新该值。

3. 漂移检测:把“忘记更新”变成机器能发现的事

有了 code:last_synced_commit:,漂移检测就化为了一个简单的脚本:

# 伪码for doc in feat-tree/**/*.md:last_sha = doc.frontmatter.last_synced_commitfor code_path in doc.frontmatter.code:if git_log(code_path, since=last_sha) is not empty:mark doc as DRIFT

该脚本被注册为 Claude Code 的 Stop Hook——每次会话结束时自动执行。支持两种模式:

  • warn(默认):打印漂移摘要,Session 正常结束;
  • block:退出码为 1,Session 不允许结束,直到漂移被处理。

软约束由此变为硬约束。AI 忘记更新文档不再是“下次再说”,而是“现在就解决”。

三、SDD vs GDD:一张对比表

维度SDD(OpenSpec / Kiro 等)GDD(OpenGeno)
起点Spec 先于 CodeCode 已存在,文档跟随
文档形态单份 Spec / 大块 MarkdownL1 / L2 / L3 三层树状结构
AI 加载方式一次性读取完整 Spec沿 L1→L2→L3 按需逐步加载
维护机制靠人或 AI 自觉同步last_synced_commit + Stop Hook 强制对账
适用阶段偏重新项目启动任意阶段(含遗留代码库)
失败模式Spec 腐烂,AI 读取错误漂移会被检测,最差仅是收到提醒并处理
接入复杂度编写 Spec 是前置任务一次初始化,之后规则通过 CLAUDE.md 自动传递

两者其实并非替代关系。SDD 解决的是“从零到一如何让 AI 写对代码”,而 GDD 解决的是“从一到无穷大如何让 AI 一直写对代码”。新项目可以先用 SDD 产出第一版,再切换到 GDD 进行长期维护。

四、整体流程图

整个系统分为三个阶段,分开来看会更清晰。

4.1 一次性初始化

┌─────────────────────────────────────────────────┐│User: /geno-init │└────────────────────┬────────────────────────────┘ │ ▼┌────────────────────────┐│ ① 选语言(中文 / 英文)│└────────────┬───────────┘ ▼ ┌──────────────────────────────┐ │ ② 选漂移模式(warn / block) │ └──────────────┬───────────────┘▼ ┌──────────────────────────────┐ │ ③ 选生成模式(stub / full)│ └──────────────┬───────────────┘▼┌────────────────────────┐│ ④ 扫描代码 → 提议模块│└────────────┬───────────┘ ▼ ┌──────────────────────────┐ │ ⑤ 写 L1 / L2 / L3 文档 │ │ 写 .feat-tree.json │ └────────────┬─────────────┘▼ ┌──────────────────────────────┐ │ ⑥ 把工作流契约注入 CLAUDE.md │ │(此后规则自动传递)│ └──────────────────────────────┘

4.2 日常改功能(不需要任何命令)

User: 改一下 sign-in 的逻辑 │ ▼[AI 读 CLAUDE.md] ── 已注入的规则告诉它怎么做 │ ▼[L1 index.md] ──► 看到 auth 模块 │ ▼[L2 auth/index.md] ──► 看到 sign-in feature │ ▼[L3 auth/sign-in.md] ──► 读详情 │ ▼[AI 改代码] │ ▼[AI 同步更新 L3 + bump last_synced_commit] │ ▼[Stop hook 自动跑 drift-check] │ ├─► 无漂移 ──► session 正常结束 └─► 有漂移 ──► warn 提醒 / block 拒绝结束

4.3 漂移发现后

Stop hook 报漂移 │ ▼User: /geno-sync │ ▼列出五类问题: ├─ 红:明确漂移(code 改了,doc 没跟) ├─ 黄:可疑(提交里有 "refactor" 字样等) ├─ 灰:从未对账过(stub / 待审 full 草稿) ├─ 坏链:code 路径已经不存在 └─ 陈旧 SHA:记录的 SHA 已不在 git 历史里 │ ▼用户选择从哪类开始 │ ▼逐篇:读 diff → 改文档 → bump SHA │ ▼最终报告:哪些已对齐、哪些跳过

整个系统只包含两个 Skill(/geno-init/geno-sync)以及两个 Hook(PostToolUse 提醒、Stop 检测漂移)。没有第三个。每多一个命令,用户就多一个需要记住的负担。

五、stub / full:两种初始化策略

/geno-init 在第 3 步会询问:生成模式选择 stub 还是 full

stub 模式(默认)

仅生成文档骨架,各部分内容全部填充为 TODO / 待补充。日常开发到哪个 Feature,再现场编写该 Feature 的具体内容。

---type: og-featurekind: uifeature: sign-inlast_synced_commit: ""last_reviewed: 2026-05-06---# Sign in## WireframeTODO## Entry pointsTODO## InteractionsTODO

适用场景:大型项目、希望增量推进、不想在初始化阶段消耗过多 Token。

full 模式

扫描深度更深,AI 会一次性将所有 L3 文档尽量写完整。但关键设计在于:last_synced_commit: 留空。

意思是:内容已经有了,但尚未经过任何验证。

last_synced_commit: ""# 哪怕全文都填了,SHA 也必须是空的

原因何在?因为 SHA 的语义是“已被验证过”,而 full 模式只是“已被生成过”。这两件事必须严格区分。/geno-sync 检测到 gen_mode: "full" 且 SHA 为空时,会将其识别为“待审稿”而非“待写”,并给出不同的处理建议。

仓库中 examples/todo-app-full/ 包含完整的 full 模式产物示例。注意其中 AI 所写的句式:

这种带有保留语气的表述(hedged tone)是刻意要求 AI 这样写的——无法确认的事项就不要假装确认。当 AI 不确定时,不是猜测一个看似合理的值,而是直接留出 待补充 让人工来填写。

六、.feat-tree.json:项目根的运行时配置

初始化完成后,会在项目根目录生成如下配置文件:

{"version": 1,"tree_path": "feat-tree","drift_mode": "warn","gen_mode": "stub"}

四个字段各有用途:

  • tree_path:特性树存放的目录(默认为 feat-tree/,可自定义);
  • drift_mode:漂移检测模式(warnblock),由 Stop Hook 读取;
  • gen_mode:生成模式(stubfull),由 /geno-sync 读取(决定空 SHA 对应的是“待写”还是“待审”);
  • version:Schema 版本号,用于未来的升级兼容。

七、规则是怎么传递给后续 session 的

这是 GDD 真正能够落地的关键所在——规则并非写在 README 里让用户记忆,而是在初始化时直接注入到项目的 CLAUDE.md 文件中。

/geno-init 的最后一步会将一段规则文本追加到 CLAUDE.md(若不存在则新建),并用 / 包裹。这段文本告知未来每一个 Session 的 AI:

  • 修改代码之前,必须沿着 L1→L2→L3 的顺序读取对应文档;
  • 修改完代码后,必须同步更新 L3 文档并更新 SHA;
  • 更新 SHA 的前提是确实读取并理解了代码——仅仅编辑文档不算。

Claude Code(以及其他读取 CLAUDE.md / AGENTS.md 的工具)每次启动时都会读取该文件。规则一次注入、永久生效,用户无需在每个 Session 中重复说明。

八、上手

快速安装

npx skills add web-abin/OpenGeno

手动安装

# 1. 把 skill 装到 Claude Codegit clone git@github.com:web-abin/OpenGeno.gitcp -r OpenGeno/skills/geno-init ~/.claude/skills/cp -r OpenGeno/skills/geno-sync ~/.claude/skills/# 2. 在你的项目下运行cd your-project/geno-init

/geno-init 会交互式询问三个问题(语言 / 漂移模式 / 生成模式),然后扫描代码、提议模块划分、确认后生成特性树。整个过程不会改动你的业务代码,仅会创建 feat-tree/ 目录、写入 .feat-tree.json 配置文件、以及追加 CLAUDE.md 规则。

完成初始化之后,日常使用就完全不需要再手动调用命令了——AI 会按照 CLAUDE.md 中的规则自动执行流程。

九、诚实地说,GDD 不是银弹

需要坦诚地指出几个明显的局限:

  1. 第一次接入时需要花费一些时间梳理模块边界。虽然 stub 模式能减轻负担,但模块划分仍然需要人为确定。
  2. AI 偶尔会忘记更新 SHA。Stop Hook 提供了兜底机制,但 Hook 报错时仍然依赖人工去修复。
  3. 多人协作时漂移会更频繁。这其实是好事——它能暴露出团队成员之间的同步问题——但在接入初期会带来一定阵痛。
  4. 目前仅在 Claude Code 上经过充分验证。虽然 AGENTS.md 已准备就绪,但尚未在 Cursor、Aider 等工具中进行打磨。
  5. 不能完全替代 Spec。在需求评审、架构设计等“打算做”的阶段,Spec 仍然更合适——GDD 只接管“已经做了什么”这一环节。

完整的设计动机与取舍权衡记录在仓库的 docs/motivation.md,多个具体决策(为什么只设计了两个 Skill、为什么使用 CLAUDE.md 进行注入、为什么采用三层结构)分别在 docs/decisions/ 中有详细说明。

结语

把“先写 Spec”换成“先看代码、再让文档跟着代码走”,是一个反直觉但越用越受益的小转向。这种感觉有点像从“写注释”切换到了“写测试”——前者依赖人的自觉,后者由机器兜底。

如果你也曾被 Spec 腐烂的问题所困扰,欢迎尝试 OpenGeno。

来源:https://juejin.cn/post/7636617093937332250
上一篇OpenCLI:把任意网站、Electron应用和本地工具变成统一CLI 下一篇宇树G1脚踩梅花桩如履平地被称少林寺训练
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多
Windows Docker Desktop RabbitMQ生产级部署完整指南
AI教程 · 2026-06-29

Windows Docker Desktop RabbitMQ生产级部署完整指南

前言 在 Windows 本地开发环境中,直接安装 RabbitMQ 确实颇为周折:需要单独配置 Erlang 运行环境、手动管理环境变量、服务启停全凭手工操作。更令人困扰的是,版本兼容冲突、端口占用、环境不一致等问题层出不穷。笔者见过不少开发者为搭建环境就得耗费整整半天时间。 相比之下,借助 Do

AI搜索重构制造业采购逻辑的阿里云企业级GEOCMS优化实践
AI教程 · 2026-06-29

AI搜索重构制造业采购逻辑的阿里云企业级GEOCMS优化实践

先分享一个切实感受。过去两年,我们与福建制造企业合作较为频繁,发现一个非常突出的现象:超过80%的企业官网,产品参数仍然存放在PDF或图片中。AI爬虫?根本无法抓取。这些企业技术实力不弱、资质证照齐全、应用案例也丰富,但在AI搜索这一全新战场上,它们几乎处于隐身状态。 一、一个正在发生的行业变化 A

阿里云Token Plan团队版功能价格与省钱购买指南
AI教程 · 2026-06-29

阿里云Token Plan团队版功能价格与省钱购买指南

阿里云百炼近期推出了名为“Token Plan 团队版”的全新服务,这一服务专为企业与开发者量身打造,定位为AI大模型订阅平台。通过引入Credits作为统一计量单位,将文本生成、图像生成等多模态AI能力纳入单一计费体系,同时无缝兼容主流AI编程工具及智能体(Agent)生态系统。其核心亮点包括:全

阿里云物联网.NET Core客户端位置信息上报
AI教程 · 2026-06-29

阿里云物联网.NET Core客户端位置信息上报

阿里云物联网平台的位置服务并非一个完全独立的功能模块。位置信息可包含二维坐标与三维坐标,而位置数据的来源本质上是借助设备属性进行上传。换言之,若要让设备上报位置,您需先将其视为一个普通属性进行处理。 1)添加二维位置数据 操作过程十分简洁。进入数据分析 → 空间数据可视化 → 二维数据,点击添加,将

年阿里云服务器选型配置与网站部署全攻略
AI教程 · 2026-06-29

年阿里云服务器选型配置与网站部署全攻略

2026年,阿里云服务器生态已高度成熟,形成了清晰的轻量应用服务器与ECS云服务器两大产品阵营。无论你是计划搭建个人博客、企业官网,还是运营电商平台、进行应用开发,基本都能找到理想的解决方案。本指南将从服务器选型、配置选择、部署流程到安全运维,系统梳理2026年最实用的操作要点,帮助你少走弯路,让网