前言:
上一节我们介绍了 OpenSpec 的安装与配置,这一节我们将通过两个连贯的迭代案例------从零开发"猜数字游戏" 和增加"暗黑模式" ,完整演示 OpenSpec 的 探索 (Explore) → 提案 (Propose) → 实施 (Implement) → 归档 (Archive) 全流程。
通过这两个案例,你将亲眼见证规范文档如何在迭代中积累,并最终形成可追溯的工程知识。
1. OpenSpec 的 4 阶段工作流
OpenSpec 的工作流可分为 4 个阶段,每个阶段对应一条 OpenSpec 斜杠命令,如表 1 所示。
表 1:OpenSpec 的 4 阶段工作流
| 阶段 | 命令 | 作用 |
|---|---|---|
| 探索 | /openspec-explore |
了解代码库现状,分析现有能力与约束 |
| 提案 | /openspec-propose |
创建结构化规范文档 |
| 实施 | /openspec-apply-change |
按照 proposal 逐步实现代码,并严格对照规范验证 |
| 归档 | /openspec-archive-change |
将已完成的变更归档,形成可追溯的知识库 |
OpenSpec 的整体流程如图 1 所示。

图 1:OpenSpec 的整体流程
2. 前置准备:配置项目上下文
在开始实战之前,请确认已按照上一节完成 OpenSpec 的安装与初始化。若尚未初始化,需执行以下命令:
mkdir guess-number-game && cd guess-number-game
openspec init
接着编辑 openspec/config.yaml,填入猜数字游戏项目的技术栈信息。示例如下:
schema: spec-driven
context: |
Tech stack: HTML5, CSS3, Vanilla JavaScript
Storage: localStorage
No backend, pure frontend application
rules:
proposal:
- Always include "## Why" and "## What Changes" sections
specs:
- Use Given/When/Then format for scenarios
核心提示: config.yaml 中的 context 字段内容就是实际项目词频,以把 OpenSpec 为 AI 提供固定的上下文。例如,当项目是纯前端应用时,应填写"HTML5+CSS3+Vanilla JavaScript"。如果是 Python 后台项目,则补充本应用 Python 版本和本地使用的框架,如"Python 3.12+FastAPI+SQLite"。
配置完成后,有两种驱动方式可以选择以下两种方案驱动工作流:
- 方式 1:OpenSpec 斜杠命令(推荐) :在 TRAE 的 AI 对话中输入
/openspec-explore、/openspec-propose、/openspec-apply-change、/openspec-archive-change等命令,自动触发对应的技能工作流。 - 方式 2:手动输入指令:在 AI 对话中手动输入"请使用 OpenSpec 的 xxx Skill"指令,灵活控制每一步的操作。
3. 第一阶段:探索 (Explore)
探索阶段的目的是让 AI 深入了解代码库现状,在不写任何代码的前提下,理清现有功能、技术约束和已有规范,为后续的提案奠定坚实基础。
对于是否需要探索,可参考表 2 的判断标准。
表 2:探索阶段的适用场景判断
| 场景 | 是否需要探索 | 说明 |
|---|---|---|
| 全新项目,从零开始 | 通常不需要 | 代码为空,没有需要了解的现状 |
| 在已有项目基础上迭代 | 必须进行 | 需要了解现有实现,避免冲突 |
| 接手他人代码进行维护 | 强烈建议 | 摸清历史包袱和技术债 |
| 修复 Bug 或优化性能 | 建议进行 | 需要定位问题根源 |
对猜数字游戏这个案例而言,由于是一个全新项目,代码库为空,所以可以跳过探索阶段,直接进入提案阶段。
4. 第二阶段:提案 (Propose)
提案阶段是 OpenSpec 工作流的核心。执行 /openspec-propose 命令后,AI 会生成完整的规范化文档结构。
4.1 文档结构解析
- proposal.md:描述为什么做(背景、目标)和做什么(功能范围、影响的能力)。
- design.md:描述怎么做(技术方案、架构决策)。
- specs/ :能力目录(如
specs/game-core/spec.md),每个功能的详细规范(数据模型、场景、验收标准)。 - tasks.md:将实现过程拆解为可执行的任务列表。
这些文档共同构成了"规范即真理"的事实来源,后续的代码实现必须严格遵循这些文档。
4.2 实战演示:创建"猜数字游戏"
现在我们在一个纯网页应用实现"猜数字游戏"功能。在 TRAE 的 Agent 模式中,新建一个任务(即创建一个会话),输入以下提示词,触发 AI 的推理:
/openspec-propose 请为"猜数字游戏"创建规范文档
AI 执行后,会在 openspec/changes 目录下创建一个名为 guess-number-game 的子目录,并在该子目录下创建多个文件。此文件名称将是变更的任务 ID。在后续的流程中,将通过这个任务 ID 来推进流程。
执行完 /openspec-propose 后,AI 创建的目录和文件如下:
openspec/changes/guess-number-game/
├── proposal.md # 提议文档
├── design.md # 技术设计文档
├── tasks.md # 任务清单
└── specs/ # 规范清单
├── game-core/ # 游戏核心逻辑规范
├── game-state/ # 游戏状态管理规范
├── score-storage/ # 存储功能规范
├── history-view/ # 历史记录浏览规范
└── statistics/ # 统计数据展示规范
AI 还会简单列出各个文件的要点,以便于用户审查。例如,在这个项目中,AI 列出的审查信息如下:
1. proposal.md
## Why
猜数字游戏是一个经典的互动游戏。通过网页应用形式实现,可以提供便捷的娱乐体验
,该游戏能够锻炼玩家的逻辑推理能力,同时也记录成绩可以让玩家追踪自己的游戏历史和表现。
## What Changes
创建猜数字游戏网页应用,支持 1~100 范围内的随机数生成
实现 7 次猜测机会机制,每次猜测后给出"太高"、"太低"或"正确"的反馈
游戏状态持久化存储到 localStorage
提供历史记录查看功能
提供游戏统计数据展示(胜率、平均猜测次数等)
## Capabilities
### New Capabilities
'game-core': 游戏核心逻辑,包括随机数生成、猜测验证和反馈提示
'game-state': 游戏状态管理,包括剩余猜测次数、当前目标数字等
'score-storage': localStorage 存储管理,自动保存游戏记录
'history-view': 历史记录查看界面,展示过往猜测记录
'statistics': 统计数据计算和展示
### Modified Capabilities
-: 无现有功能能力修改
## Impact
新增 HTML/CSS/JS 文件实现游戏前端业务逻辑
使用 localStorage 进行数据持久化
无后端依赖,纯前端实现
2. design.md
design.md 将 proposal.md 中的"做什么"转化为"怎么做",它确保了以下事项:
1.技术选型有依据:每个技术选择都有明确的理由,而不是"因为 AI 默认用了这个"。
2.架构设计有规划:在写代码之前明确了目录结构、localStorage 存储策略。
3.关键决策有记录:游戏核心算法(二分查找策略)、localStorage 存储策略、
响应式设计方案等决策被显式记录下来,供后续参考。
4.验收标准可追溯:每条验收标准都有对应的实现方式和验证方法。
接下来 AI 生成规范,规范有多个文件,位于 specs 目录下,使用的是 Gherkin 格式。规范详细定义了边界条件、异常处理以及用户交互细节,如下所示:
# game-core Specification
## Purpose
TODO - created by archiving change guess-number-game. Update Purpose after
archiving.
## Requirements
### Requirement: Generate random target number
The system SHALL generate a random integer between 1 and 100 (inclusive) as the
target number when starting a new game.
#### Scenario: Generate target on new game
- **WHEN** user starts a new game
- **THEN** system generates a random integer between 1 and 100
- **AND** the generated number is stored as the target number
3. tasks.md
提案阶段的最后一步,AI 会根据技术方案生成任务列表 tasks.md,具体内容如下:
## 项目初始化与基础文件
- [ ] 1.1 创建 index.html 主页面
- [ ] 1.2 创建 styles.css 样式文件
- [ ] 1.3 创建 script.js 脚本逻辑文件
## 实现游戏核心逻辑
- [ ] 2.1 实现随机数生成函数 (1~100)
- [ ] 2.2 实现猜测验证函数 (范围检查、格式检查、重置检查)
- [ ] 2.3 实现猜测比较逻辑 (太高/太低/正确)
- [ ] 2.4 实现游戏状态管理 (目标数字、猜测次数、已猜测序列)
## 实现用户界面
- [ ] 3.1 实现游戏标题和说明区域
- [ ] 3.2 实现剩余次数显示组件
- [ ] 3.3 实现已猜测数字显示区域
- [ ] 3.4 实现输入框和提交按钮
- [ ] 3.5 实现反馈消息区域
- [ ] 3.6 实现游戏结果弹窗 (胜利/失败)
- [ ] 3.7 添加响应式布局适配
## 实现 localStorage 存储
- [ ] 4.1 实现游戏记录保存函数
- [ ] 4.2 实现历史记录加载函数
- [ ] 4.3 实现历史记录显示组件
- [ ] 4.4 实现统计计算逻辑 (胜率、最佳成绩)
- [ ] 4.5 测试浏览器兼容性
## 测试和优化
- [ ] 5.1 测试输入验证逻辑
- [ ] 5.2 测试游戏流程 (胜利/失败路径)
- [ ] 5.3 测试 localStorage 持久化功能
- [ ] 5.4 测试响应式设计
- [ ] 5.5 修复发现的 bug
## 优化和完善
- [ ] 6.1 添加动画效果支持 (渐入渐出)
- [ ] 6.2 添加键盘快捷键
- [ ] 6.3 优化 UI 样式
可以看到,我们只是使用 /openspec-propose 提出了一个需求,AI 就为我们创建了这么多文件。这些文件共同构成了"猜数字游戏"功能的完整事实来源。后续代码必须严格遵循这些文档。这正是规范驱动编程的"规范即真理"执行的体现。
5. 第三阶段:实施 (Implement)
在提案与规范确认无误后,即可进入实施阶段,开始编写代码。
在 TRAE 中输入以下命令,即可启动编码流程:
/openspec-apply-change guess-number-game
若不指定具体一个任务变更,则在直接写如下:
/openspec-apply-change
执行后,AI 将自动加载当前变更目录(如 openspec/changes/2026-05-11-guess-number-game/)下的所有规范文件,包括 proposal.md、design.md、specs/ 及 tasks.md,并严格按照 tasks.md 中的任务顺序,逐条实现代码。每完成一项任务,AI 会自动将该任务从未完成标记为已完成。
AI 执行 /openspec-apply-change 后,生成或修改后的文件如下:
index.html # 主页面
css/
└── styles.css # 样式文件
js/
├── game.js # 游戏核心逻辑
├── storage.js # 存储管理
└── ui.js # UI 交互逻辑
openspec/changes/guess-number-game/
├── proposal.md # 提议文档
├── design.md # 技术设计文档
├── specs/ # 规范清单
└── tasks.md # 任务清单 (已全部完成)
在本案例中,最重要的业务逻辑位于 game.js,代码如下:
class GuessNumberGame {
constructor() {
this.targetNumber = null;
this.remainingGuesses = 7;
this.guessHistory = [];
this.gameStatus = 'playing'; // playing, won, lost
this.minGuesses = 1;
this.maxGuesses = 100;
}
// 生成随机目标数字
generateTargetNumber() {
return Math.floor(Math.random() * (this.maxGuesses - this.minGuesses + 1)) + this.minGuesses;
}
// 开始新游戏
startNewGame() {
this.targetNumber = this.generateTargetNumber();
this.remainingGuesses = this.maxGuesses;
this.guessHistory = [];
this.gameStatus = 'playing';
this.saveCurrentGame();
return this.getGameState();
}
// 验证输入
validateInput(input) {
const number = parseInt(input, 10);
if (isNaN(number)) {
return { valid: false, message: '请输入有效的数字' };
}
if (number < this.minGuesses || number > this.maxGuesses) {
return { valid: false, message: `请输入 ${this.minGuesses}-${this.maxGuesses} 之间的数字` };
}
return { valid: true, number };
}
// 进行猜测
makeGuess(input) {
if (this.gameStatus !== 'playing') {
return {
success: false,
message: '游戏已结束,请开始新游戏',
gameOver: true,
won: false
};
}
const validation = this.validateInput(input);
if (!validation.valid) {
return {
success: false,
message: validation.message,
gameOver: false,
won: false
};
}
const guess = validation.number;
this.remainingGuesses--;
let result = '';
let isCorrect = false;
if (guess === this.targetNumber) {
result = 'correct';
isCorrect = true;
this.gameStatus = 'won';
} else if (guess > this.targetNumber) {
result = 'too-high';
} else {
result = 'too-low';
}
this.guessHistory.push({
number: guess,
result: result
});
// 检查是否用完所有机会
if (!isCorrect && this.remainingGuesses === 0) {
this.gameStatus = 'lost';
}
this.saveCurrentGame();
// 如果游戏结束,保存记录
if (this.gameStatus !== 'playing') {
this.saveGameRecord();
}
return {
success: true,
message: this.getFeedbackMessage(result, isCorrect),
result: result,
remainingGuesses: this.remainingGuesses,
gameOver: this.gameStatus !== 'playing',
won: this.gameStatus === 'won',
guessHistory: this.guessHistory,
targetNumber: this.gameStatus !== 'playing' ? this.targetNumber : null
};
}
// 获取反馈消息
getFeedbackMessage(result, isCorrect) {
if (isCorrect) {
return `恭喜!你猜对了!答案就是 ${this.targetNumber}!`;
}
if (this.gameStatus === 'lost') {
return ` 游戏结束!正确答案是 ${this.targetNumber},再试一次吧!`;
}
if (result === 'too-high') {
return `太高了!你还有 ${this.remainingGuesses} 次机会`;
}
return `太低了!你还有 ${this.remainingGuesses} 次机会`;
}
// 获取游戏状态
getGameState() {
return {
targetNumber: this.gameStatus !== 'playing' ? this.targetNumber : null,
remainingGuesses: this.remainingGuesses,
guessHistory: this.guessHistory,
gameStatus: this.gameStatus,
maxGuesses: this.maxGuesses
};
}
// 保存当前游戏状态到 localStorage
saveCurrentGame() {
try {
const gameState = {
targetNumber: this.targetNumber,
remainingGuesses: this.remainingGuesses,
guessHistory: this.guessHistory,
gameStatus: this.gameStatus
};
localStorage.setItem('guessNumberGame_current', JSON.stringify(gameState));
} catch (e) {
console.error('保存游戏状态失败:', e);
}
}
// 从 localStorage 恢复游戏状态
loadCurrentGame() {
try {
const saved = localStorage.getItem('guessNumberGame_current');
if (saved) {
const gameState = JSON.parse(saved);
this.targetNumber = gameState.targetNumber;
this.remainingGuesses = gameState.remainingGuesses;
this.guessHistory = gameState.guessHistory;
this.gameStatus = gameState.gameStatus;
return true;
}
} catch (e) {
console.error('加载游戏状态失败:', e);
}
return false;
}
// 清除当前游戏状态
clearCurrentGame() {
try {
localStorage.removeItem('guessNumberGame_current');
} catch (e) {
console.error('清除游戏状态失败:', e);
}
}
// 保存游戏记录
saveGameRecord() {
const record = {
timestamp: Date.now(),
targetNumber: this.targetNumber,
guesses: this.guessHistory.length,
isWon: this.gameStatus === 'won',
guessHistory: this.guessHistory
};
try {
const records = StorageManager.getRecords();
records.unshift(record);
StorageManager.saveRecords(records);
} catch (e) {
console.error('保存游戏记录失败:', e);
}
}
}
5.1 代码与规范的严格对齐
AI 执行 /openspec-apply-change 后,生成的代码必须逐条对照规范文档中的验收标准进行验证。表 3 列出了针对核心验收标准的验证要点及验证方法。
表 3:验证要点及验证方法
| 验证要点 | 验证方法 |
|---|---|
| 随机数生成 | 进行多次游戏,确认目标数字在 1~100 范围内且随机 |
| 输入验证 | 测试 0、101、非数字、空输入、重复数字 |
| 反馈显示 | 猜大、猜小、猜对,分别验证提示文字 |
| 次数限制 | 连续猜错 7 次后检查游戏是否结束 |
| 历史记录 | 刷新页面后检查记录是否存在 |
| 统计数据 | 验证胜率计算公式是否正确 |
5.2 界面效果
实施阶段确保生成的代码与规范严格对齐,具体表现在以下几方面:
- 游戏逻辑与规范一致:随机数范围、猜测次数限制、反馈规则与规范文档完全一致。
- 存储机制与规范一致 :
localStorage键名、数据结构与规范文档完全一致。 - 验收标准可验证:每条验收标准都有对应的代码实现和验证方法。
- 技术约束被遵守:纯前端实现,无后端依赖,响应式设计。
6. 第四阶段:归档 (Archive)
在功能实现并通过验收后,我们需要将当前的变更从"活跃状态"转变为"历史资产"。
6.1 执行归档命令
在 TRAE 中输入如下命令,将当前变更从 openspec/changes/ 移动到 openspec/changes/archive/,完成归档:
# 在 TRAE 中输入
/openspec-archive-change guess-number-game
归档不仅仅是"移动文件",它标志着该功能的规范文档已进入只读状态,除非有新的变更提案,否则不再修改。归档后的文件会纳入版本管理,成为项目历史的一部分。手动执行下面的命令,将规范文档纳入版本管理,和代码一起同源管理:
git add openspec/changes/archive/2026-05-11-guess-number-game/
git commit -m "feat: archive guess-number-game change"
6.2 归档的价值
归档赋予规范文档以下 3 个重要属性:
- 可追溯性:每个功能的完整需求、设计和实现决策都有据可查。
- 可复用性:遇到类似功能时,直接参考已归档的规范,无须从头设计。
- 可审计性:规范文档纳入版本管理,团队可以看到每个变更的完整历史。
7. 进阶实战:增加暗黑模式
接下来为猜数字游戏增加暗黑模式,演示 OpenSpec 如何在已有功能基础上新增能力。因为本次变更是增加新功能,所以使用 /openspec-explore 进行探索。
7.1 探索:了解现有实现
在 TRAE 中,通过以下提示词即可触发探索。AI 会探索当前的项目目录、功能,并给出实现建议。
/openspec-explore 为猜数字游戏增加暗黑模式
AI 会基于对现有代码的分析,给出相应的设计方案。例如,在本案例中,AI 给出了下列建议:
当前代码结构分析
├── index.html # 主页面(无主题切换按钮)
├── css/styles.css # 样式文件(纯亮色主题)
├── js/game.js # 游戏核心逻辑
├── js/storage.js # 存储管理
└── js/ui.js # UI 交互逻辑
暗黑模式实现方案
方案:CSS 变量 + JavaScript 切换
核心思路 :使用 CSS 自定义属性 (CSS Variables) 定义主题颜色,通过 JavaScript 切换 'dark' class 来改变主题。
需要修改的文件
| 文件 | 修改内容 |
|---|---|
index.html |
添加主题切换按钮 |
css/styles.css |
添加 CSS 变量和暗黑模式样式 |
js/ui.js |
添加主题切换逻辑和持久化 |
配色方案对比
| 元素 | 亮色模式 | 暗黑模式 |
|---|---|---|
| 背景渐变 | #667eea → #764ba2 |
#1a1a2e → #16213e |
| 容器背景 | white |
#1f1f3a |
| 游戏区域 | #f8f9fa |
#2a2a4a |
| 文字颜色 | #333 |
#e0e0e0 |
| 边框颜色 | #eee |
#3a3a5a |
实现步骤规划
- 修改 CSS :定义 CSS 变量,添加
.dark类样式 - 修改 HTML:添加主题切换按钮(太阳/月亮图标)
- 修改 JS:添加切换逻辑,保存到 localStorage
- 处理边界情况:页面加载时获取用户偏好
潜在风险与考虑
- 图标颜色:FontAwesome 图标在暗黑模式下可能需要调整
- 动画效果:确保动画在两种模式下都正常显示
- 兼容性:CSS 变量在现代浏览器中支持良好
- 性能:切换主题是纯 CSS 操作,性能开销小
在探索阶段可以和 AI 反复对话,确定方案。在方案确定好后,可以直接使用 /openspec-propose 进行提案。
7.2 提案:定义暗黑模式规范
在 TRAE 中使用以下提示词进行提案,提案会自动使用探索阶段确定的方案。
/openspec-propose 为猜数字游戏增加暗黑模式
TRAE 执行完提案后,会在 openspec/changes 目录下创建一个名为 add-dark-mode 的子目录,其中 add-dark-mode 就是本次变更的任务 ID。
和前面的流程一样,提案会创建相应的 proposal.md、design.md、规范文档和 tasks.md,这里不再赘述。
7.3 归档:形成知识库
在完成了功能开发并归档后可以看到,openspec/changes/archive/ 目录下保存了已完成变更的完整规范文档:
2026-05-11-guess-number-game/:猜数字游戏的原始实现。2026-05-11-add-dark-mode/:暗黑模式的功能迭代。
这个目录结构本身就是项目的历史记录。当有团队新成员加入时,其只需浏览 openspec/changes/archive/ 目录,就能了解项目的完整演进历史------每个功能是什么时候加的、为什么加、设计了什么、是如何实现的,这些信息都在规范文档中,而不是散落在 Git 提交历史和办公聊天工具中。
8. 其他操作与总结
除了上述核心步骤,OpenSpec 还提供以下辅助操作:
- 规范审查:在规范文档编写完成后,提交给团队成员审查,重点检查功能范围是否清晰、数据模型是否合理、验收标准是否可验证。
- 规范复用:遇到类似功能时,直接参考已归档的规范文档,修改功能范围和数据模型即可快速复用。
此外,4 个阶段可根据任务复杂度灵活裁剪,具体建议如表 4 所示。
表 4:不同复杂度任务的工作流裁剪建议
| 任务复杂度 | 推荐工作流 |
|---|---|
| 简单任务(修复 Bug、小改动) | 直接实施,可跳过探索和提案 |
| 中等任务(新增单个功能) | 提案→实施→归档 |
| 功能迭代(在已有功能基础上新增功能) | 探索→提案→实施→归档 |
| 复杂任务(涉及多个功能、架构变更) | 完整 4 阶段 |
OpenSpec 的四个阶段构成了一个从"模糊需求"到"可追溯规范"的完整循环。探索阶段让 AI 了解现状,提案阶段让 AI 明确目标,实施阶段让 AI 按规范行动,归档阶段将这一切固化为工程资产。这正是规范驱动编程的核心价值------通过结构化的流程保障质量下限,并将每次迭代的知识转化为团队可传承的资产。