首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >OpenSpec 项目实战(一) | 从零搭建项目骨架:OpenSpec 工作流跑通全流程实录

OpenSpec 项目实战(一) | 从零搭建项目骨架:OpenSpec 工作流跑通全流程实录

原创
作者头像
运维有术
发布2026-05-14 21:28:52
发布2026-05-14 21:28:52
820
举报
文章被收录于专栏:运维有术运维有术

OpenSpec 项目实战(一) | 从零搭建项目骨架:OpenSpec 工作流跑通全流程实录

🚩 2026 年「术哥无界」系列实战文档 X 篇原创计划 第 109 篇,OpenSpec 最佳实战「2026」系列第 1

大家好,欢迎来到 术哥无界 | ShugeX | 运维有术

我是术哥,一名专注于 AI 编程、AI 智能体、Agent Skills、MCP、云原生、AIOps、Milvus 向量数据库的技术实践者与开源布道者

Talk is cheap, let's explore。无界探索,有术而行。

封面图 - 信息图风格:OpenSpec 工作流全景
封面图 - 信息图风格:OpenSpec 工作流全景

图 1:OpenSpec 工作流全景——6 步从探索到验证

说明:本文内容基于 OpenSpec(Fission-AI/OpenSpec)v1.3.1 和 React 19 + TypeScript + Vite 的实际操作记录整理而成,所有命令和代码均在 shuge AI Toolbox 项目中实际验证。文中的配置模板和参数建议仅供参考,实际效果请以你的业务数据和环境测试结果为准。如果有实际使用经验,欢迎在评论区分享交流。

1. 从方法论到实战

上期讲完方法论——2/8 法则、三步配置、6 个 Phase 的日常工作流。结论很明确:改 tasks 的 instruction 这一段配置文本,投入 20%,覆盖 80% 的质量提升。

但方法论终归是纸上谈兵。tasks instruction 升级之后,AI 生成的 tasks.md 真的能达到 2-5 分钟粒度吗?propose 一次产出 5 个工件,每个都是什么样子?apply 阶段 AI 还会夹带私货吗?

这期用一个真实项目把这些问题回答掉。项目名叫 shuge AI Toolbox——一个 AI 工具集合平台,纯前端,技术栈是 React 19 + TypeScript + Vite + Tailwind CSS 4。change name 叫 project-init,做的事情很简单:搭项目骨架、配好 OpenSpec 工作流、提交 GitHub。

完整流程对应下面的流程图:

代码语言:markdown
复制
Explore  →  Propose  →  Review  →  Apply   →  验证    →  Archive
  ↓           ↓          ↓         ↓           ↓          ↓
 澄清       生成       人工检查   按任务       浏览器     归档
 需求       5 工件     1-2 分钟   实现        确认       change

到文章结尾,你会拿到一个能跑的项目骨架、一套配好的 OpenSpec 工作流、一个已经推到 GitHub 的仓库。以及一个实测结论:tasks.md 的粒度到底有没有达到上期说的标准。

流程图:6 步从探索到验证
流程图:6 步从探索到验证

图 2:本文的 6 个步骤,每一步对应一个章节

2. 探索:用 Explore 澄清需求

project-init 也需要 Explore?

项目初始化看起来是 npm create vite@latest 一行命令的事,有什么好探索的?

实际上有几个关键决策如果不提前想清楚,propose 阶段 AI 会自行做主:

  • 技术选型:React 还是 Vue?用什么 UI 库?需不需要后端?
  • 目录结构:用默认的 src/components/ 平铺结构,还是参考 Creator-Toolbox 的模块化架构?
  • MVP 边界:第 2 期做到什么程度就停下?工具注册中心是这期做还是下期做?

这些决策点不复杂,但每个都会影响 propose 的产出方向。

Explore 是多轮交互,不是一次输出

在 Claude Code 中执行 /opsx:explore,AI 进入 explore 模式。

第 1 轮:你说需求

AI 会问你想做什么。你可以这样描述:

项目名:shuge AI Toolbox 定位:AI 工具集合平台,前端项目,工具数据暂时硬编码 参考:Creator-Toolbox 的模块化架构 技术偏好:React 19 + TypeScript + Vite + Tailwind CSS MVP 目标:项目骨架能跑 + OpenSpec 工作流配置好 + 提交 GitHub

第 2 轮:AI 追问细节

AI 会追问几个深挖问题。这次实际被问了 4 个:

关于模块化 - 每个工具是独立可插拔的 React 组件?还是路由级别的独立 feature 模块? 关于工具数据硬编码 - 数据存在哪?data/tools.ts?JSON 文件? 关于骨架能跑 - MVP scope 里具体要有哪些东西? 关于 GitHub - 仓库名是 shuge-ai-toolbox?已经有的还是从零创建?

逐一回答后,AI 继续追问。

第 3 轮:AI 追加设计决策

components/ 是放在 src/components/ 还是 src/lib/components/?

这个问题可以拒绝——这期 MVP 没有 shared components 的需求。直接告诉 AI:

不需要这个目录。app/layouts/ 放布局,app/views/ 放页面,就够了。

AI 随后输出最终结论。注意:Explore 不是一次输出,是多轮交互。AI 会追问和澄清——它在帮你把模糊需求变成清晰决策。

Explore 最终输出的决策结论

技术栈确认:

Layer

Choice

Framework

React 19 + TypeScript (strict)

Build

Vite

Styling

Tailwind CSS

Routing

React Router(动态,registry 驱动)

Data

TS 硬编码数组 + ToolManifest 接口抽象

选 React 不选 Vue,原因很实际:React 生态的训练数据量比 Vue 大得多,AI 生成 React 代码的质量肉眼可见地更稳定。Tailwind 不装组件库——原子类够用,还能省掉一个依赖。

说个实话:虽然 Explore 阶段讨论了 Zustand 和 Vitest,但最终 project-init 的 package.json 里没有这两个依赖。骨架项目不需要状态管理和单元测试——等到做工具注册中心的时候再加。这也算一个实际教训:Explore 阶段可以畅想技术栈,但 MVP 边界要划清,不用的就别装。

目录结构设计:

代码语言:markdown
复制
src/
  ├── app/
  │   ├── layouts/
  │   └── views/
  │       ├── Home.tsx
  │       └── NotFound.tsx
  ├── modules/               # .gitkeep — Phase 3
  ├── router/
  │   └── index.ts
  ├── lib/                   # .gitkeep
  └── tool-registry/
      └── catalog.ts

这个结构参考了 Creator-Toolbox 的模块化设计:modules/ 放功能,app/ 放应用层逻辑,tool-registry/ 放工具注册。区别在于 Creator-Toolbox 是 Vue 3,这里是 React,但目录组织思路一致。

MVP 边界:

本期只做骨架。具体来说:

  • 做的事:脚手架、基础目录、首页占位、路由(/ + 404 fallback)、OpenSpec 配置、Git 初始化 + GitHub
  • 不做的事:modules/ 只放 .gitkeep 占位,tool-registry/ 放接口骨架但不做完整功能,具体功能留给第 3 期

Explore 把模糊需求变成了清晰的开发计划。接下来 propose 就有明确的上下文可以用了。

3. 提议:propose 生成 5 个工件

一行 slash command 启动

在 Claude Code 中执行:

代码语言:bash
复制
/opsx:propose

不需要在命令行指定 change name 和 schema——AI 会自动执行 openspec new change "project-init" 创建 change 目录,schema 在 .openspec.yaml 中已配置。

执行后你会看到类似输出:

代码语言:markdown
复制
Change: `project-init`
Location: `openspec/changes/project-init/`
Schema: with-review

Artifacts created:
| Artifact | Path | Status |
|----------|------|--------|
| proposal | `proposal.md` | ✅ |
| design | `design.md` | ✅ |
| specs | `specs/project-scaffold/spec.md` | ✅ |
| review | `review.md` | ✅ |
| tasks | `tasks.md` | ✅ |

All artifacts complete!

Run `/opsx:apply project-init` to start implementing.

