Skip to content

用 GitHub Issues 驱动 AI 全流程开发:从需求讨论到 macOS 成品 ​

在这篇教程中,我们会完整走一遍这样的过程:先把一个还比较模糊的想法告诉 AI,再和它一起把需求讨论清楚;接着让 AI 写出需求文档、在 GitHub 上拆好任务,最后按照任务顺序把软件真正做出来。

这种方法叫 Spec 驱动开发。Spec 是“需求规格”的简称。它不是一份写完就放在角落里的文档,而是后续拆任务、写代码、测试和审查时共同遵守的依据。需求发生变化时,先更新 Spec,再继续实现,而不是只在聊天里临时补一句。

和上一篇有什么区别?

《从 Vibe Coding 到 Spec Coding》主要解释为什么规范会成为 AI 开发的核心;本文不再重复理论,而是用一个真实 GitHub 仓库演示如何把规范变成 Issues、任务依赖、提交、测试和最终成品。

我们不会停在“讲概念”这一步。文章里的仓库、Issues、代码、测试和截图都来自一次真实开发。最开始,我们只有下面这一句话:

我想做一个 macOS 上的 CRM,用来管理联系人关系,帮助我梳理人脉。可以先使用假数据。

最后,我们得到了一个名为 Relationship Compass 的原生 macOS 应用。它可以搜索和筛选联系人、维护关系档案、导入 CSV、记录互动,并自动算出下一次应该联系谁。

最终完成的 Relationship Compass 联系人管理界面

你可以直接查看这次实践产生的公开 GitHub 示例仓库。仓库只使用假数据,里面保留了需求文档、GitHub Issues、提交记录、源代码和测试。

1. 先理解:什么是 Spec 驱动开发 ​

很多人第一次用 AI 写代码时,会采用下面这种方式:

text
告诉 AI 想做什么 → AI 写代码 → 发现不对 → 再补一句要求 → 继续修改

做一个小页面时,这种方式通常够用。但项目变大后,很容易遇到三个问题:

  1. 前面讨论过的要求,过几轮对话后被忘掉了;
  2. AI 一次改很多文件,你不知道现在到底完成了多少;
  3. 功能看起来能运行,却没人逐条检查它是否真的符合最初需求。

Matt Pocock 的 Skills 就是为了解决这些问题。这里的 Skill 可以先简单理解成“写给 AI 的标准工作流程”。它不会只告诉 AI 写哪一段代码,而是规定 AI 在每个阶段应该先做什么、产出什么、什么时候停下来让你确认。

1.1 它和直接让 AI 写代码有什么不同 ​

普通的 AI 辅助开发,常常把聊天记录当成唯一需求来源。Spec 驱动开发则会在写代码前,先把已经确认的要求保存成仓库里的正式文档。后续每一步都回到这份文档检查。

直接从聊天开始写Spec 驱动开发
AI 主要依赖当前聊天内容AI 以仓库中的 Spec 为主要依据
想到一个要求就直接补一句先确认需求,再更新 Spec 和任务
进度通常只存在于 AI 的总结里进度保存在 GitHub Issues 和提交中
完成后主要看“能不能运行”完成后逐条对照 Spec 检查有没有漏项

因此,Spec 驱动开发的重点并不是“多写一份文档”,而是让需求从聊天中的一句话,变成整个开发过程都能引用、更新和验证的共同标准。

1.2 GitHub 在这条流程中具体做什么 ​

一次聊天只能保存“我们刚才说了什么”,GitHub 则可以长期保存“项目已经决定了什么、接下来要做什么、哪些事情已经完成”。

在这篇教程里,GitHub 不只是存放源代码的网盘。它同时承担三种角色:

  1. 项目档案室:保存 Spec、项目用词和重要技术决定;
  2. 任务看板:用 Issues、优先级和依赖关系表示工作顺序;
  3. 完成记录:用提交、测试结果和关闭状态证明每张任务是怎样完成的。
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

下面这张表更具体地展示了 GitHub 在每个阶段发生的变化:

开发阶段GitHub 中发生什么Relationship Compass 的实际结果
需求讨论结束把统一用词和重要决定写入仓库CONTEXT.md 和 2 份 ADR
生成 Spec保存需求文件,并创建一张总 Issuespecs/relationship-compass-mvp.md 和 Issue #1
拆分任务创建实现 Issues,添加优先级和前置依赖Issues #2–#6
逐张实现每完成一张 Issue,就产生对应提交并运行测试5 个主要功能提交
完成任务移除 ready-for-agent,添加 completed-by-agent,关闭 Issue#2–#6 全部关闭
最终审查把审查修复继续提交,确认无遗漏后关闭总 Issue3 个修复提交,#1 最终关闭
mermaid
flowchart LR
  A["讨论结果"] --> B["仓库中的 Spec"]
  B --> C["GitHub 总 Issue #1"]
  C --> D["实现 Issues #2–#6"]
  D --> E["优先级 + 前置依赖"]
  E --> F["代码提交 + 测试"]
  F --> G["关闭实现 Issue"]
  G --> H["最终审查"]
  H --> I["关闭总 Issue"]

