GitHub Issues 驱动的 Spec 化迭代开发实战:从一句产品想法到可交付的 macOS 应用(easy-vibe Spec Coding 落地课)
【免费下载链接】easy-vibe💻 vibe coding 101|The first course for AI-native product builders.项目地址: https://gitcode.com/GitHub_Trending/ea/easy-vibe
本篇技术指南以 easy-vibe 课程 Stage 3「核心技能」章节中的完整实战案例为骨架,演示如何用一组可复用的 AI Skills(grill-with-docs → to-spec → to-tickets → implement → code-review)把一句模糊的产品想法,逐步转化为由 GitHub Issues 驱动的可编译、可测试、可交付的 macOS 原生应用。读完本文,你将掌握 Spec 驱动的迭代开发全流程:如何用 Skill 澄清需求、把共识固化为 Spec、拆解为带优先级与依赖的 Issue、按 TDD 逐 Issue 实现并进行双重代码审查,以及如何判断何时可以放心让 AI 连续执行任务。
前置关联:本文是 Spec Coding 章节 的实践延续——该章节解释了为什么在 AI 开发中「Spec(规格说明)才是真正的代码」,而本文用一个真实公开仓库展示 Spec 如何落地为 Issues、commits、tests 和可运行的产品。Skill 的底层机制(
SKILL.md结构与触发方式)可进一步参考 Claude Code Skills 完整指南。
1. 理解 Spec 驱动的迭代开发
日常使用 AI 编程时,最常见的循环是这样的:
描述一个想法 → AI 写代码 → 发现问题 → 追加指令 → 继续修改这个循环对一两个小页面或许够用。但当项目规模变大,问题会接连出现:早期需求在长对话中被「挤」出上下文窗口、进度难以追踪、某个功能虽然能运行却早已偏离最初意图。
Matt Pocock 的 Skills 方案给 AI 提供了一个可复现的过程。Skill 定义的不只是「写什么代码」,而是「需要澄清什么、产出什么制品、何时等待人类确认」。把这两条路线并排对比,差异一目了然:
| 维度 | 纯聊天式实现 | Spec 驱动的实现 |
|---|---|---|
| 权威来源 | 当前聊天上下文 | 一份纳入版本管理的 Spec |
| 需求变更方式 | 边做边加需求 | 先更新 Spec 和任务,再改代码 |
| 进度载体 | AI 的对话摘要 | Issues 与 commits |
| 完成判据 | 「跑通了」就算完 | 逐条核对验收标准 |
1.1 GitHub 在流程中的三个角色
在整个流程里,GitHub 承担了三个相互独立又互补的角色:
- 项目归档库:保存 Spec、领域词汇表和架构决策(ADR);
- 任务看板:管理 Issues 的优先级与依赖关系;
- 完成证明:通过 commits、测试与关闭的 Issues 留下可审计的交付证据。
| GitHub 制品 | 含义 | 案例 |
|---|---|---|
| Spec | 最终软件应当做什么 | specs/relationship-compass-mvp.md |
| Issue | 一个可独立交付的任务 | #2 Browse sample Contacts |
| 依赖 | 必须先行完成的前置任务 | #3被#2阻塞 |
| Commit | 一个步骤内的变更 | feat: browse sample contacts |
| Tests | 行为保持正确的证据 | swift test |
| ADR | 重要技术选型的理由 | docs/adr/0002-native-swiftui-macos.md |
整个过程可以画成一条从「确认决策」到「关闭父 Issue」的链路:
1.2 五个 Skill 组成的主流程
grill-with-docs → to-spec → to-tickets → implement → code-reviewgrill-with-docs:澄清项目边界与技术限制(「grill」意为追问、盘问,配合文档资料向 AI 求证);to-spec:把已达成的共识转化为一份正式规格说明;to-tickets:依据 Spec 创建带优先级和依赖关系的 GitHub Issues;implement:一次只处理一个未被阻塞的 Issue,TDD 实现;code-review:把「代码健康度」和「需求覆盖度」分开审查。
2. 环境准备
本案例需要以下前置条件:
- 一个 GitHub 账号;
- 已认证的 GitHub CLI(
gh); - Node.js 18 或更高版本;
- 一个能够读取项目内 Skills 的 AI 编程工具;
- 运行 macOS 应用还需要一台装有 Xcode 的 Mac。
安装 Matt Pocock 的 Skills 包、确认认证状态并创建仓库:
npx skills@latest add mattpocock/skills -y gh auth status gh repo create relationship-compass-macos \ --public \ --source . \ --remote origin \ --push示例仓库公开是因为其中只有虚构的联系人数据。如果要处理真实数据,务必改用--private,并在推送前仔细检查示例、日志和 Git 历史。整个流程依赖三个关键标签(labels):ready-for-agent(AI 可认领)、priority:P0/P1/P2(优先级)、completed-by-agent(AI 已完成)。这类标签机制与本仓库 AI 工作流章节 中「为 AI 建立明确的交接与验收约定」的思路一致——标签就是 Agent 与人类之间的状态协议。
3. 定义 MVP 的产品范围与边界
任何成功的 Spec 驱动开发,第一步都是把「做什么」和「不做什么」同时讲清楚。本案例第一版的明确功能清单如下:
- 六个确定性(deterministic)的虚构联系人样例;
- 按姓名、组织、角色、邮箱和圈子搜索;
- 按关系强度和圈子组合筛选;
- 编辑档案、备注与跟进节奏;
- 导入经校验的 UTF-8 CSV 并安全去重;
- 交互历史记录与下次跟进日期计算;
- 本地 JSON 持久化,启动时自动恢复。
明确排除在 MVP 之外的包括:云端同步、AI 关系评分、账号体系、后端服务,以及对 macOS 系统通讯录(Contacts)的访问。排除项的价值在于:它划定了 AI 不会被诱导越界实现的范围,也防止对话中途范围蔓延——这正是 Spec Coding 章节强调的「先定边界,再让 Agent 执行」原则。
4. 第一步:用grill-with-docs澄清边界
整个流程的起点是一句极其模糊的话:
我想创建一个 macOS CRM,用来管理导入的联系人、更好地组织我的人际关系。我们可以先用假数据开始。
把这句话直接交给grill-with-docs:
🙋 你(/grill-with-docs) 我想创建一个 macOS CRM,用来管理导入的联系人、组织我的人际关系。我们可以先用假数据开始。 ✨ Agent 在写任何代码之前,我们先用几个问题确认第一版包含什么、排除什么、数据存在哪里、 采用什么技术、如何判定完成。对每个选择我都会说明差异并给出建议。追问之后得到一组明确结论:采用SwiftUI 原生(macOS 14+)、本地 JSON 存储、UTF-8 CSV 导入、六个样例数据、无网络请求、不申请系统通讯录权限。
这些结论不是停留在聊天里,而是被固化进仓库:
CONTEXT.md:固定Contact、Interaction、Follow-up三个核心术语的定义(统一词汇表,避免 AI 与人对概念理解不一致);docs/adr/*:用两条 ADR(Architecture Decision Records)分别记录「本地优先(local-first)」和「选择 SwiftUI」两项技术决策及其理由。
GitHub 在这一步的角色:已确认的上下文被提交到
CONTEXT.md和docs/adr/*,但实现类 Issues 尚未创建——边界未定之前不拆任务。
ADR 的写法可参考 AI 工作流章节 中维护docs/decisions/目录的做法:每条 ADR 至少包含状态(Status)、背景(Context)、决策(Decision)、理由(Justification)与后果(Consequences)五部分,让「为什么这么选」可以长期追溯。
5. 第二步:用to-spec把共识写成正式规格
边界确认后,调用to-spec把讨论结果沉淀为一份版本化的规格说明:
🙋 你(/to-spec) 把我们确认过的讨论整理成一份完整的 Spec,保存到仓库里, 并作为父 Issue 发布,打上 ready-for-agent 标签。产出的specs/relationship-compass-mvp.md包含:问题定义、MVP 范围、24 条用户故事、技术决策、验证策略和明确的排除项。同时创建的Issue #1成为整个项目的可见入口。
这里有一条值得记住的写作准则:好的 Spec 描述「行为」而非「文件名」。例如「没有交互记录的联系人也要出现在 Follow-ups 列表里」这样的表述,即使在内部重构后依然成立;而「读取 contacts.json 文件」则会在任何一次重构后立即失效。Spec Coding 章节中「三层规格结构」(功能层「做什么」、语言无关的架构层、语言相关的实现层)正是为了让这样的行为描述拥有稳定的分层载体。
6. 第三步:用to-tickets拆解成有序的 Issues
to-tickets的职责是把一份 Spec 切成可以逐步交付的 GitHub Issues:
🙋 你(/to-tickets) 把 Spec 拆成 GitHub Issues。每个 ticket 要交付一条可演示的垂直切片, 并写清楚优先级、完成标准和前置条件。发布前先给我看列表和依赖关系。得到的结果是五条实现类 Issue,挂在一张父 Issue(#1)之下:
| Issue | 优先级 | 可见结果 | 被谁阻塞 |
|---|---|---|---|
| #2 Browse sample Contacts | P0 | 启动、样例数据、搜索、详情 | 无 |
| #3 Import and persist | P0 | 去重后的 CSV 与 JSON 持久化 | #2 |
| #4 Organize Profiles | P1 | 档案、关系强度、圈子 | #2 |
| #5 Interactions and Follow-ups | P1 | 交互历史与跟进 | #4 |
| #6 Polish and verify | P2 | 错误处理、文档、打包、验证 | #3, #5 |
这里最关键的工程原则是垂直切片(vertical slice):绝不按「先把所有模型做完、再做所有 Store、再写所有界面、最后补测试」的水平分层方式拆解。每条垂直切片只串联刚好够用的数据层、界面和测试,让每一次交付都产生一个「新的、可演示的结果」。依赖关系也因此清晰可推理:#3 需要 #2 的浏览界面作为底座,#5 建立在 #4 的档案之上,而 #6 汇总所有前期成果做收尾验证。
7. 第四步:用implement一次只实现一个 Issue
进入实现阶段,指令是:
🙋 你(/implement) 按优先级和依赖关系实现所有 ready-for-agent 的 Issues。 一次只处理一个未被阻塞的 ticket:先写一个会失败的行为测试, 跑通 build 和测试,然后每个 ticket 单独提交一个 commit。7.1 TDD:先让测试失败
以 CSV 导入这条 ticket(#3)为例,实现之前先写一个行为测试:同一份文件导入两次,不得产生重复联系人。待实现通过后,再补一条测试保证非法表头不会破坏已有数据。
swift test --filter RelationshipStoreTests swift build swift test最终的公开行为测试共13 条全部通过。项目最终通过的行为测试覆盖了 CSV 导入、去重、搜索筛选、跟进日期计算等关键行为——这正是 Spec 中「验证策略」一节的落地点:每条 Spec 行为都有一条对应的、可重复执行的测试作为证据。
7.2 一个 ticket 一个 commit
每个 ticket 完成后,Agent 依次执行:发布 commit 与测试结果 → 移除ready-for-agent标签 → 打上completed-by-agent→ 关闭该 Issue。最终仓库里留下的是按依赖顺序排列的9 个小型 commit,例如feat: browse sample contacts,每个 commit 对应一条可审计的 Issue。
8. 第五步:用code-review做双重审查
实现全部完成不等于结束,code-review把审查拆成两个独立视角:
- 第一轮:代码健康度——检查命名、重复代码、过大的视图、模块耦合,以及是否遵守仓库根目录
AGENTS.md中定义的规则; - 第二轮:需求覆盖度——重读 Spec 和每一条 Issue,逐条核对期望行为是否真的实现。
这次真实审查中,确实发现并修复了如下问题:
- 重复的 CSV 表头未被拦截;
- 没有邮箱的联系人在去重时可能丢失;
- Follow-ups 筛选条件不完整;
- 启动时的数据恢复缺失;
- 下次跟进日期的显示逻辑有误。
修复流程严格遵循「先补测试、再修代码、然后重跑两轮审查」,而不是改完就完事。
这里有一个重要的认知提醒:测试全绿只能证明「写进测试的那些行为」是对的,并不能自动证明「每一条原始需求都被覆盖了」。绿色测试与需求覆盖是两回事,这正是第二轮审查存在的意义。
9. 最终交付成果
整个流程结束时,仓库呈现如下状态:
| 交付物 | 结果 |
|---|---|
| GitHub 管理 | 1 条父 Issue + 5 条实现 Issue,全部关闭 |
| 提交历史 | 9 个按依赖顺序排列的小型 commits |
| 验证 | 13/13 测试通过,build 完整成功 |
| 最终审查 | 代码健康度与 Spec 覆盖度双双通过 |
| 可运行产品 | 可生成Relationship Compass.app |
| 隐私 | 数据全部本地存储,无通讯录访问、无上传 |
9.1 搜索与组合筛选
在搜索框输入Founder,列表只剩 Maya Chen;关系强度与圈子可以组合筛选,验证了 Issue #2 的搜索/筛选行为。
9.2 编辑关系档案
组织、角色、邮箱、关系强度、圈子、跟进节奏与备注全部可编辑(Issue #4 的交付)。
9.3 记录交互并自动计算下次跟进日期
在 2026 年 8 月 9 日记录一次交互、跟进节奏设为 30 天,应用自动计算出下一次跟进日期为2026 年 9 月 8 日(Issue #5 的核心行为),同时交互历史中新增一条记录。
本地构建并运行这款应用(示例仓库为公开仓库,包含 Spec、Issues、提交历史、代码与测试):
git clone <relationship-compass-macos 公开示例仓库地址> cd relationship-compass-macos swift build swift test ./scripts/package-app.sh open "dist/Relationship Compass.app"10. 可直接复制的工作流
把下面的五段指令保存为你的「项目启动模板」,在任何新项目里直接复用:
/grill-with-docs Clarifie avec moi le périmètre, les exclusions, les données, la technologie et la vérification. N'écris pas de code avant ma confirmation explicite./to-spec Transforme l'accord en Spec avec comportements, critères d'acceptation et exclusions, puis crée une Issue GitHub parente./to-tickets Découpe la Spec en Issues verticales avec priorité, critères de fin et dépendances./implement Implémente chaque Issue non bloquée par priorité avec TDD, validation et commit séparé./code-review Revois la santé du code et la couverture de la Spec, corrige tout et relance les tests.11. 何时适合让 AI 连续执行任务
这套流程并非万能,它的适用边界很明确:
适合:范围清晰的 MVP、网站、应用和带有可观察行为、有可靠测试或构建命令的后端项目。
不适合:每小时都在变的需求、结果无法验证的任务、需要直接修改生产数据的操作。
无论 AI 多强,人始终保留以下确认权:项目范围、需求覆盖度与 Issue 顺序;涉及支付、部署、删除、权限和隐私的操作;最终的用户界面与交付形态。用一句话概括分工:人守住目标、边界与验收标准,AI 按约定例行执行工作。
12. 总结:从模糊想法到可验证软件
模糊的想法 ↓ grill-with-docs 确认范围、词汇表与技术决策 ↓ to-spec 可版本化、可验证的需求 ↓ to-tickets 带优先级与依赖的 GitHub Issues ↓ implement 每个 ticket:测试 → 实现 → commit ↓ code-review 代码健康度 + Spec 覆盖度 ↓ 可编译、可验证的软件一次对话结束后,Spec、Issues、依赖关系、commits 和测试证据都完整留在 GitHub 上——下一次会话从已记录的状态继续,而不是重新猜测意图。这正是 Spec 驱动迭代开发相对纯 Vibe Coding 的核心价值:把「一次性对话」升级为「可延续、可审计、可协作的工程资产」。
延伸阅读(仓库内配套章节)
- 从 Vibe Coding 到 Spec Coding:Spec 即代码的理念、三层规格结构与渐进迁移策略;
- Claude Code Skills 完整指南:
SKILL.md结构、Skill 触发机制与团队共享方式; - AI 辅助开发工作流最佳实践:AI 能力边界、项目知识库(
CLAUDE.md/AGENTS.md)与问题解决记录的维护方法。
【免费下载链接】easy-vibe💻 vibe coding 101|The first course for AI-native product builders.项目地址: https://gitcode.com/GitHub_Trending/ea/easy-vibe
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考