QuGame(简称 “Qu”)是一款具备 Game Center 在线对战功能的 iOS 棋牌/拼图游戏。它的底子很厚:SwiftUI 撸的界面,核心引擎是一个本地 Swift Package(QuGameModel),还用了 Swift Macros。除了一个用来搞定 GameKit 匹配的“老古董” Objective-C 文件(MatchmakerDelegate.m),整个项目清一色全是 Swift。
这可不是什么从零开始的 Demo,而是一个开发已久的成熟项目。也就是说,我们这次是要在既有项目(Brownfield)中“硬拓” Spec-Kit,而不是在白纸上画画。
Spec-Kit 是 GitHub 出品的规范驱动开发(Spec-Driven Development, SDD)工具包。它把传统流程反过来了:不再是先写代码后补文档,而是先写出极其详尽的“规格说明书(Spec)”,然后让 AI 照着说明书去生成实现代码。
我想通过这篇文章,一步步记录下在真实项目里落地 Spec-Kit 到底是个什么体验。我原本抱有极高的期望……咱们往下看。
在折腾 Spec-Kit 之前,我们得先给 AI 助手的“大脑”升个级,让它能看懂复杂的 Swift 代码库。我们添加了一个 Model Context Protocol (MCP) 服务——简单说,就是一个 Swift 语义分析工具。它能解析 Swift 源码,吐出结构化的声明、导入和类型信息。
我让 Claude Code 帮我搞定了这套配置。这个 MCP 服务住在 /Users/work/Documents/swiftMCP,它利用 Swift 解析器提取 .swift 文件的语义信息(类型、成员、访问权限、协议遵从等),并通过 MCP 协议暴露给 AI 工具。
为了用起来爽,我让 Claude Code 建立了一个斜杠命令。这就是 AI 助手的魅力:你不需要手动改配置,直接吩咐它:“帮我连上线”。 现在,我只要在 Claude Code 里敲 /summarize-swift @QuGame/GamePlay/BagView.swift,它就能给我一份清爽的结构化报告——导入了啥、结构体长啥样、有哪些私有属性,全是基于 AST(抽象语法树)解析出来的,比纯文本盲猜准得多。
我们在 BagView.swift 上试了试,效果拔群。不过说实话……后面我发现 Spec-Kit 压根没怎么用到这个 MCP。所以,这步你要是想偷懒,跳过也行。
安装之前,我先去它的 GitHub 仓库调研了一下。
核心考点:
uv(快到飞起的 Python 包管理器)安装。只要你有 Python 3.11+ 和 uv,一行命令搞定:
uv tool install specify-cli --from git+https://github.com/github/spec-kit.git@v0.6.1
小贴士:如果装完提示找不到 specify 命令,记得把 ~/.local/bin 加到你的 PATH 环境里。
在项目根目录运行:
specify init . --ai claude
这是一个交互式命令。我建议你自己手跑,而不是让 AI 代劳,这样你能更清晰地掌控配置细节。
初始化后会生成:
.specify/:工具的“大脑”,放模板、脚本和记忆。.claude/skills/:给 Claude Code 注入的超能力(斜杠命令)。宪法(Constitution)是 SDD 流程的基石。所有的 Spec、计划和任务都要对着宪法“宣誓”。这步要是糊弄,整个框架就没牙了。
这玩意儿不是 README,也不是代码风格指南。它是一份有版本号的治理文档——是项目的原则底线。
我先让 Claude Code 去“巡视”了一圈代码库,做了两件事:
翻车现场:第一版草案回来时,AI 自信满满地把项目描述成了“Swift 和 ObjC 混合项目”,还说核心引擎是“遗留的 ObjC”。破案了: AI 偷懒读了过时的 CLAUDE.md 文档。实际上 ObjC 引擎早就被我重写成 Swift 了。
教训:AI 极度迷信你的旧文档。如果文档是馊的,宪法就是歪的。我赶紧下令:“重新查数!只看现在的代码,不要信旧文档,给我肉眼去 ls 和 grep!”
| I. Swift 6 & iOS 17+ 适配 | @Observable、async/await、DocC 注释、swift-format。 |
| II. 只准用 Swift Testing (不可动摇) | import Testing,用 @Test 和 #expect。严禁 XCTest! |
| III. DRY 与简洁 | |
| IV. 状态驱动架构 | @State、@Binding,不搞 MVVM,逻辑写在 Observable 类型里。 |
| V. 关注点分离 | #Preview,改项目文件要守规矩。 |
万事俱备,召唤:
/speckit-constitution
运行完后,记得重启 Claude Code 进程,不然它认不出新安装的技能。
/speckit-specify终于要动真格的了。
这个功能原本就有,但 Bug 满天飞,交互也得重做。在老功能上写 Spec 是个极好的测试:如果不从零开始,Spec-Kit 还灵吗?
我压根没提现有的烂代码,直接描述我想要的:
““用户每天第一次启动,弹个领奖台。前三名排排坐,还要显示用户的连胜纪录。背景静默刷新数据,如果排名变了,领奖台要自动刷新并带动画。升职了撒花(Confetti),降级了也要有醒目的提醒。领奖台要像奥运会那样:金银铜,底座高度要跟分数挂钩。展示 5-7 秒后自动消失。”
命令一敲,Git 钩子自动生效:
001-daily-ranking-podium。specs/001-daily-ranking-podium/。/speckit-clarify在动手之前,AI 会过来确认细节(最多问 5 个问题)。 它问了:
/speckit-plan这是 AI 第一次正儿八经读你的代码。它派出了“研究特工”去扫描我的排行榜系统、头像组件和庆祝动画。
旧项目改造的福音:AI 回复我:“太棒了,研究发现大部分组件(ConfettiView、RankService 等)都已经有了。我们只需要做针对性的增强,不用推倒重来。”
它生成了详细的 plan.md,甚至做了一份状态迁移图。最牛的是,它会拿着计划去对撞“宪法”:“报告,本方案符合 Swift 6 规范,且没有使用 XCTest,准予执行!”
/speckit-implement基础工作很扎实:建立了 RankSnapshot 模型,增强了现有的 View,修好了一些无关痛痒的并发错误。编译一次过,零报错。
领奖台的主视图 DailySpotlightView 居然重写了好几遍。病根:AI 习惯性把简单问题复杂化。Spec 说:显示昨天的排名 → 等待 → 显示今天的排名 → 做过渡动画。 这是个标准的数据状态切换问题。结果 AI 开始疯狂写各种通知监听器、计时器、复杂的 Guard 逻辑。结果: Previews 里的动画死活出不来。AI 的反应是:再加一层代码!
我不得不打断它: “大哥,视图是跟着数据走的。动画不出来是因为数据没变,别再堆垃圾代码了,直接用我们现有的 UserSettings 把昨天和今天的数据存进去不就结了吗?”
一旦我把 AI 从“过度设计”的泥潭里拽出来,代码瞬间清爽:
UserSettings 里。.onChange(of: currentSnapshot)。这次折腾让我玩得挺开心。
几点干货:
我不打算给整个 App 补 Spec,但以后任何新功能或者重大的 Bug 修复,我一定会用 Spec-Kit。这种“先想清楚、写清楚,再写代码”的感觉,确实让重构老项目少了很多焦虑。
最后的一句吐槽: 哪怕有了最顶级的 Spec,AI 还是会在一些基础的逻辑上翻车。不过没关系,比起它帮我省下的时间,这点学费我交得起!