所以 GitHub 在这里更像一块“有记忆的开发工作台”。AI 每次开始工作前都可以先读取当前状态;人也可以随时打开仓库,看到需求、进度、代码和验证结果,而不必翻完整聊天记录。

1.3 整条路线先看一遍 ​

这次实践会依次使用五个命令:

  1. grill-with-docs:先和 AI 讨论,把“我大概想做什么”变成双方都理解的明确范围;
  2. to-spec:把已经确认的讨论整理成一份正式需求文档;
  3. to-tickets:把大需求拆成几张有先后顺序的 GitHub Issues;
  4. implement:让 AI 从第一张可以开始的任务卡出发,边测试边实现;
  5. code-review:完成后再检查两遍,一遍看代码质量,一遍看有没有漏掉需求。
text
想法 → 讨论清楚 → 写成文档 → 拆成任务 → 逐个实现 → 检查结果

现在不需要记住所有英文名词。你只要先记住一件事:我们不再让 AI 拿到一句话就马上写完整项目,而是先把需求说清楚,再让它按有记录、有顺序、可检查的方式开发。

2. 开始之前要准备什么 ​

如果你只想理解这套工作方法,可以直接继续往下读。如果你想自己跟着做一遍,需要提前准备:

  1. 一个 GitHub 账号;
  2. 已经登录的 GitHub CLI,也就是终端里的 gh 命令;
  3. Node.js 18 或更高版本,用来安装 Skills;
  4. 一个能够读取项目 Skills 的编程 AI 工具;
  5. 如果要运行本文的 macOS 示例,还需要一台 Mac 和 Xcode。

2.1 安装 Matt Pocock 的 Skills ​

先在你准备开发的项目目录中打开终端,然后运行:

bash
npx skills@latest add mattpocock/skills

安装过程可能会询问你要把 Skills 安装到哪里。如果希望直接安装全部内容、不逐项确认,可以使用:

bash
npx skills@latest add mattpocock/skills -y

本次实践实际安装了 35 个 Skills。安装完成后,它们会出现在项目的 .agents/skills/ 目录中。本文重点使用的是下面这条主流程:

text
grill-with-docs → to-spec → to-tickets → implement → code-review

这里比最初流传的“四步流程”多了最后的 code-review。原因很简单:软件“能运行”不等于“已经按要求做好”。完成实现后,再单独检查一次,往往能发现测试和第一次开发都没有注意到的问题。

项目特别大时怎么办?

如果你的项目大到连“应该先讨论哪些问题”都不清楚,可以先使用 wayfinder。它会帮助你列出还没有做出的关键决定,再回到本文这条主流程。第一次练习时不需要使用它。

相关说明可以查看 AI Skills for Real Engineers 和 Skills v1.1 更新说明。

2.2 创建 GitHub 示例仓库 ​

先确认终端已经登录 GitHub:

bash
gh auth status

如果还没有登录,再运行:

bash
gh auth login -h github.com

接着创建一个名为 relationship-compass-macos 的公开仓库,并把当前项目推送上去:

bash
gh repo create relationship-compass-macos \
  --public \
  --source . \
  --remote origin \
  --push

这几个参数分别表示:仓库公开、使用当前文件夹、把 GitHub 地址保存为 origin,并立即推送当前代码。

真实联系人数据不要放进公开仓库

本文为了方便读者查看完整案例,使用的是公开仓库和固定假数据。如果你要开发自己的联系人管理工具,请改用 --private,并在推送前检查样例文件、日志和 Git 历史中是否包含真实姓名、邮箱或关系备注。

2.3 准备任务标签 ​

GitHub 标签就像贴在任务卡上的彩色便签。它能告诉 AI 一张 Issue 是否可以开始,以及它有多重要。本例实际使用了下面几类标签:

标签表示什么
ready-for-agent需求已经写清楚,AI 可以开始做
priority:P0最先完成,否则后面的功能无法继续
priority:P1核心功能,但需要等待前置任务
priority:P2收尾、文档和完整验证
completed-by-agent已经由 AI 实现并验证完成

3. 这次要做一个什么软件 ​