AI 按依赖顺序逐个生成:proposal.mddesign.mdspecs/review.mdtasks.md。注意 design 和 specs 都只依赖 proposal,AI 可能先做 design——实际顺序和依赖图有关,不是固定的。每个工件生成完自动存到 openspec/changes/project-init/ 目录下。

可以随时用 openspec status --change project-init --json 查看依赖状态:

代码语言:json
复制
{
  "changeName": "project-init",
  "schemaName": "with-review",
  "isComplete": false,
  "artifacts": [
    {"id": "proposal", "status": "ready"},
    {"id": "design", "status": "blocked", "missingDeps": ["proposal"]},
    {"id": "specs", "status": "blocked", "missingDeps": ["proposal"]},
    {"id": "review", "status": "blocked", "missingDeps": ["design", "proposal", "specs"]},
    {"id": "tasks", "status": "blocked", "missingDeps": ["design", "review", "specs"]}
  ]
}

可以看到 review 依赖 design+proposal+specs,tasks 依赖 design+review+specs。依赖链一目了然。

proposal.md:一张项目全景图

proposal 开头就点明了本次 change 的目标:搭建 shuge AI Toolbox 的项目骨架,配置好 OpenSpec 工作流,推送到 GitHub。

核心内容三块:

  • 技术栈:React 19 + TypeScript + Vite + Tailwind CSS 4 + React Router
  • 目录结构:和 Explore 阶段确认的一致
  • 交付清单:能跑的项目骨架 + OpenSpec 配置 + GitHub 仓库

没有意外,proposal 把 Explore 阶段的决策做了第一次格式化输出。

specs/:把决策变成可验证的规格

specs 目录下只有 1 个 capability 文件specs/project-scaffold/spec.md。不是每个路由一个独立 spec 文件,而是 7 个 Requirement 合并在一个文件中。

格式用的是 ### Requirement: + 简短描述:

代码语言:markdown
复制
### Requirement: 项目使用 Vite + React + TypeScript 脚手架初始化

### Requirement: 目录结构包含 app/views、modules、router、lib、tool-registry

### Requirement: 首页路由 / 显示项目名称 "shuge AI Toolbox"

### Requirement: 404 fallback 路由显示页面不存在提示

### Requirement: tool-registry 包含 ToolManifest 接口和 getTools 查询函数

### Requirement: OpenSpec 工作流配置完成(config.yaml + schema)

### Requirement: Git 仓库初始化并推送到 GitHub

坦白说,config.yaml 的 rules 里写了"Scenario 必须使用 #### 四级标题",但 propose 生成的 specs 并没有严格遵循。这可能是 instruction 和 schema 之间的小摩擦,不影响实际使用——specs 的作用是把决策变成可验证的规格说明,格式细节可以后续优化。

design.md:从做什么怎么做

design 是 specs 到 tasks 的桥梁。specs 说首页要显示项目名称,design 说首页组件用 Home.tsx,Tailwind 布局,调用 getTools() 动态渲染。specs 定义做什么,design 定义怎么做

design 里展示了最终的目录树和技术选型理由。每个选型都有简短的一句话说明——React 选型因为生态训练数据量大,Tailwind 选型因为不用装组件库。

还有一个设计决策值得注意:数据层用 TypeScript 硬编码数组 + ToolManifest 接口。这意味着 shuge AI Toolbox 是一个纯前端 SPA,npm run dev 就能跑起来,不需要后端服务。这是刻意的选择——需要后端的场景留给后面的项目实战系列,这期保持零门槛复现。

review.md:五维审查结论

review 在 design 和 tasks 之间插入,像个闸门——review 没过,tasks 就不会生成。

审查结论:

维度

状态

关键发现

边界条件

✅ 通过

骨架项目,边界条件简单

回滚方案

✅ 通过

首次提交,无历史数据需要迁移

测试覆盖

⚠️ 警告

路由 404 fallback 建议加测试

向后兼容

✅ 通过

全新项目,无兼容问题

任务粒度

⚠️ 警告

待 tasks.md 生成后复审

