
卸载了 95% 的 Skills 之后,我开始逐行拆 Waza
我刚卸掉了大部分 Skills,转头却把 Waza[1] 的仓库完整拉下来,开始逐行读。
这件事看起来很矛盾。
最近我一直在清理为旧模型编写的补偿规则。模型变强以后,这些规则不会自动失效,反而会被执行得更彻底。Ponytail 被我从 Claude Code、Codex 和 Grok 里全部卸掉,Superpowers 和 gstack 也不再作为默认工程套件。
既然规则越少越好,我为什么还要花时间研究 Waza?
因为我之前把两个问题混在了一起:大模型能不能写好一段代码,和一个软件项目能不能长期正确地运行,根本不是同一道题。
不严谨声明:这组文章首先是我的学习笔记,用来总结和回顾自己的实际使用。文中判断只代表个人观点,文章由我与 Agent 协作完成,事实部分尽量回到源码、Git 历史和公开资料核对。
强模型减少了实现摩擦,系统复杂度没有消失
写一个函数、补一组测试、重构一个组件,强模型已经做得很好。模型继续变强以后,这类局部实现还会越来越便宜。
软件开发的难处并不只在代码生成。需求是否正确,改动会影响哪些模块,失败后能不能回滚,测试究竟覆盖了什么,生成产物有没有同步,权限边界是否越过,版本、安装包、文档和线上状态是否一致,这些问题不会因为模型更聪明就自动消失。
模型写代码越快,系统里同时发生的改动反而越多。过去一个工程师一天改三个文件,现在 Agent 可以同时改三十个文件。局部实现成本降了,评审、验证、状态一致性和发布闭环承受的压力更大。
Waza 值得保留,并不是因为它能教强模型怎样写代码。它保存的是模型无法从当前函数里直接推断出来的工程判断。
Waza 很轻,但一点也不小
我之前把 Waza 归为控制面最轻的一套 Skills。完整拆开以后,这句话只对了一半。
截至我这次拆解,Waza 固定为 8 个 Skill:think、ui、check、hunt、write、learn、read 和 health。8 个入口一共 1776 行,check 单独就有 400 行。从 2026 年 3 月 12 日第一次提交到这次核对时,主分支已经积累了 435 次提交。
它并不靠内容少来保持轻量。轻的是运行时控制面。
Waza 没有默认的 SessionStart 或 SubagentStart hook,不会在每次会话开始时把整套方法注入主 Agent 和所有子 Agent。它没有自动串联的工作流,也没有常驻状态机。宿主先根据 8 个 Skill 的 description 判断当前任务属于哪一类,只加载命中的入口。一个 Skill 做完就停下来,下一步要不要进入 check、write 或 hunt,仍然由人决定。
方法体可以很厚,常驻控制面保持很薄。这比“把所有规则压到 150 行”更接近我想要的极简。
最值得学的是它把经验放到了哪一层
Waza 仓库里的 AGENTS.md[2] 有一张很简单的判断表。
需要理解上下文、做判断、适应变化或者继续追问的能力,放进 Skill。相同输入总会得到相同输出的检查,放进 Script 或 Rule。项目自己的构建命令、发布边界和架构事实,继续留在项目里,Waza 只在运行时读取。
这套分层解决了一个很容易被忽略的问题:工程经验不是都应该写成提示词。
比如“先找根因再修复”需要结合现场判断,它适合放在 hunt。检查 Markdown 里有没有错误破折号、中英文之间是否缺少空格,不需要模型每次重新理解,它被做成了标点脚本。版本号、插件镜像和安装信息需要保持一致,仓库直接从 VERSION 和 Skill frontmatter 生成,不靠维护者记得同步。只有明确列进 packaging.allowlist 的文件才能进入发布包,漏掉的文件默认不发。
模型负责语义、权衡和例外,脚本负责可以重复判定的事实,测试再证明脚本遇到坏输入时会真的失败。
Waza 没有试图用规则替模型思考。它把模型最不该凭感觉完成的部分,做成了可以变红的工程事实。
一个找不到测试就失败的脚本
check 里有个很小的 run-tests.sh">run-tests.sh[3]。它会从项目里寻找 Cargo、TypeScript、npm、Makefile 或 pytest 的验证入口。
很多自动检查脚本在找不到测试时,会打印一句“没有发现测试”,然后返回成功。这样 CI 是绿的,Agent 也很容易顺着绿色结果宣布任务完成。
Waza 的处理是直接返回非零状态。没有找到验证命令,不代表代码通过了验证,只代表证据不足。对应测试还会专门创建一个空项目,确认脚本必须失败。
这个实现没有复杂算法,却准确切开了模型判断和工程事实。模型可以分析为什么当前项目没有测试,也可以询问正确命令,但不能把“没有测”解释成“已经通过”。
大模型再强,也不能从语言能力里凭空获得外部世界的执行结果。测试会不会失败、文件是否存在、页面有没有保存成功、安装包里到底装了什么,仍然需要真实工具给出证据。
Waza 自己也经历过一次反过度设计
Waza 的 Git 历史比最终文档更值得读。
它最初只有一个 health,来源是作者在真实 Swift 项目里遇到的 Claude Code 配置问题。后来才逐步扩展到需求判断、界面、审查、调试、阅读、学习和写作。
扩张以后,作者很快遇到了上下文成本。write 曾经有 658 行,后来被拆成薄入口和中英文参考文件。另一次重构从多个 SKILL.md 入口删除了 564 行,把细节移到按需加载的 references,把确定性逻辑移到 scripts。
这两次删除没有减少能力,只改变了加载方式。
Waza 的当前规则甚至要求逐句做 no-op test:一句话如果没有改变强模型的默认行为,就不值得占用上下文。这里的减法不是少写几个字,而是判断这句话有没有行为增量。没有就整句删除,有真实失败需要防止,就保留成硬边界;能机械判断,就继续下沉成脚本。
这和我在媒体仓遇到的 640 行压成 150 行完全不同。那次删除只证明文件变短了,没有证明知识仍然完整。Waza 的做法是让入口变薄,同时把知识留在正确的位置。
为什么作者的工程经历很重要
Waza 的作者 Tw93[4] 长期维护的项目横跨 Shell、Go、Rust、Swift、TypeScript 和桌面产品。从 Mole、Pake、Kaku、MiaoYan 到 Kami,他面对的不只是代码是否能运行,还有安装、升级、迁移、用户数据、跨平台兼容、发布资产和长期维护。
这些经验会直接改变一个人看 Agent 的方式。
只看代码生成,很容易把 Skill 写成“怎样把代码写得更漂亮”。长期交付产品以后,更关心的是需求有没有跑偏,修改能否回退,验证是否可信,生成物是否漂移,最终用户拿到的东西和仓库里的声明是否一致。
作者在自己的 Claude Code 工程文章[5] 里把协作环境拆成上下文、动作、控制、隔离和验证几个表面。Waza 基本就是这些判断经过真实项目和几百次提交以后,沉淀出来的一套可调用版本。
我愿意继续研究这套系统,当然有个人偏好。我已经用了大约四个月,也认可 Tw93 对产品、工程和开源的很多判断。但这组文章不会把“作者厉害”当作结论,源码、历史和可以运行的验证才是论据。
值得学习,不等于全部照搬
Waza 仍然有明显边界。
435 次提交集中在四个月左右,说明它仍在快速变化。绝大多数提交来自同一位作者,体系因此很一致,也难免带有个人工作流偏好。8 个 Skill 虽然比几十个入口克制,1776 行方法体仍然可能和其他工程套件产生路由重叠。
我们这轮拆解也不是运行时 A/B。离线确定性门禁已经实际跑通,在线抓取、安装 E2E、pytest 和 shellcheck 没有形成完整运行证据。文章可以解释架构和实现,不能据此宣布 Waza 在所有项目里都能提高多少分。
我目前的选择仍然是把 Waza 留作默认工程方法,但每个设计都要继续接受同一套问题:它补上了模型拿不到的什么?它留下了什么可重复验证的证据?它的自动触发范围有多大?不用它以后,项目究竟会损失什么?
强模型已经不需要一本教它怎样当工程师的员工手册,但软件开发依然需要工程系统。
Waza 最值得学的不是哪一句提示词,而是它处理工程经验的方式:从真实失败里找到重复模式,把需要判断的部分写进 Skill,把确定性事实写成 Script,把项目约束留在项目里,再用测试、生成和打包门禁防止这套方法自己腐化。
后面的文章,我会继续拆它的路由设计、验证脚本和 Git 演化,一起来欣赏优秀作者的作品。
引用链接
[1] Waza: https://github.com/tw93/Waza[2] AGENTS.md: https://github.com/tw93/Waza/blob/main/AGENTS.md[3]run-tests.sh: https://github.com/tw93/Waza/blob/main/skills/check/scripts/run-tests.sh[4] Tw93: https://github.com/tw93[5] Claude Code 工程文章: https://tw93.fun/2026-03-12/claude.html
夜雨聆风