我们的例子是一个 macOS 联系人关系管理工具。它不是用来追踪销售业绩,而是帮助个人记住:我认识谁、我们是什么关系、上次聊了什么、什么时候适合再次联系。

之所以选择这个例子,是因为它足够小,可以在一篇教程里走完;同时又包含真实软件常见的多个环节:界面、数据导入、本地保存、搜索筛选、日期计算和自动化测试。

第一版只做下面这些事情:

  • 内置 6 个假联系人,打开应用就能看到效果;
  • 支持搜索联系人,并按关系强度和圈子筛选;
  • 可以编辑组织、角色、邮箱、备注和跟进周期;
  • 可以从 UTF-8 CSV 文件导入联系人;
  • 可以记录一次互动,并自动计算下一次跟进日期;
  • 数据保存为本地 JSON 文件,下次启动时可以恢复。

第一版暂时不做云同步、AI 人脉评分,也不读取 macOS 系统通讯录。这样可以先把最重要的使用闭环做完整,同时避免一开始就申请敏感权限。

4. 第一步:用 grill-with-docs 把需求聊清楚 ​

grill-with-docs 可以理解为“先把需求问透”。它不会在收到第一句话后马上写代码,而是像一位有经验的产品和技术伙伴一样,继续问你几个真正会影响结果的问题。

进入新仓库后,像平时说话一样描述目标即可,不需要提前写正式的产品文档:

🙋 你
/grill-with-docs

我想实现一个 macOS 上的 CRM,可以管理我导入的联系人关系,帮助我梳理人脉。可以先使用假数据。

✨ Agent

好,我们先不急着写代码。我会和你一起把“第一版做什么、不做什么、数据放在哪里”讨论清楚。遇到需要选择的地方,我会先解释区别,再给出推荐。

这一步看起来像“多聊了一会儿”,其实是在提前避免返工。比如,要不要读取系统通讯录,会影响隐私权限;要不要云同步,会影响是否需要账号和服务器。这些问题如果等代码写到一半才决定,改动会更大。

4.1 对话如何逐步收敛 ​

下面是本例中最关键的几轮对话。你会发现,用户不需要懂 SwiftUI、数据库或测试框架,只需要说清楚自己想要的使用体验。

✨ Agent

我建议首版采用原生 SwiftUI 和本地优先架构,这样能获得真正的 macOS 体验,又不必先建设账号和服务器。先确认三件事:是否直接读取系统通讯录?是否需要云同步?首版准备如何导入数据?

🙋 你

首版使用原生 SwiftUI,只导入 UTF-8 CSV,不直接读取系统通讯录。数据全部保存在本地,也不需要账号、联网和后端。

✨ Agent

明白。那它更像“私人关系维护工具”,而不是销售漏斗。联系人档案除了姓名、组织、角色和邮箱,还需要哪些关系信息?怎样才算形成一个最小闭环?

🙋 你

我需要关系强度、圈子、备注和互动记录;还想看到哪些人该联系了。可以按最近一次互动和我设置的跟进周期计算,不需要把私人关系做成销售评分。

✨ Agent

建议把从未记录过互动的联系人直接放进“待跟进”列表;记录一次互动后,再按你设置的天数计算下一次日期。首版使用 6 个固定假联系人,并为搜索、导入、保存和日期计算编写自动化测试。这个范围可以吗?

🙋 你

可以,就按这个范围。先不要做云同步、AI 人脉评分和系统通讯录权限。我们已经达成共识,可以生成规格了。

在本例中,我们确定了以下范围:

决策选择原因
产品形态macOS 14+ 原生 SwiftUI获得原生文件选择、键盘操作和辅助功能
首版数据6 个确定性的假联系人不要求用户一开始就交出敏感数据
导入格式UTF-8 CSV容易准备、检查和修复
数据保存本地 JSON简单、透明、不需要后端
关系强度Close / Active / Dormant避免把私人关系变成销售评分
核心行为搜索筛选、资料维护、互动记录、待跟进列表构成可验证的最小闭环
隐私边界不读取系统通讯录、不联网首版不申请敏感权限
测试入口RelationshipStore 对外提供的功能测试用户能看到的结果,不依赖内部写法

4.2 同步建立项目语言 ​

讨论过程中,一些词很容易产生歧义。比如 Contact 既可以翻译成“联系人”,也可能被 AI 理解成“销售线索”;Follow-up 可能被理解成任务、提醒或通知。

因此,我们把已经确认的项目用词写进 CONTEXT.md。下面这段的意思是:Interaction 专门表示一次有日期的交流记录,Follow-up 专门表示根据最近交流推算出的下次联系日期。