重点看任务粒度维度:⚠️ 警告(待复审)。这并不是说任务粒度有问题——而是 review 在 tasks 之前生成,它没法评估一个还不存在的东西。等 tasks 生成后人工检查确认粒度合理,即可视为通过。

坦率说,review 是自己审自己,结论偏宽松。但对于 project-init 这种简单 change,宽松问题不大。

tasks.md:全文最重要的一个文件

tasks.md 是三步配置的核心验证对象。如果 instruction 升级生效了,这里的每个 task 都应该是 2-5 分钟粒度、附完整代码和命令。

先看整体结构——8 个任务组、33 个子任务:

代码语言:markdown
复制
## 任务清单

- [ ] 1. 项目脚手架初始化(8 steps)
- [ ] 2. 目录结构创建(6 steps)
- [ ] 3. 工具注册中心接口(1 step)
- [ ] 4. 路由配置(5 steps)
- [ ] 5. 页面组件创建和清理(5 steps)
- [ ] 6. OpenSpec 工作流配置(3 steps)
- [ ] 7. Git 初始化和 GitHub 推送(4 steps)
- [ ] 8. 验证(1 step)

和草稿预期不同,只有路由配置(组 4)和页面组件(组 5)有 TDD 步骤,脚手架初始化部分(组 1-3)没有 TDD——脚手架就是跑命令、建目录,不需要先写测试再写实现,这很合理。

挑任务 4(路由配置)展示格式:

代码语言:markdown
复制
### 4. 路由配置(含 TDD)

- [ ] 4.1 写失败测试 - 测试 / 路由渲染 Home 组件
- [ ] 4.2 写最小实现 - createBrowserRouter + RouterProvider
- [ ] 4.3 运行测试确认通过

每个 step 都有精确的文件路径、完整代码、运行命令。AI 拿到这种 task 还能发挥什么?照着做就行了。

这就是上期说的核心结论在真实项目里的表现:任务细 + 附代码 → AI 只需执行 → 没有解释空间 → 夹不了私货。

人工检查:1-2 分钟的事

propose 跑完之后,做了两件事:

  1. 打开 review.md,扫一眼任务粒度维度的状态。⚠️ 警告,待 tasks 生成后复审。没问题。
  2. 打开 tasks.md,快速检查有没有 TBD、TODO、implement later 这类占位符。没有。

两个文件加起来看了不到 2 分钟。如果发现问题,直接编辑 Markdown 改掉就行,不用重跑 propose。这就是第 1 期说的第三层防线——收尾确认,1-2 分钟,做快不做重。

到这里,5 个工件全部生成并检查完毕。下一步是 apply。

依赖关系图:5 个工件的依赖链
依赖关系图:5 个工件的依赖链

图 3:5 个工件的依赖关系——review 是 design 和 tasks 之间的闸门

4. 执行:apply 按任务实现

启动 apply

在 Claude Code 中执行:

代码语言:bash
复制
/opsx:apply project-init

AI 读取 openspec/changes/project-init/ 下的所有工件,然后按 tasks.md 里的顺序逐个实现。因为每个 step 都有完整代码和命令,AI 基本是在执行一个精确的脚本。

apply 可能不会一次跑完。这次跑到 28/33 的时候暂停了——AI 没有 GitHub 推送权限,需要人工协助。这是正常的,按提示操作后输入 continue 就行。

最终 AI 汇报完成:

代码语言:markdown
复制
## Implementation Complete

**Change:** project-init
**Schema:** with-review
**Progress:** 33/33 tasks complete ✓

### Completed This Session

- [x] 1.1-1.8 项目脚手架初始化(Vite + React + TS + Tailwind + Router + ESLint)
- [x] 2.1-2.6 目录结构创建(app/layouts, app/views, modules, router, lib, tool-registry)
- [x] 3.1-3.2 ToolManifest 接口和查询函数
- [x] 4.1-4.3 路由配置(Home + NotFound)
- [x] 5.1-5.5 页面组件创建和清理
- [x] 6.1-6.3 OpenSpec 工作流配置
- [x] 7.1-7.4 Git 初始化和 GitHub 推送
- [x] 8.1-8.2 构建验证和最终推送

