在周三之前,我花了每周分配给Claude的预算中的64%来开发一个旨在减少对Claude使用频率的工具。这种具有讽刺意味的情况,确实值得专门写一篇说明来描述。
这个工具被称为“spec-writer”:它是一种基于Claude Code开发的技能,能够在编写任何一行代码之前,根据用户提供的模糊需求生成结构化明确的需求文档、技术计划以及任务分解方案。
它所解决的问题,正是大多数开发者在使用AI编码助手的第一周就会遇到的问题:这些助手会“自信地”朝着错误的方向进行开发,而你却因此付出双重代价——一次是消耗代币,另一次则是需要重新修改代码。
本教程将教你如何安装spec-writer,如何在实际项目中使用它,以及如何解读其生成的输出结果,这样你就能及时发现那些可能会浪费你时间的错误假设或不合理设计。
目录
直接使用提示语来指导助手开发的问题
如果你跳过了编写需求文档这个步骤,就会发生以下情况:
你脑海中有一个功能需求:“为用户提供导出数据的功能。”你打开Claude Code并描述了这个需求,助手随后生成了代码。乍看之下,代码似乎没什么问题,但你运行后发现:它不仅会导出所有数据,包括那些被“软删除”的记录;也没有分页功能;在处理大型账户时会出现超时现象;而且导出接口也没有任何身份验证机制。
这些错误其实都并不在你的原始需求描述中。助手是根据自己的判断来生成代码的,而这种判断虽然看似合理,但实际上却完全是错误的。直到你进行测试时,才发现了这些问题。
对于任何非简单的开发任务来说,直接使用提示语来指导助手开发,本质上面临的就是这个问题:你的提示语只反映了你意识中明确提出的需求,但每个功能背后其实都存在着一些你没有考虑到的潜在要求,而助手就会根据这些隐含的要求来生成代码。
大多数情况下,这些隐含的要求都是合理的;但有时候,它们也会导致严重的错误,而要发现这些错误往往需要花费很多时间。
这种错误的本质并不是“幻觉”,而是助手仅仅按照你提供的提示语来工作,而已这些提示语本身并不足以确保开发出正确的结果。
规范驱动的开发方式正是为了解决这个问题而设计的。像Julián Deangelis这样的专家已经对这种方法进行了深入的探讨,他们认为:编写需求文档并不是一种额外的负担,而是一种强制你在助手开始开发之前就明确各项要求的机制。
什么是规范驱动开发
规范驱动开发是指在编写代码或启动自动化工具之前,先制定结构清晰的规范文档。这份规范明确了功能需要实现的具体内容、所基于的假设条件,以及实现过程应分解为哪些步骤。
关键在于要明白规范的作用:规范并不是为了替代代码,而是为了让那些原本隐藏在开发过程中的决策变得显而易见。无论有没有规范,自动化工具最终都会做出这些决策;但有规范的话,这些决策可以在开发初期就被明确下来;而没有规范的话,就只能在测试阶段才发现这些问题。
针对规范驱动开发最有力的反对意见来自Gabriella Gonzalez:她认为“一份足够详细的规范本质上就是代码”。她的观点有一定道理,因为有些规范确实会详细到几乎与实现代码没有区别的程度。
但问题在于,这些规范所采用的抽象层次并不合适。规范的作用应该是明确各项决策,而不是预先完成这些决策的实现。“只有经过身份验证的用户才能执行此操作”属于决策内容,而“调用verifyJWT(token),如果失败则返回401错误码”则是具体的实现细节。规范应该侧重于前者,而后者则应由自动化工具来处理。
规范驱动开发可以分为三个层次:
-
规范优先:在开发每个功能之前先制定规范文档,然后将其作为输入提供给自动化工具。本教程重点介绍的就是这种工作方式。
-
以规范为依据:规范文档保存在代码仓库中,并与代码同步发展。当需求发生变化时,只需更新规范文件,再重新启动自动化工具即可使其适应新的要求。
-
将规范作为核心资源
:在这种情况下,规范本身就是最重要的开发成果,代码则是根据规范生成的,属于可随时替换的临时性产物。这是最高阶的规范驱动开发模式,也是许多团队正在努力的方向。
使用spec-writer工具,你可以立即开始采用“规范优先”的开发方式,而无需进行任何复杂的设置。
spec-writer的工作原理
spec-writer是一种属于Claude Code技能的工具——它是一个Markdown格式的文件,当被导入自动化工具的环境中后,会改变该工具的处理方式。
这种工具遵循一个原则:先生成完整的规范文档,然后直接标明其中所依赖的假设条件。它在生成结果之前不会要求用户进行补充说明,而是会立即生成完整的规范,并使用[ASSUMPTION: ...]标签标出所有未经用户明确指定的决策内容。之后用户就可以根据这些标记来修改错误之处。
这种方式比传统的问答式开发方式更快,因为它能让各种决策以一种可以直接应对的形式呈现出来,而无需用户事先进行预测。
生成的输出文件包含三个固定顺序的部分:
-
规范内容:明确功能的目的、用户需求、边界情况以及验收标准,这些信息会按照“给定条件/操作步骤/预期结果”的格式呈现。
-
实施计划:包括技术架构选择、数据模型变更、API接口设计、测试策略以及安全要求等内容。
-
具体任务列表:将整个开发过程分解为一系列有序且独立的任务,每个任务都可以在一次自动化工具运行中完成,并且每个任务都有各自的验收标准。
在完成这三个部分的编写后,该技能会生成一份假设项汇总:输出内容中的每一条[ASSUMPTION: ...]都会根据其影响程度进行排序。在将任何内容提交给智能助手之前,你都需要先查看这份汇总。
该技能与GitHub Spec Kit以及OpenSpec兼容。如果你使用的是这两种框架中的任何一种,只需将规范编写结果保存到.specify/或openspec/changes/目录中,然后继续后续操作即可。
如何安装spec-writer
spec-writer遵循Agent Skills标准,这意味着同一个SKILL.md文件可以在Claude Code、Cursor、GitHub Copilot、Gemini CLI以及任何支持该标准的智能助手中正常使用。你只需安装一次,它就可以在所有地方发挥作用。
安装步骤
如果还没有创建技能目录,请先创建一个,然后克隆相应的仓库:
mkdir -p ~/.claude/skills
git clone https://github.com/dannwaneri/spec-writer.git ~/.claude/skills/spec-writer
在Windows PowerShell中操作时:
注意:PowerShell使用反引号(`)来表示行续接,而不是反斜杠。
New-Item -ItemType Directory -Force -Path "$HOME\.claude\skills"
git clone https://github.com/dannwaneri/spec-writer.git "$HOME\.claude\skills\spec-writer"
以上就是全部的安装步骤。不需要安装任何软件包,也不需要编辑配置文件或输入API密钥。该技能实际上就是一个Markdown文件,智能助手会直接读取这个文件即可。
验证安装是否成功
打开Claude Code,然后输入以下命令:
/spec-writer test
如果安装正确,智能助手会读取SKILL.md文件并生成相应的规范结构——即使输入的内容仅仅是“test”这样的简单指令。你会看到三个部分以及假设项汇总。如果没有出现任何反应,请确认~/.claude/skills/spec-writer/SKILL.md文件确实存在。
如何编写你的第一个规范文档
调用该技能的格式如下:
/spec-writer [你的功能描述]
这个描述可以像你在Slack中发送消息时写的那样简略。该技能的任务就是将这些描述整理成规范的格式。你不需要写得非常详细,因为规范本身才是用来详细说明各项要求的。
一个实际示例
以下是一个来自Foundation项目的真实调用示例。该项目是一个基于Cloudflare Workers构建的联邦知识库:
/spec-writer Add CLI capture for Claude Code sessions stored in ~/.claude/projects/
这条命令只有十二个字,其中没有提到技术栈、数据模型细节、认证要求或错误处理机制等内容。所有这些信息都会在生成的规范文档中体现出来。
以下是该命令执行后的简化输出结果:
技术规格
功能简介:** 开发人员可以将自己本地文件系统中的Claude Code会话日志保存到Foundation系统中,这样这些日志在30天后被删除之前就能得到妥善保留。
适用用户及使用场景:
-
作为每天都会使用Claude Code的开发人员,我希望自己的编码会话记录能够被自动保存下来,这样那些关于架构设计或调试过程中的信息就不会在30天后丢失。
-
作为Foundation系统的用户,我希望通过同一个知识库来查看所有的CLI会话记录以及浏览器扩展程序产生的数据,这样我就可以在一个地方查询所有与AI相关的交互记录了。
验收标准:
当开发人员的Claude Code会话记录存储在~/.claude/projects/目录中时,如果他们运行Foundation的CLI捕获命令,系统会显示一份未捕获的会话列表,并且这些列表会按照会话创建的时间顺序进行排序。
如果某个会话已经保存在Foundation系统中,当开发人员再次运行捕获命令时,这个会话不会出现在列表中。
如果输入的.jsonl文件格式不正确,捕获命令在处理该文件时会记录错误信息,但会继续处理其他会话记录。
实施计划:
技术架构:**
CLI捕获功能是在本地运行的——它需要读取本地的文件系统数据,而Cloudflare Workers无法完成这一操作。[假设:CLI捕获工具是一个本地的Node.js脚本或Bun脚本,它会调用Foundation API来保存会话记录,而不是本身作为一个Worker来运行。]
API接口规范:
-
POST /api/sessions/import– 接收经过解析的JSON格式会话数据,返回会话ID -
如果会话已经存在,该接口会返回409错误代码
-
成功插入会话记录后,会触发相应的评估流程
待完成任务:
## 任务1:.jsonl文件解析器
**开发内容:** 编写一个解析器,能够读取Claude Code生成的.jsonl格式会话文件,并将其转换成Foundation系统内部使用的消息格式。
**可能涉及的文件:** cli/src/parsers/claudeCode.js
**验收标准:**
1. 能够正确解析有效的.jsonl文件,将其转换为正确的消息格式。
2. 对于格式错误的文件,解析器不应出现崩溃现象,而应记录错误信息并跳过这些错误行。
3> 如果文件内容为空,解析器应返回一个空数组。
**依赖库:** 无
需要确认的事项:
1. CLI捕获工具是一个本地脚本,它通过调用Foundation API来保存会话记录,而不是作为一个Worker来运行。
影响程度:高
如果你希望采用纯服务器less架构,请修改这一设计。
2> 会话记录的导入是手动进行的,而非自动批量导入。
影响程度:高
如果你希望实现自动背景捕获功能,请修改这一设置。
3> .jsonl文件名中的会话ID被用作去重键。
影响程度:中等
如果你的数据存储方案中会话ID的存储方式不同,请相应地调整代码。
4> 在当前版本中,不会对会话记录中的敏感数据进行清洗处理。
影响程度:中等
如果你的会话记录包含密码或密钥等敏感信息,请修改相关逻辑。
在读了这十二个字之后,立刻就有四个决定浮现出来——其中三个决策实际上对建筑设计产生了直接影响。
第三个假设(“.jsonl文件中的会话ID就是去重键”)很可能会引发最隐蔽的错误。如果代理程序根据文件名来执行去重操作,那么在会话名称被更改之前,这种机制应该是可以正常工作的。而在任何代码被编写出来之前,规范文档就已经发现了这个问题。
如何阅读输出结果
输出结果的阅读顺序应该是:首先查找[ASSUMPTION: ...]标签,然后再阅读与任务相关的内容。
阅读假设条件
每个[ASSUMPTION: ...]标签都标志着代理程序在哪些地方根据用户未明确指定的内容进行了自动填充。你的任务是仔细阅读这些假设条件,并针对每一条做出如下判断:
-
正确:该假设条件是正确的,保留原样即可。
-
需要修改:该假设条件有误,需要重新表述假设内容并重新运行测试流程。
-
暂不处理:对于当前迭代来说,这个假设条件并不重要,可以直接跳过它继续下一步。
影响程度的评级会告诉你哪些假设条件需要在开始编码之前先进行修正。影响程度较高的假设条件会影响到系统架构或数据模型;如果这些假设有误,修改它们会导致整个系统需要重新设计。而影响程度较低的假设条件则会影响那些日后容易更改的行为细节。
阅读验收标准
以“Given/When/Then”格式编写的验收标准是规范文档中用于检测范围错误的最有用部分。阅读每一条验收标准后,要问自己:这确实是我想要测试的内容吗?
验收标准的性质本质上是二元的。“未认证时返回401状态码”属于明确的验收标准,而“运行正常”则不属于。如果你在阅读某条验收标准时觉得“这个标准其实并不明确”,那么这说明这条标准背后隐藏着某种假设条件,你需要重新表述这条标准。
阅读任务内容
这些任务都是按顺序排列的,并且每个任务都能产生可验证的结果。在将任何任务交给代理程序执行之前,请先检查以下两点:
-
该任务是否包含了所有必要的上下文信息?如果任务要求“遵循现有的认证机制”,但你还没有向代理程序提供相应的认证代码,那么代理程序就会自行猜测。
-
该任务的验收标准是否与你实际想要测试的内容一致?如果验收标准不够明确,请在代理程序开始执行任务之前将其细化。
如何将规范文档交给代理程序
规范文档本身就包含了完成任务所需的所有上下文信息,它并不需要用户另行提供提示或说明。当为某个任务启动代理程序会话时,请将相关的规范内容与任务描述一起提供给代理程序。
以上面例子中的任务1为例,你的代理程序会话可能会这样开启:
上下文信息:
- 该系统是一个基于Cloudflare Workers、D1和Vectorize构建的联邦知识库。
- 会话数据以.jsonl文件的格式存储在~/.claude/projects/目录下。
- API接口的地址为https://.workers.dev。
规范内容:
[粘贴SPEC和PLAN部分]
任务内容:
[粘贴任务1的具体要求]
上述示例仅用于说明目的。请将其替换为您自己项目所使用的技术栈、文件路径以及API地址。关键在于要让代理在第一天就能获得与新团队成员相同的开发环境信息。
现在,代理已经掌握了需求信息、架构背景,以及一项具有明确验收标准的具体任务。由于规范中已经明确了相关细节,因此它不可能错误地判断去重键的值;同时,由于验收标准有明确要求,它也不能忽略错误处理环节。
这就是该规范所设计的目的——它并非取代代理的工作,而是将决策权从代理手中转移到您的手中,在工作开始之前就为所有事项制定明确的规则。
保存规范以备后续使用
如果您希望采用“以规范为导向的开发模式”,即让规范存储在代码仓库中,那么请将生成的结果文件保存到项目中的specs/目录下:
# 创建spec目录
mkdir -p specs
# 保存您的规范文件
# 将输出内容粘贴到specs/cli-capture.md文件中
当需求发生变化时,只需更新规范文件,然后重新让代理根据新的规范来调整开发工作。此时,规范才是权威依据,而非代码注释。
下一步该怎么做
在编写任何代码之前,先在下一个功能开发项目中尝试使用这种规范编写方式。规范中指出的那些问题会帮助您发现一些尚未被意识到的问题——而在将任务交给代理之前纠正这些高影响性的错误,正是这一方法的核心意义。如果跳过这个步骤,就相当于直接让代理随意决策。
如果您的项目规模正在扩大,建议尽快采用“以规范为导向的开发模式”。请将所有规范文件保存在代码仓库的specs/目录下。这样,当有新成员加入团队或代理开始新的工作流程时,他们可以直接参考这些规范来开展工作,而无需花费时间去反推代码实现细节。
目前,这种开发模式面临的最大挑战在于有人认为过于详细的规范实际上会变成代码本身。如果您的规范文件中包含了具体的实现细节,那就意味着您已经越过了合适的界限。应该把决策权保留给自己,只规定“只有经过身份验证的用户才能执行某项操作”,而将具体实现工作交给代理来完成。规范的作用应该是指出那些代理可能会犯错的环节,而不是详细描述功能的实现过程。
目前,《Agent Skills》标准已适用于Claude Code、GitHub Copilot、Cursor以及Gemini CLI等工具。规范编写工具的代码仓库地址为github.com/dannwaneri/spec-writer。
确实,我们在Claude项目中投入了64%的资源来开发这个工具,但这一努力确实取得了成效——通过这个规范,我们从一个短短12个字的提示中得出了4项重要的决策。其中第4项关于去重键的假设,如果处理不当,可能会导致程序出现错误,而这种错误在会话名称被更改之前是无法被发现的。
这不是幻觉,而是代理确实发挥了它所能发挥的最大作用。
正是通过规范,我们才能真正提升“辅助工具”的效用水平。