markdown
**Interaction**:
A dated note that records a meaningful exchange with a Contact.
_Avoid_: Activity, event, touchpoint

**Follow-up**:
A suggested next connection date derived from the latest Interaction
and the Relationship Profile's rhythm.
_Avoid_: Task, reminder, notification

这不是为了把文档写得更正式,而是为了让后面的代码、测试和 Issue 一直使用同一套说法,避免 AI 一会儿写 Contact,一会儿又改成 Lead 或 Customer。

4.3 只记录真正重要的 ADR ​

ADR 是“架构决策记录”的缩写。你可以把它理解成一张很短的说明卡:记录一个重要选择,以及当时为什么这样选。这样几个月后再看到代码,不会疑惑“为什么没有用另外一种方案”。

本例只记录了两条真正重要的决定:

  • 0001-local-first-private-data.md:关系信息留在本地,不申请通讯录权限;
  • 0002-native-swiftui-macos.md:使用原生 SwiftUI,而不是 Electron 或 Web 壳。

ADR 不需要很长,也不用为每个小选择都写一份。只有那些以后很难改、而且存在明显取舍的决定,才值得单独记录。

4.4 确认共享理解 ​

讨论结束时,AI 会问你是否已经达成共识。只有你明确确认后,流程才进入下一步。

这个暂停很重要。此时改一句需求只需要几秒;如果等 20 个文件都写完才发现方向错了,就要花更多时间返工。

完成这一步后,你应该得到什么?

  • 一份明确的第一版功能范围;
  • 一份“不做什么”的清单;
  • 统一的项目用词;
  • 少量真正重要的技术决定;
  • 你对最终方向的一次明确确认。

这时还没有开始实现功能,是正常的。

GitHub 在这一步做什么?

需求讨论发生在你和 AI 的对话中,但确认后的结果不能只留在聊天里。本例把统一用词写进 CONTEXT.md,把两项重要技术选择写进 docs/adr/,然后提交到 GitHub。这样下一次会话重新打开仓库时,AI 可以直接读取这些决定。

此时 GitHub 负责“保存已经确认的上下文”,还没有开始创建实现任务。

5. 第二步:用 to-spec 写成需求文档 ​

需求已经聊清楚了,下一步是把聊天内容整理成一份以后可以反复查看的正式文档。这里的 Spec 就是“需求规格”:它应该讲清楚软件解决什么问题、用户可以完成哪些操作、哪些内容不在第一版范围内,以及最后怎样判断功能已经做好。

你只需要告诉 AI:把刚才确认的内容写下来。

🙋 你
/to-spec

根据刚才的讨论生成完整规格,保存到仓库,并发布到 GitHub Issues,标签使用 ready-for-agent。

✨ Agent

收到。我会直接整理刚才已经确认的内容,不会再从头问一遍。完成后,我会把文档保存进仓库,并创建一张总的 GitHub Issue 作为入口。

to-spec 会综合刚才的对话、项目用词和架构决定,生成一份结构化文档。本例最终得到的规格包括:

text
要解决的问题
第一版解决方案
24 条用户故事
已经确认的技术选择
测试方式
第一版明确不做的内容
其他补充说明

完整规格保存在 specs/relationship-compass-mvp.md,同时发布为 GitHub Issue #1。以后无论是人还是 AI,都可以从这张总 Issue 找到完整需求。

GitHub 在这一步做什么?

同一份需求会以两种方式存在:仓库中的 Markdown 文件便于版本管理和代码审查;GitHub Issue #1 则作为项目入口,方便跟踪状态和关联后续任务。

如果需求后来发生变化,应该先修改 Spec 文件并留下提交,而不是只在新聊天里补充一句。这样 GitHub 会保留“需求为什么变了、什么时候变了”的历史。

5.1 好 Spec 要描述行为,而不是文件 ​

一份好规格应该描述“用户最后能做到什么”,而不是过早指定“必须创建哪个文件”。例如,本例有一条用户故事是:

作为用户,我希望从未记录过互动的联系人也出现在待跟进列表中,这样刚导入的人不会被悄悄忘掉。

这句话包含三个信息:谁需要它、希望发生什么、为什么有价值。它没有规定 Swift 文件叫什么,所以以后即使重构代码,这条需求仍然成立。

5.2 提前说明怎样验证 ​

规格还要提前说明“做完后怎样证明它是对的”。本项目把 RelationshipStore 对外提供的功能当作主要测试入口,自动检查:

  • 样例数据初始化;
  • 搜索与组合筛选;
  • CSV 导入、校验与去重;
  • JSON 保存和恢复;
  • 关系档案编辑;
  • 互动记录的时间顺序;
  • 指定日期下的下一次跟进计算。