注意最后一行——task 8.1 是 AI 自动执行的构建验证:

代码语言:markdown
复制
> tsc -b && vite build
✓ 27 modules transformed.
dist/index.html                   0.46 kB
dist/assets/index-D0QgG82j.css    7.82 kB
dist/assets/index-DGZfOP5p.js   284.85 kB
✓ built in 99ms

99ms,零 error。AI 在 apply 阶段就把构建验证跑完了,不需要手工执行 npm run build

关键实现片段

展示 4 个核心文件的实际代码。

首页组件 src/app/views/Home.tsx

代码语言:typescript
复制
import { getTools } from '../../tool-registry/catalog';

export default function Home() {
  const tools = getTools();

  return (
    <main className="p-8">
      <h1 className="text-3xl font-bold mb-4">shuge AI Toolbox</h1>
      <p className="text-gray-600 mb-8">AI 工具集合平台</p>
      <section>
        <h2 className="text-xl font-semibold mb-4">工具列表</h2>
        {tools.length === 0 ? (
          <p className="text-gray-400">暂无工具</p>
        ) : (
          <ul className="space-y-2">
            {tools.map((tool) => (
              <li key={tool.id} className="border rounded p-4">
                <span className="font-medium">{tool.name}</span>
                <span className="text-gray-500 ml-2">- {tool.description}</span>
              </li>
            ))}
          </ul>
        )}
      </section>
    </main>
  );
}

注意几个关键差异和草稿预期的不同:组件名是 Home 不是 HomeView;导入了 getTools()tool-registry/catalog;使用条件渲染——tools.length === 0 显示"暂无工具",否则循环渲染。

工具注册中心 src/tool-registry/catalog.ts

代码语言:typescript
复制
export interface ToolManifest {
  id: string;
  name: string;
  description: string;
  route: string;
  category: string;
}

const tools: ToolManifest[] = [];

export function getTools(): ToolManifest[] {
  return tools;
}

catalog.ts 定义了 ToolManifest 接口和 getTools() 查询函数。这期 MVP 的 tools 数组是空的——首页会显示"暂无工具"。等到第 3 期做工具注册中心时,只需要往这个数组里加数据就行,接口和查询函数不用改。

路由配置 src/router/index.tsx

代码语言:typescript
复制
import { createBrowserRouter, RouterProvider } from 'react-router-dom';
import Home from '../app/views/Home';
import NotFound from '../app/views/NotFound';

const router = createBrowserRouter([
  { path: '/', element: <Home /> },
  { path: '*', element: <NotFound /> },
]);

export default function Router() {
  return <RouterProvider router={router} />;
}

这里用的是 react-router-domcreateBrowserRouter + RouterProvider API,不是 react-routerBrowserRouter + Routes/Route。React Router v7 推荐用 data router 模式。

项目入口 src/main.tsx

代码语言:typescript
复制
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import './index.css'
import Router from './router'

createRoot(document.getElementById('root')!).render(
  <StrictMode>
    <Router />
  </StrictMode>,
)

实际项目没有 App.tsx——main.tsx 直接导入 Router 组件。少一层文件嵌套,更简洁。

OpenSpec 配置的实际步骤

上期说的"三步配置"在实际操作中需要四步。原因:openspec init --tools claude 在非交互模式下不会生成 config.yamlwith-review schema fork 出来默认只含 4 个工件,review 需要手动添加。

第 1 步:初始化 OpenSpec

代码语言:bash
复制
openspec init --tools claude

输出:

代码语言:markdown
复制
- Creating OpenSpec structure...
▌ OpenSpec structure created
- Setting up Claude Code...
✔ Setup complete for Claude Code

OpenSpec Setup Complete

Created: Claude Code
4 skills and 4 commands in .claude/
Config: skipped (non-interactive mode)

注意最后一行:Config: skipped (non-interactive mode)。config.yaml 没有自动生成。

