灵枢 v0.3:用户嫌弃的两样东西,我都删了
两条用户吐槽,逼出一次”做减法”的架构重构
上一篇《开源第一天被打脸 5 次》,是被 bug 追着打——一种被动的狼狈。
这一篇没有 bug。
只有两条用户吐槽。但就是这两条,让我做了件听起来很反直觉的事:v0.3 没有加任何大功能,反而删掉了三样东西——还把灵枢这套工具在你仓库里的”存在感”,尽量删干净了。
这篇文章想讲清楚一件事:
最好的工程化基础设施,是让你感觉不到它存在的。
两条吐槽
v0.2.6 在团队里推开用了一段时间,反馈陆陆续续回来。其中两条,出现的频率最高。
第一条,几乎每个人都提:
“你这
.lingshu/目录和package.json,凭什么出现在我的业务仓库里?这俩又不是我项目的东西。”
第二条,来自几个认真读了文档的人:
“
lingshu tool这个命令……我盯着帮助看了半天,不知道它有啥用。”
这两条乍看毫不相干:一个嫌目录脏,一个嫌命令费解。
但我盯着它们想了很久,发现它们指向同一个病根。
病根:我把整台引擎,塞进了每个仓库
灵枢的核心机制是”规则真源 → 多 AI 工具产物”的自动分发:你只在 reference/rules/ 写一份规则,工具帮你生成 CLAUDE.md、.cursor/rules/、AGENTS.md……
v0.2 时代,这台”分发引擎”长这样:
1 | 你的业务仓/ |
.lingshu/scripts/ 里那几个 .mjs,是引擎代码。package.json 几乎是个空壳,存在的唯一理由是让你能跑 npm run sync。
当初这么设计,理由很”贴心”:就算你没装全局 CLI,克隆下来 npm install && npm run sync 也能用。
听起来周到。但代价是——你的每一个业务仓库,都背着一套和业务毫无关系的工具引擎,外加一个空壳 package.json。
用户的直觉完全正确:这些东西不属于我的项目。
至于第二条吐槽里的 lingshu tool 命令,它当时长这样:
1 | lingshu tool baseline <工具> # 把工具产物设为"入库" |
baseline / personal 这对词,是我这个作者脑子里的行话。用户既不懂它俩什么意思,也不知道自己什么时候需要用。
教训:贴心的默认,如果让用户的仓库背上不属于他的东西,那它就不叫贴心,叫侵入。
解法:把引擎收回去,再删掉一份多余的真相
第一步很直接:把分发引擎从每个仓库里搬走,收回到全局 CLI 里。
引擎只有一份,住在你 npm i -g 装的那个 @ruobai/lingshu 里。业务仓只留下真正属于它的东西——reference/ 治理资产,加上生成出来的 AI 工具产物。
1 | 你的业务仓/ ← v0.3 |
但搬走引擎只是搬家。真正让我觉得这一版”想通了”的,是接下来这个洞察——
那份 .lingshu/config/adapters.mjs 配置,其实大部分根本不需要存在。
它当时记了三件事:有哪些工具、哪些工具产物要入库、哪些工具已经在用。
我盯着这三件事,逐个问”这个信息,系统里别处是不是已经有了?”
- 有哪些工具 → 这是通用的,所有项目都一样,应该内置在 CLI 里,而不是抄一份进每个仓库。
- 哪些产物要入库 → 等一下……这件事,
.gitignore不是早就说了吗?一个文件在不在.gitignore里,就是”它入不入库”的答案。 - 哪些工具已激活 →
.cursor/rules/这个目录存在,不就说明你在用 Cursor 吗?
于是结论浮出来了:
根本不需要配置文件。文件系统本身就是配置。
.gitignore= “这个工具产物入库还是忽略” 的唯一真相- 产物目录是否存在 = “这个工具是否已激活” 的唯一真相
配置文件的存在,本质上是在重复一份系统状态已经表达过的事实。删掉它,不丢任何信息。
这个洞察顺手解决了第二条吐槽。既然 .gitignore 就是”入库 vs 忽略”的真相,那 tool 命令要做的事,无非就是改 .gitignore。于是 baseline/personal 那对行话,换成了人话:
1 | lingshu tool track <工具> # 让它入库(从 .gitignore 移除) |
track(追踪)/ untrack(不追踪)——这是 git 用户每天都在用的词。不需要解释。
教训:减法的支点,是找到一个”系统状态已经表达了的事实”,然后停止重复表达它。
做减法是有代价的,我不打算假装没有
删掉 package.json,意味着”克隆下来 npm install 就能用”这条路,断了。
团队里每个人,得各自全局装一次 @ruobai/lingshu:
1 | npm install -g @ruobai/lingshu |
CI 里则用 npx -y @ruobai/lingshu 临时拉起。
这是个实打实的退步吗?我想了想,认为值得:
- 一个治理工具,和你项目的业务依赖,本就不该混在同一个
package.json里。 - 全局装一次,是一次性的摊销成本,远比”每个仓库都背一套引擎”干净。
但我不想把它包装成”全是好处的升级”。它就是有代价:你多了一步全局安装,换来仓库的干净。 这个取舍,我摆在明面上,由你判断值不值。
教训:做减法不是无痛的。诚实地标出代价,比假装”全是好处”更可信。
让工具去迁移它自己
问题来了:已经用 v0.2.x 建好的存量项目,里头那一堆 .lingshu/ 和 package.json 怎么办?总不能让人手动删。
所以 v0.3 加了唯一一个”新命令”——lingshu upgrade:
1 | lingshu upgrade # 一键迁移到零侵入结构 |
它会自动:删掉 .lingshu/、删掉空壳 package.json、把原来配置里的元信息迁进规则文件、改造 CI、重装 git 钩子、重新生成产物。
写完它,我做的第一件事,是用它给灵枢自己的模板仓做迁移。
工具吃自己的狗粮,迁移它自己。lingshu upgrade 一跑,模板仓的 .lingshu/ 和 package.json 干净消失,lingshu doctor 体检通过。这种”自己能迁移自己”的踏实感,比任何测试都让我安心。
但真正有意思的是另一件事。
我在同级目录扫到了 4 个更早期的项目——灵枢 1.0 时代留下的。它们比 v0.2 还老:规则直接散落在各个产物文件里,根本没有 reference/rules/ 这个真源。
对这种项目,lingshu upgrade 做了一个我很满意的决定:它没有强行迁移。
1 | ⚠ 检测到灵枢 1.0 结构(规则直接写在产物中,无 reference/rules/ 真源) |
它识别出”这玩意我没法在不丢信息的前提下自动迁”,于是退一步,把决定权交还给人,给出手动步骤——而不是硬来、然后把人家的规则搞乱。
教训:好的迁移工具,知道自己什么时候不该自动迁移。
为什么”删东西”比”加功能”难
加一个功能,你只要想到一个新需求就行。
删一个东西,你得先证明”没有它也照样转”,还得找到那个让一切自然简化的支点——否则你删掉的就是别人正在依赖的地基。
v0.3 的支点,就是那句想通了的话:
.gitignore已经说出了真相,我何必再维护一份配置去重复它。
找到这个支点之前,那份配置文件看起来理所当然、不可或缺。找到之后,它显得多余得刺眼。
整个 v0.3 没有炫目的新功能。它做的事,是让你用着灵枢,却越来越看不见灵枢——仓库里没有它的引擎、没有它的 package.json、没有它的行话。
最好的工程化基础设施,就该是这样:无感。
回头看这三篇:
- 第一篇,立纲领——讲清楚灵枢是什么。
- 第二篇,交答卷——开源第一天被真实 bug 教做人。
- 这一篇,学会了克制——听用户的话,把不该在的东西删掉。
一个开源项目,大概就是这样从”宣言”,慢慢走向”克制”的。
写在最后
灵枢架构(LingShu)是为 AI 原生开发设计的中枢-肢体解耦架构——逻辑收敛于中枢,执行弥散于全栈。v0.3 起,它在你的仓库里尽量隐身。
1 | npm install -g @ruobai/lingshu |
- npm 包:https://www.npmjs.com/package/@ruobai/lingshu (v0.3 已上线)
- 中枢模板:https://github.com/imrui/lingshu-template
- 脚手架 CLI:https://github.com/imrui/lingshu-cli
老用户升级:
1 | npm i -g @ruobai/lingshu@latest # 升到 v0.3 |
留个问题给你:
你的工具链里,有没有哪个文件——你其实一直觉得它”本不该出现在你的仓库里”?
欢迎在评论区告诉我。
▎ 第一篇立纲领,第二篇交工程答卷,这一篇学会了克制。
若白知行 · Rubai AI