这些测试只关心用户最终能观察到的结果,不关心内部某个小函数被调用了几次。这样以后整理代码结构时,测试不会因为内部写法变化而全部失效。

完成这一步后,你应该看到什么?

仓库中会出现一份可以直接阅读的 Spec,GitHub 上会出现一张对应的总 Issue。此时你应该能逐条回答:“第一版到底要做什么?什么算完成?哪些功能明确不做?”

6. 第三步:用 to-tickets 拆成有顺序的任务 ​

一份 Spec 可能包含几十条要求,直接让 AI “一次全部实现”仍然很冒险。to-tickets 的作用,就是把大目标拆成几张能够单独完成、单独检查的 GitHub 任务卡。

接着输入:

🙋 你
/to-tickets

根据 Relationship Compass 的第一版需求文档拆分 GitHub Issues。每张任务都要交付一个可以独立演示的小功能,并写清楚优先级、完成标准和前置任务。

✨ Agent

我会先把任务清单和先后顺序展示给你。你确认没有漏项后,我再创建 GitHub Issues,并写清楚每张任务卡的完成标准和前置任务。

拆任务时,最容易犯的错误是按技术类别分工:一张票只建数据模型,另一张票只写界面,最后一张票才补测试。这样前几张票做完时,用户仍然看不到任何可以使用的功能。

更合适的方法叫 纵向切片。你可以把它想象成切蛋糕:每一块都同时包含蛋糕胚、奶油和水果。对应到软件里,就是每张 Issue 都尽量同时包含必要的数据、界面和测试,关闭一张就能多演示一个完整的小功能。

本例拆成 5 张实现票:

Issue优先级完成后可以看到什么前置任务状态
#2 Browse sample ContactsP0可启动的应用、样例联系人、搜索和详情无已关闭
#3 Import and persist private Contact dataP0CSV 导入去重、JSON 打开保存#2已关闭
#4 Organize Relationship ProfilesP1编辑资料、关系强度、圈子与筛选#2已关闭
#5 Record Interactions and plan Follow-upsP1互动历史与待跟进列表#4已关闭
#6 Polish and verify the MVPP2文档、错误状态、打包和完整验证#3、#5已关闭
mermaid
flowchart LR
  T1["P0 · Browse sample Contacts"] --> T2["P0 · Import and persist"]
  T1 --> T3["P1 · Organize Profiles"]
  T3 --> T4["P1 · Interactions and Follow-ups"]
  T2 --> T5["P2 · Polish and verify"]
  T4 --> T5

GitHub 在这一步做什么?

to-tickets 会把 Spec 中的大目标发布为独立 Issues,并给它们添加 priority:P0、priority:P1 或 priority:P2。本例还使用了 GitHub 原生的 Blocked by 依赖关系,所以 #6 会明确等待 #3 和 #5,而不是只在正文里写一句“以后再做”。

这一步之后,GitHub 从“需求档案室”变成了真正的任务看板。

6.1 任务为什么要有先后顺序 ​

表格里的 Blocked by 表示“必须等待谁先完成”。例如,应用还不能显示联系人时,就不适合先开发联系人资料编辑。

流程刚开始时,只有 #2 可以动手。#2 完成后,#3 和 #4 都具备了前置条件;#5 必须等 #4 完成;最后的 #6 则要等导入保存和互动跟进两条功能线都完成。

Skills 把“所有前置任务已经完成、现在可以开始”的那几张票称为 任务前沿。名字听起来有些抽象,其实就是“当前没有被卡住的任务”。

优先级和依赖是两回事:P0 表示很重要,依赖关系则表示现在能不能做。一张很重要的任务,如果依赖的基础功能还没完成,也需要先等待。

6.2 不要拆成横向任务 ​

下面这种按技术层拆分的方法不适合让 Agent 连续交付:

text
创建所有数据模型 → 创建所有 Store → 创建所有 UI → 最后补测试

因为任何一张中间任务完成后都无法单独使用,要到最后才知道各层能不能真正连起来。更好的拆法是:

text
先让“浏览样例联系人”从模型到 UI 完整工作并通过测试,
再增加“导入与保存”的完整路径。

完成这一步后,你应该看到什么?

GitHub 上会出现 5 张实现 Issue。每张 Issue 都有优先级、验收标准和前置任务。你不需要自己猜下一步做什么,只要从当前没有被阻塞的第一张任务开始。

7. 第四步:用 implement 逐张任务实现 ​

任务已经拆好后,才正式进入写代码阶段。implement 会读取 GitHub Issues,找到当前没有被前置任务卡住、同时优先级最高的那一张,然后只围绕这张票工作。