openspec init 还会自动在项目根目录创建 .claude/ 目录,里面包含 4 个 skills 和 4 个 commands——这是 Claude Code 集成用的,包括 /opsx:explore/opsx:propose/opsx:apply/opsx:archive 这些 slash command。

第 2 步:手动创建 openspec/config.yaml

代码语言:yaml
复制
schema: with-review

context: |
  技术栈:React 19, TypeScript, Vite, Tailwind CSS 4, React Router
  代码规范:ESLint
  所有新功能遵循 TDD 节奏——先写失败测试,再写实现代码

rules:
  specs:
    - 每个数据字段的变更,必须覆盖 null、空值、越界三种异常场景
    - Scenario 必须使用 #### 四级标题,否则归档时不生效
  design:
    - 涉及数据结构变更的设计,必须包含迁移方案
  tasks:
    - 每个 task 必须包含完整的测试代码和实现代码
    - 测试任务必须指定断言内容,不能只写「写测试」
    - 每组 task 的第一步必须是写失败测试,最后一步必须是验证通过
  review:
    - 重点检查 tasks.md 的粒度是否达到 2-5 分钟一个 step
    - 检查是否有占位符(TBD、TODO、implement later)

第 3 步:Fork Schema

代码语言:bash
复制
openspec schema fork spec-driven with-review

输出:

代码语言:markdown
复制
Note: Schema commands are experimental and may change.
- Forking 'spec-driven' to 'with-review'...
✔ Forked 'spec-driven' to 'with-review'

第 4 步:手动在 schema.yaml 中添加 review 工件

fork 出来的 with-review schema 默认只有 4 个工件:proposal → specs → design → tasks。review 需要手动添加。

打开 openspec/schemas/with-review/schema.yaml,在 artifacts 列表中新增 review artifact 定义,设置依赖链:

代码语言:yaml
复制
- id: review
  description: 设计审查
  requires: [design, proposal, specs]
  generates: review.md
  instruction: |
    对 design 和 specs 进行五维审查:边界条件、回滚方案、测试覆盖、
    向后兼容、任务粒度。每个维度给出 ✅ 通过 或 ⚠️ 警告 + 原因。

然后更新 tasks 的依赖,加上 review:

代码语言:yaml
复制
- id: tasks
  requires: [design, review, specs]

完成后用 openspec schemas 验证。有个小坑:即使 schema.yaml 已有 5 个工件,openspec schemas 的描述文字仍显示 4 个(描述字段不会自动更新),但实际 propose 时会正确生成 5 个工件。

四步做完,日常开发就是反复跑 explore → propose → review → apply → archive。

踩坑记录

这次 project-init 踩了两个坑。说实话都不难,但如果不知道的话会卡住。

踩坑 1:Vite 初始化目录非空

tasks.md 写的是 npx create-vite@latest . --template react-ts,但因为项目目录已有 openspec/.claude/ 等文件(OpenSpec init 产物),Vite 检测到目录非空,操作直接被取消。AI 的处理方式是创建临时目录初始化 Vite,再把文件迁移回来。

建议顺序:先 npx create-vite 初始化空目录,再 openspec init。这样可以避免冲突。如果项目目录已有 OpenSpec 文件,要么先清空,要么接受 AI 的临时目录方案。

踩坑 2:GitHub 推送反复失败

AI 跑到 task 7(Git 初始化和 GitHub 推送)时卡住了——没有 GitHub 推送权限。apply 暂停在 28/33 的位置,AI 输出了三个选项:手动创建仓库、给它 GitHub 凭据、跳过 GitHub。

这其实是个前置配置问题。AI 要直接执行 gitgh 命令,前提是你本地已经装好 GitHub CLI 并完成认证。配置步骤:

代码语言:bash
复制
# 安装
brew install gh

# 认证(交互式,选 Paste an authentication token)
gh auth login -h github.com

gh auth login 会问你几个问题:协议选 HTTPS,认证方式选 "Paste an authentication token"。去 GitHub Settings > Tokens 创建一个 Personal Access Token (classic),最小 scopes:reporead:orgworkflow。粘贴后确认:

代码语言:markdown
复制
✓ Configured git protocol
✓ Logged in as shuge-x

