用共享规格约束 AI,减少跨平台功能漂移
作者用 Claude 开发分属两个仓库的 Mac 与 Windows 应用,遇到文案不一致、修复不同步和功能遗漏。通过在仓库上层建立共享规格目录,两端在 1.1.0 版本实现了功能与措辞同步。
AI 深度解读
AI 能分别写好两个平台的代码,却不会自动记住另一个仓库里的决定。Memotori 的作者用 Claude 开发 Mac 和 Windows 版本,逐渐遇到按钮文案不同、修复遗漏、功能只做一边的问题。到了 1.1.0,两个版本才第一次做到功能与措辞同步。
关键变化是把两端共用的规格放进同一个工作目录。这套做法值得看,因为它处理的是 AI 编程里很容易被忽略的问题:代码各自能跑,产品却慢慢变成了两个样子。
两份代码为什么需要一份共同规格
Memotori 是一款在设备端运行的转写与摘要应用。Mac 版用 Swift,Windows 版用 C#,代码位于两个独立仓库,几乎都由 Claude 编写。
最初,作者分别进入仓库,让 AI 添加同一个功能。问题逐渐出现:相同操作用了不同按钮名称,一边修好的 bug 另一边还在,有些功能甚至忘了补齐。
在作者原来的工作方式里,AI 只能看到当前打开的仓库。另一端已经做过什么决定,需要作者每次重新说明。只要漏讲,两次实现就可能走向不同方向。
作者于是把 AI 的工作位置上移了一层,让它同时看到两份代码和共享规格。下面是原文的目录结构,它解决的是共同规则放在哪里、AI 从哪里开始工作的问题:
Memotori/
├── Memotori-mac/ ← Mac repository
├── Memotori-win/ ← Windows repository
├── spec/ ← specs shared by both versions
├── releases/ ← release notes shared by both
└── CLAUDE.md ← working rules for the AI
要留意 spec/ 与两个仓库处于同一层。作者保留了独立仓库,只把共同规格、发布说明和 AI 工作规则集中起来。
spec/ 内又分成四部分:
features/每个功能一份文件,描述当前已经生效的行为。changes/保存编号为0001、0002等的变更提案,记录原因与改动。differences.md记录刻意保留或尚未消除的平台差异。ideas.md收纳还没有成为正式规格的想法。
当前规格回答「现在怎么工作」,变更提案回答「当时为什么这样改」。
这个区分很实用。讨论记录需要保留,但理解当前功能不该先读完十份历史提案。提案在两端落地后,作者会重写 features/ 中的现行规格。
同步功能之前,先同步文案和例外
作者认为帮助最大的一步,是把界面文字也写进规格。
按钮名称、提示消息都放进 Wording 表,同时提供日语和英语版本,实现时直接使用。这样,AI 不必在两次编码时分别临场措辞,同一个操作也就不容易长出两个名字。
平台习惯仍然需要保留。例如 Mac 使用「this Mac」,Windows 使用「this PC」。作者采用 Windows 术语编写规格,再通过替换表处理 Mac 用词,原文给出的映射是 File Explorer → Finder。
这里统一的是术语对应关系,而不是要求所有平台显示完全一样的文字。
另一项关键约定,是承认有些改动只适用于一端。状态表按功能分别记录 Mac 与 Windows 的进度,状态包括 Not started / In progress / Done / Won't do。
Won't do 必须写原因。原文中的 bug 修复 spec 0016,Windows 被标记为不做,因为那里原本就没有相关检查。留下这个解释,半年后才不会把合理差异误认为遗漏。
作者还把一条规则写进 CLAUDE.md:修复某个平台的 bug 时,要检查另一端是否存在相同问题。规格因此不只是功能清单,也承接了跨平台排查的提醒。
从提案到发布,最容易漏的是最后一步
作者把新增功能流程写进 CLAUDE.md:先复制模板到 changes/,分配编号并登记状态,再分别实现两个版本。每个平台各开一个 PR,并引用对应规格,例如 spec 0008。如果只完成一端,必须在状态表和规格里说明。
提案需要写清背景、行为、日英界面文字、两端设置名称,以及不能对齐的差异。合并后,再更新状态并重写现行规格。
发布材料也有共同入口。releases/1.1.0.md 列出本次包含的规格,以及日语、英语的商店更新文案,两家商店使用相同文字。
但这套流程仍然发生了遗漏:1.1.0 的主要功能待办事项,对应 spec 0008,已经在两端发布,状态表却还停在 Not started。作者和 AI 都忘了合并后的更新步骤。后来,作者增加了一个检查时机:写发布说明时,交叉核对状态表。
共享文件能减少信息分散,却不能保证文件始终准确。
这次 1.1.0 共交付了 0004 至 0013 十份规格。待办提取是其中最直观的例子:在转写文本上点击 Extract To-dos,右侧会出现候选事项;「下周五之前」之类的表达会转成建议截止日期,但候选项需要用户确认才会加入列表。

确认后的事项汇总到跨会议列表,按截止日期排序。

其他改动包括摘要与待办统一放进右侧面板,面板头部提供复制、删除、停止操作;历史录音可以重命名,会议日期时间单独保存;录音界面可直接选择麦克风和语言,停止录音后再识别说话人;选中的麦克风找不到时,可以换一个继续开始录音。作者称,转写和摘要全部在设备端运行,音频与转写文本不会离开设备。
我的判断
这套方法最有价值的地方,是把容易被当成实现细节的内容提前变成共同约定:按钮叫什么、哪里允许不同、某端为什么不做。这些内容恰好也是分别让 AI 编码时,最容易靠默认理解补出来的部分。
它很适合两个平台保留独立技术栈、又希望产品行为接近的项目。相比分别维护两份需求文档,共享规格减少了重复同步;相比改成共享代码或跨平台框架,它处理的是需求与行为的一致性,无法直接解决重复实现的成本。
效果也有边界。作者确实交付了两端一致的 1.1.0,但没有提供改造前后的返工次数、开发耗时或缺陷对照数据。「总体更快」仍是作者的经验判断。文案写进规格,也不能据此认定两端交互已经经过完整验证。
原文还没说明共享目录如何管理版本、多人如何处理规格冲突,以及如何自动检查实现是否符合规格。对于多人团队,仅靠大家记得改 Markdown,可靠性仍然有限。spec 0008 的状态遗漏已经说明,流程必须有明确的核对时机。
能拿来做什么
- 如果你在维护两个客户端,或同一产品的两套独立前端,可以先为一个共同功能建立共享规格,写清行为、界面文字和允许存在的差异,再让 AI 分别实现。
- 在日常 AI 编程中,把已经确定的按钮、提示和设置名称直接交给模型使用。涉及多语言时,把各语言文案放在同一份规格里,减少分别生成造成的偏差。
- 修复一端问题时,顺手检查另一端是否受影响;确实不适用就记录原因,让「不做」成为有解释的决定。
- 发布前用本次规格列表核对两端代码、PR 和状态表,尤其检查已经合并却仍显示未开始的条目,再据此更新现行规格与发布说明。