输入:

🙋 你
/implement

根据优先级和依赖关系逐个实现所有 ready-for-agent Issues,从第一个未被阻塞的 Issue 开始。每张票使用 TDD,在完成后运行类型检查和对应测试并提交。

✨ Agent

我会一次只处理一张可以开始的任务。每张任务都先写测试,再完成代码、运行构建并提交。全部完成后,我会继续检查代码质量和需求完成情况。

本例中,每张任务完成后都会留下一个主要提交。这样如果某一轮出现问题,可以准确知道是哪张任务带来的修改。

GitHub 任务主要提交
#2 浏览样例联系人9d9d7bd
#3 导入并保存联系人935750b
#4 维护关系档案329bd67
#5 记录互动和跟进83f4af6
#6 打磨、打包和验证3ae0bbf
审查后修复cbad102、11361ca、d1c83be

GitHub 在这一步做什么?

Agent 不会随便挑一项功能开始写。它先读取 ready-for-agent、优先级和 Blocked by,找到当前可以执行的 Issue。完成后,把提交哈希和测试结果写回对应 Issue,移除 ready-for-agent,添加 completed-by-agent,再关闭这张任务。

因此,GitHub 上的 Issue 状态就是项目的真实进度,而不是一份需要手动维护、很快就会过期的旁观清单。

7.1 每张任务都先证明“现在还不行” ​

本例使用 TDD,也就是“测试驱动开发”。这个名字听起来很专业,但做法并不复杂:先写一个描述正确结果的测试,确认它现在会失败;再补上最少的代码,让测试变成通过。

以 CSV 导入这张任务为例,Agent 实际按照下面的顺序工作:

  1. 先写一个测试:同一份 CSV 导入两次,联系人数量不能翻倍;
  2. 运行测试,确认当前版本确实还做不到;
  3. 实现 CSV 读取和去重,让这个测试通过;
  4. 再补一个测试:CSV 表头错误时,原来的联系人不能被破坏;
  5. 修正实现,重新运行这一组测试和完整构建;
  6. 提交代码,关闭当前 Issue,再领取下一张没有被阻塞的任务。

本项目使用 Swift Testing:

bash
swift test --filter RelationshipStoreTests
swift build
swift test

swift build 负责确认整个项目可以编译,swift test 负责运行全部自动化测试。最终共有 13 项行为测试,完整构建和测试都通过。

7.2 打开真实代码看一眼 ​

下面是本例真正提交到仓库的 RelationshipStore.importCSV,不是为了截图临时写的示例代码。

这段代码做了四件事:读取 UTF-8 CSV、检查表头、寻找重复联系人、准备导入结果。它会先在一份候选数据上完成全部处理,只有所有行都合法时才替换当前联系人列表。因此,文件中途出错也不会让应用留下“只导入一半”的状态。

Xcode 中的 CSV 导入、表头校验与安全去重实现

对应的 RelationshipStoreTests 会把同一份 CSV 连续导入两次,确认第二次只更新已有联系人,而不是再新增一份。测试还覆盖了重复表头和带 UTF-8 BOM 的文件等边界情况。

Swift Testing 中关于重复导入和异常表头的公开行为测试

完成这一步后,你应该看到什么?

GitHub 上的实现 Issues 会按照依赖顺序逐张关闭;仓库里会出现对应提交;应用功能会一块一块增加;每轮都能用测试和构建命令确认当前版本仍然可用。

8. 第五步:用 code-review 检查有没有遗漏 ​

所有 Issues 都关闭,并不代表工作已经结束。第一次实现时,AI 的注意力主要放在“把当前任务做通”,仍然可能出现两类问题:代码越来越难维护,或者有些需求表面上做了、实际还有缺口。

因此,当前流程在实现完成后还会运行 code-review。它分成两次独立检查。

8.1 第一遍:检查代码是否健康 ​

第一遍只看代码本身,不重新讨论产品需求。它会检查:

  • 文件和类型的名字是否容易理解;
  • 同一段逻辑是否在多个地方重复;
  • 一个界面文件是否承担了太多工作;
  • 修改一个小功能是否需要同时改很多无关位置;
  • 代码是否遵守仓库 AGENTS.md 中的约定。

本例第一次检查时,就发现 SwiftUI 主界面过大,而且“跟进天数”只是一个普通整数,很容易绕过最小一天的校验。随后我们拆分了界面职责,并把跟进周期变成一个会主动校验的数据类型。

8.2 第二遍:逐条检查需求是否真的完成 ​