认证完成后,回到 Claude Code 输入 continue,AI 继续完成剩余的 5 个 task——创建 GitHub 仓库、推送代码。最终推送成功的输出:

代码语言:markdown
复制
To https://github.com/shuge-x/shuge-ai-toolbox.git
  * [new branch]      main -> main
  branch 'main' set up to track 'origin/main'.

建议:在跑 apply 之前就配好 gh auth。这样 tasks 里的 git 命令才能被 AI 直接执行,不用中途暂停。配置一次,后续所有项目都能用。

这两个坑都不是 OpenSpec 的问题,但确实会影响 apply 的流畅度。特别是踩坑 1,通过调整初始化顺序完全可以避免。踩坑 2 则是一次性配置,配好之后后续 change 不会再遇到。

最终项目结构

33 个 task 全部完成后,项目目录长这样:

代码语言:markdown
复制
shuge-ai-toolbox/
  ├── .claude/               # Claude Code skills + commands
  ├── openspec/
  │   ├── config.yaml
  │   ├── changes/
  │   │   └── archive/
  │   │       └── 2026-05-11-project-init/  # 归档目录(5 工件)
  │   ├── schemas/
  │   │   └── with-review/
  │   └── specs/             # 空(首次项目无主 specs)
  ├── src/
  │   ├── app/views/
  │   │   ├── Home.tsx
  │   │   └── NotFound.tsx
  │   ├── assets/
  │   ├── lib/.gitkeep
  │   ├── main.tsx
  │   ├── modules/.gitkeep
  │   ├── router/index.tsx
  │   └── tool-registry/catalog.ts
  ├── index.html
  ├── package.json
  ├── tsconfig.json
  ├── vite.config.ts
  └── eslint.config.js

几个和初始预期的差异:没有 App.tsx(入口直接用 Router 组件);tool-registry/ 下有 catalog.ts(不是 .gitkeep);有 eslint.config.js.claude/ 目录是 openspec init 自动生成的。modules/lib/.gitkeep 占位,具体实现留给后续 change。

项目结构图:最终目录可视化
项目结构图:最终目录可视化

图 4:shuge AI Toolbox 最终项目结构

5. 浏览器验证:archive 之前的最后一道检查

apply 的 task 8.1 自动跑了 npm run build,99ms 构建通过。但构建只检查语法和类型错误,页面能不能正确渲染还得打开浏览器确认。

执行 npm run dev 启动开发服务器,在浏览器打开 http://localhost:5173,确认三件事:

  • 首页显示 shuge AI Toolbox
  • 首页显示"暂无工具" ✅
  • 访问不存在的路径显示 404 提示 ✅
浏览器验证:首页截图
浏览器验证:首页截图

图 6:npm run dev 启动后浏览器访问 localhost:5173 的实际效果

三样都对了,构建(apply 自动完成)+ 浏览器(手工确认),两道检查都过了。接下来可以放心 archive。

6. 归档:archive

在 Claude Code 中执行:

代码语言:bash
复制
/opsx:archive

AI 会把 change 目录移到归档位置并输出摘要:

代码语言:markdown
复制
## Archive Complete

**Change:** project-init
**Schema:** with-review
**Archived to:** `openspec/changes/archive/2026-05-11-project-init/`
**Specs:** No delta specs

All artifacts complete. All tasks complete.

归档做了两件事:

  1. openspec/changes/project-init/ 目录移到 openspec/changes/archive/2026-05-11-project-init/
  2. 检查 delta specs——首次项目显示 "No delta specs"(没有主 specs 需要同步),这是正常的

归档之后,5 个工件还在,只是从活跃区移到了归档区。后续需要回顾的时候随时可以翻出来看。比如第 3 期做 tool-registry 的时候,如果需要回看项目初始化阶段的设计决策,直接去归档目录找就行。

7. 回顾:这期学到了什么

OpenSpec 工作流的真实体验

走完整个流程之后,几个直观感受:

Explore 确实有用。 project-init 这种看起来简单的 change,其实有 4-5 个决策点。Explore 把这些决策提前理清了,propose 阶段几乎没有意外产出。而且 Explore 是多轮交互——AI 会追问和澄清,不是一次就完事。