第二遍不评价代码写得漂不漂亮,而是重新打开 Spec 和所有 Issues,逐条核对:

  • 有没有遗漏的要求;
  • 有没有只做了一半的功能;
  • 界面看起来存在,但实际行为是否正确;
  • 有没有擅自增加不在第一版范围内的功能。

这次审查并不是走形式,它找出了第一轮测试没有覆盖的真实问题:

  • CSV 中出现两个同名表头时,应用会报运行时错误,而不是安全提示;
  • 没有邮箱的联系人,无法通过“姓名+组织”识别为同一个人;
  • 普通联系人列表已经筛选了,但“待跟进”列表没有使用同样的筛选条件;
  • 数据虽然能保存,却不会在下次启动时自动恢复;
  • 详情页没有明确显示计算出来的下一次跟进日期。

我们先为这些问题补上测试,再修正代码,然后重新执行两遍检查。最终,代码质量检查和需求完成度检查都通过。

这里最值得记住的是:测试全部通过,只能证明“已经写进测试的行为”没有出错,不能自动证明最初需求一条都没有漏。 所以最后仍然需要重新对照 Spec。

完成这一步后,你应该看到什么?

审查发现的问题会变成新的修复提交;完整测试会再次通过;两份审查结果都明确给出通过结论。到这里,才适合把整个 Spec 标记为完成。

GitHub 在这一步做什么?

审查发现的问题继续以独立提交保留在仓库中。确认全部修复后,#2–#6 的完成评论会写明主要提交和验证结果;最后再关闭总需求 Issue #1。这样打开 Issues 页面 就能从任务一直追溯到代码和测试。

9. 最终得到的软件 ​

经过需求讨论、文档整理、任务拆分、逐张实现和两轮审查后,我们最终得到了 Relationship Compass。

它不是一张界面效果图,也不是一堆无法运行的示例代码,而是一个可以编译、测试、打包并双击打开的原生 macOS 应用。

交付项最终结果
GitHub 项目管理1 张总需求 Issue 和 5 张实现 Issues,全部关闭
实现过程9 个小步提交,按照任务依赖逐个完成
自动化验证13/13 项行为测试通过,完整项目可以编译
最终审查代码质量与需求完成度两项检查均通过
可运行产物脚本可以生成 Relationship Compass.app
数据边界数据只保存在本地,不读取系统通讯录,也不上传联系人关系

完成后的产品包含:

  • 6 个固定的假联系人;
  • 按姓名、组织、角色、邮箱和圈子搜索;
  • 按关系强度和圈子组合筛选;
  • 编辑联系人的关系档案;
  • UTF-8 CSV 导入、表头校验与安全去重;
  • 本地 JSON 打开、保存和下次启动恢复;
  • 互动记录与按时间排序的历史;
  • 根据最近互动和跟进周期计算待跟进联系人;
  • 原生 macOS .app 打包脚本;
  • 13 项自动化行为测试。

9.1 搜索与组合筛选 ​

在右上角输入 Founder 后,列表会从 6 位样例联系人缩小到 Maya Chen。左上角还可以继续选择关系强度和圈子。普通联系人列表与待跟进列表使用同一套筛选规则,不会出现一边筛选了、另一边仍显示全部联系人的情况。

按角色搜索联系人,只保留匹配 Founder 的 Maya Chen

9.2 编辑关系档案 ​

选择联系人后,可以修改组织、角色、邮箱、关系强度、圈子、跟进周期和备注。应用会自动清理重复圈子,并检查跟进周期至少为一天。保存后的内容会立即反映到搜索和筛选结果中。

Relationship Compass 的联系人关系档案编辑界面

9.3 记录互动并计算下次跟进 ​

为 Maya 记录一次 2026 年 8 月 9 日的互动后,应用根据 30 天的跟进周期,把下一次联系日期更新为 2026 年 9 月 8 日。互动内容会出现在历史记录中;日期到期后,这位联系人会自动进入“待跟进”区域。

记录互动后自动计算出的下一次跟进日期

新记录已经出现在 Interaction History 中

这些界面背后的关键行为都有对应测试。例如,同一份 CSV 重复导入不会产生重复联系人;错误表头不会破坏原有数据;保存和重新打开后,所有字段仍然一致;保存文件损坏时,应用会安全回到样例数据;搜索和两个筛选条件也可以一起使用。

如果你使用 Mac,可以按照下面的顺序下载、测试和打包这个项目:

bash
git clone https://github.com/sanbuphy/relationship-compass-macos.git
cd relationship-compass-macos
swift build
swift test
./scripts/package-app.sh
open "dist/Relationship Compass.app"