propose 一次生成 5 个工件,效率很高。 proposal、design、specs、review、tasks 按依赖顺序生成,不需要手动触发每一步。review 工件作为 design 和 tasks 之间的闸门,确实能发现一些粗看容易漏掉的问题(比如路由 404 的测试覆盖)。

tasks.md 的粒度实测通过。 8 个任务组、33 个子任务,路由和页面部分有完整的 TDD 步骤。AI 在 apply 阶段几乎没有发挥空间——因为 instructions 里该做的事、该写的代码都写好了。这和上期的结论一致:tasks instruction 升级之后,apply 阶段 AI 的行为从创造性地实现需求变成了机械地执行指令。对于项目质量和可控性来说,这是一件好事。

三个实操体会

初始化顺序有讲究。npx create-vite 初始化空目录,再 openspec init。反过来做会因为目录非空导致 Vite 拒绝初始化。这个小坑不踩不知道,一踩就卡住。

四步配置的投入产出比确实高。 init → 手动创建 config.yaml → fork schema → 手动添加 review 工件。后续所有 change 都复用这套配置,边际成本趋近于零。从第 1 期的 TypeScript + Express 项目迁移到本期的 React + Vite 项目,改动量只有 context 字段里的技术栈描述。

GitHub CLI 配一次受用全程。 gh auth login 配置完之后,AI 在 apply 阶段直接执行 git 命令,不需要手动切到终端操作。对于多 change 的项目,这个配置的价值会不断放大。

任务粒度实测结论

上期说"2/8 法则"——改 tasks instruction 这 20% 的投入,覆盖 80% 的质量提升。这期的 project-init 实测结论:tasks.md 的粒度确实达到了 2-5 分钟一个 step,8 组 33 个子任务,上期的核心论点在真实项目中验证通过。

当然,project-init 是个简单的 change。后续更复杂的功能 change(工具注册中心、Prompt 模板库)能不能保持这个粒度,需要到时候再看。

实测数据总结:关键指标和结论
实测数据总结:关键指标和结论

图 5:project-init 实测数据——5 工件、8 组 33 子任务、99ms 构建

8. 下一期预告

第 3 期做工具注册中心(change name: tool-registry)。这是模块化架构的核心——有了注册中心,后续每个工具就能独立注册、动态路由、按需加载。

shuge AI Toolbox 项目代码地址:https://github.com/shuge-x/shuge-ai-toolbox

如果你也想跟着做,建议先跑通两件事:

  1. 安装 OpenSpec(v1.3.1):npm install -g @fission-ai/openspec@latest
  2. 配好 GitHub CLI:按本文第 7 步操作

系列持续更新中。关注不迷路。

好啦,谢谢你观看我的文章,如果喜欢可以点赞转发给需要的朋友,我们下一期再见!敬请期待!

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • OpenSpec 项目实战(一) | 从零搭建项目骨架:OpenSpec 工作流跑通全流程实录
    • 1. 从方法论到实战
    • 2. 探索:用 Explore 澄清需求
      • project-init 也需要 Explore?
      • Explore 是多轮交互,不是一次输出
      • Explore 最终输出的决策结论
    • 3. 提议:propose 生成 5 个工件
      • 一行 slash command 启动
      • proposal.md:一张项目全景图
      • specs/:把决策变成可验证的规格
      • design.md:从做什么到怎么做
      • review.md:五维审查结论
      • tasks.md:全文最重要的一个文件
      • 人工检查:1-2 分钟的事
    • 4. 执行:apply 按任务实现
      • 启动 apply
      • 关键实现片段
      • OpenSpec 配置的实际步骤
      • 踩坑记录
      • 最终项目结构
    • 5. 浏览器验证:archive 之前的最后一道检查
    • 6. 归档:archive
    • 7. 回顾:这期学到了什么
      • OpenSpec 工作流的真实体验
      • 三个实操体会
      • 任务粒度实测结论
    • 8. 下一期预告
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档