前两条命令下载代码并进入项目目录;swift build 和 swift test 分别检查编译与测试;打包脚本会在 dist 目录生成应用,最后一条命令负责打开它。

示例不是生产版通讯录

示例有意不读取 macOS 系统通讯录、不上传关系数据,也不提供 AI 人脉评分。真实产品如果增加云同步、联系人权限、加密或 AI 分析,需要重新讨论隐私边界,并记录新的架构决定。

10. 可直接复制的完整流程 ​

如果你想在自己的项目里复现这套流程,可以从下面四段输入开始。你不必原样照抄产品名称,但建议保留“先确认、再写文档、按依赖实现、最后审查”这些约束。

10.1 需求讨论 ​

🙋 你 · 可直接复制
/grill-with-docs

我想实现一个 macOS 上的 CRM,可以管理我导入的联系人关系,帮助我梳理人脉。可以先使用假数据。

请和我继续讨论第一版要做什么、不做什么、数据放在哪里、采用什么技术,以及最后怎样验证。每次只问当前最关键的问题;遇到选择时先解释区别并给出推荐。在我明确确认之前,不要开始写代码。

10.2 生成 Spec ​

🙋 你 · 可直接复制
/to-spec

把刚才已经确认的讨论整理成一份完整需求文档,保存到仓库,并发布为一张 GitHub 总 Issue,添加 ready-for-agent 标签。

不要重新问已经确认的问题。文档要写清楚用户能完成哪些操作、怎样验收、第一版明确不做什么;技术部分记录稳定决定,不要堆容易过期的文件路径。

10.3 拆分 Issues ​

🙋 你 · 可直接复制
/to-tickets

根据刚才的需求文档拆分 GitHub Issues。不要把数据、界面和测试完全分开;每张任务都要尽量交付一个可以独立演示的小功能。

每张 Issue 写清楚优先级、完成标准和前置任务。先把任务清单与依赖图展示给我,确认后再发布到 GitHub。

10.4 自动实现 ​

🙋 你 · 可直接复制
/implement

根据优先级和前置任务,实现所有 ready-for-agent Issues。每次只处理一张当前可以开始的任务;先写描述正确结果的测试,再完成实现,并经常运行测试和完整构建。每张任务完成后单独提交。

所有 Issues 完成后,分别检查代码质量和需求完成度。修复发现的问题,重新运行全部测试,直到两项检查都通过。

11. 什么时候适合“梭哈” ​

这里的“梭哈”不是指完全不看过程,而是指:当需求和安全边界已经确认后,让 AI 沿着任务清单连续工作,不必每写一个函数都停下来等待指令。

这条流程比较适合:

  • 范围可以通过讨论收敛的 MVP;
  • 有明确用户行为和验收标准的后台、App 或网站;
  • 可以通过测试或构建命令验证的仓库;
  • 希望 Agent 跨多个会话持续工作的项目。

它不太适合那些需求每小时都在变化、无法通过测试或构建验证,或者会直接操作生产数据的任务。

即使让 AI 连续实现,下面几个节点仍然应该由你亲自确认:

  1. 需求讨论结束时,确认第一版范围没有理解错;
  2. 创建 Issues 前,确认任务没有漏项,先后顺序合理;
  3. 涉及付费、生产部署、删除数据、账号权限和隐私时,确认具体外部操作;
  4. 完成后亲自打开真实界面,检查构建产物和审查结果。

真正可靠的自动开发,不是把所有决定都交出去,而是你负责目标、边界和最终验收,AI 负责把已经确认的事情稳定地执行下去。

总结 ​

到这里,我们已经从一句模糊想法出发,完成了需求讨论、正式文档、GitHub 任务拆分、逐张实现、测试、审查和应用打包。

这套方法最重要的不是记住几个斜杠命令,而是把开发过程变成一条随时可以查看、暂停和继续的路线:

text
模糊想法
  ↓ grill-with-docs
明确范围 + 统一用词 + 重要技术决定
  ↓ to-spec
可以逐条验收的需求文档
  ↓ to-tickets
有优先级和先后顺序的 GitHub 任务
  ↓ implement
逐张任务实现、测试和提交
  ↓ code-review
检查代码质量 + 检查需求完成度
  ↓
可构建、可验证的软件

当一段聊天结束后,需求文档、Issues、依赖关系、提交和测试仍然留在 GitHub 中。下一次继续开发时,AI 不需要从头猜测你想做什么,而是可以沿着这些记录继续往前走。

你可以把这条流程迁移到网站、后台系统、移动应用或自己的工作工具中。先选一个范围不大的真实需求,完整走通一次,再逐渐把它用到更复杂的项目里。

参考资料 ​