OpenSpec 項目實戰(一) | 從零搭建項目骨架:OpenSpec 工作流跑通全流程實錄

作者:術哥無界
日期:2026年5月12日 上午8:30
來源:WeChat 原文

整理版優先睇

速讀 5 個重點 高亮

實測 OpenSpec 工作流:改 tasks instruction 嘅 20% 投入,換來 80% 嘅質量提升,AI 執行變得可控,任務粒度達到 2-5 分鐘。

整理版摘要

術哥係專注 AI 編程嘅技術實踐者,今次用 OpenSpec v1.3.1 同 React 19 + TypeScript + Vite 嘅真實項目「shuge AI Toolbox」,驗證佢之前提出嘅方法論——改 tasks instruction 呢 20% 嘅投入,可以覆蓋 80% 嘅質量提升。

文章行咗 6 步工作流Explore(多輪澄清需求)、Propose(一次產出 5 個工件)、Review(作為閘門)、Apply(按 tasks.md 執行)、驗證(瀏覽器確認)、Archive(歸檔)。實測發現:tasks.md 嘅粒度真係達到 2-5 分鐘一個 step,8 組 33 個子任務附完整代碼;Apply 階段 AI 幾乎冇發揮空間,因為指令寫得太具體,變咗機械執行。Review 工件喺 design 同 tasks 之間起閘門作用,發現路由 404 測試覆蓋嘅潛在問題。

整體結論:方法論有效,配置投入產出比高。但實際操作有兩個小坑——初始化順序要「先 npx create-vite,再 openspec init」,否則 Vite 會因為目錄非空而拒絕;另外 GitHub CLI 要預先認證,否則 Apply 會暫停。呢啲經驗對後續 change 好有價值。

  • 結論:改 tasks instruction 令 AI 從「創造性實現」變成「機械執行」,項目質量更可控。
  • 方法:2/8 法則——花 20% 精力優化 tasks.md 嘅 instruction,覆蓋 80% 嘅質量提升。
  • 差異OpenSpec 工作流多輪 Explore 澄清需求,一次產出 5 個工件,Review 作為閘門,比傳統開發更系統。
  • 啟發:tasks.md 粒度實測達 2-5 分鐘,33 個子任務附完整代碼,AI 冇解釋空間,無法夾帶私貨。
  • 可行動點:先跑 npx create-vite 再 openspec init;Apply 之前配好 gh auth,避免中途卡住。
值得記低
連結 github.com

shuge AI Toolbox 項目代碼

項目源碼,可參考初始化骨架同 OpenSpec 配置

結構示例

內容片段

內容片段 text
Explore  →  Propose  →  Review  →  Apply   →  驗證    →  Archive  ↓           ↓          ↓         ↓           ↓          ↓ 澄清       生成       人工檢查   按任務       瀏覽器     歸檔 需求       5 工件     1-2 分鐘   實現        確認       change
整理重點

方法論實戰——由紙上談兵到真實項目

上期講咗 2/8 法則、三步配置同 6 個 Phase 嘅日常工作流,結論話改 tasks instruction 呢 20% 嘅投入可以覆蓋 80% 質量提升。但方法論終歸要實戰驗證——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。完整流程對應 6 步:Explore → Propose → Review → Apply → 驗證 → Archive。

整理重點

探索同提議——多輪澄清需求,一次產出 5 件工件

Explore 階段用 /opsx:explore 啟動,AI 會多輪追問細節。今次被問咗 4 個問題,包括 模塊化設計(每個工具係獨立組件定係路由級別模塊?)、工具數據硬編碼位置、MVP 邊界同 GitHub 倉庫名。逐個回答後,AI 最終輸出清晰嘅技術選型同目錄結構決策。

Propose 階段用 /opsx:propose 一行命令,AI 自動按依賴順序生成 5 個工件:proposal.md(項目全景)、design.md(點樣做)、specs/</highlight>review.md(五維審查)、tasks.md(最重要嘅執行清單)。每個工件存到 openspec/changes/project-init/</highlight> 目錄。

Review.md 作為閘門,喺 design 同 tasks 之間插入,審查五個維度:邊界條件、回滾方案、測試覆蓋</highlight>向後兼容</highlight>、任務粒度</highlight>。今次發現路由 404 fallback 建議加測試(⚠️警告),但由於 tasks.js 未生成,暫未評估。

Tasks.md 係全文核心驗證對象。實測有 8 個任務組、33 個子任務</highlight>,每個 step 都有精確文件路徑、完整代碼同運行命令。例如路由配置組包括:寫失敗測試(測試 / 路由渲染 Home 組件)→ 寫最小實現(createBrowserRouter + RouterProvider)→ 運行測試確認通過。AI 拿到呢種 task 只能照做,冇解釋空間。

整理重點

執行同驗證——AI 機械執行,瀏覽器最終確認

Apply 階段用 /opsx:apply project-init 啟動。AI 讀取所有工件,按 tasks.md 順序逐個實現。由於每個 step 有完整代碼同命令,AI 基本係執行精確腳本。今次跑到 28/33 時暫停——原因係 AI 冇 GitHub 推送權限,需要人工協助。按提示操作後輸入 continue 繼續。

最終 AI 彙報完成,33 個 task 全部完成。關鍵實現片段包括:Home.tsx</highlight>tool-registry/catalog.ts</highlight>router/index.tsx</highlight>(用 createBrowserRouter + RouterProvider,唔係 BrowserRouter),同埋 main.tsx</highlight>(直接導入 Router 組件,冇 App.tsx)。特別留意 主頁條件渲染</highlight>——tools.length === 0 顯示「暫無工具」。

驗證分兩步:先係 Apply 階段 AI 自動執行 tsc -b && vite build</highlight>,99ms 構建通過,零 error;然後人手執行 npm run dev</highlight> 開瀏覽器確認三樣嘢:首頁顯示 shuge AI Toolbox、首頁顯示「暫無工具」、404 路由顯示頁面不存在。全部通過後,先至 Archive。

整理重點

歸檔同回顧——三個實操體會同最終結論

歸檔用 /opsx:archive</highlight> 命令,AI 將 change 目錄移到歸檔位置並輸出摘要。歸檔後 5 個工件仍在,後續需要回顧設計決策時可以隨時翻查。

三個實操體會:第一,初始化順序有講究</highlight>——應該先 npx create-vite 再 openspec init,避免 Vite 因目錄非空而拒絕;第二,四步配置嘅投入產出比好高</highlight>——init → 手動創建 config.yaml → fork schema → 手動添加 review 工件,後續所有 change 複用同一套配置,邊際成本趨近於零;第三,GitHub CLI 配一次受用全程</highlight>——gh auth login 後 AI 可以直接執行 git 命令,唔使中途暫停。

最終結論:上期嘅核心論點——2/8 法則、改 tasks instruction 覆蓋 80% 質量提升——喺真實項目中驗證通過。Tasks.md 粒度實測達到 2-5 分鐘一個 step</highlight>,8 組 33 個子任務。當然 project-init 係簡單 change,後續更複雜嘅功能(如 tool-registry)能否保持呢個粒度,需要繼續觀察。

🚩 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。

完整流程對應下面嘅流程圖:

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 邊界要劃清,唔用嘅就唔好裝。

目錄結構設計:

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 執行:

/opsx:propose

唔需要喺命令行指定 change name 同 schema——AI 會自動執行 openspec new change "project-init" 創建 change 目錄,schema 喺 .openspec.yaml 中已配置。

執行之後你會見到類似輸出:

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.md → design.md → specs/ → review.md → tasks.md。注意 design 同 specs 都只依賴 proposal,AI 可能優先做 design——實際順序同依賴圖有關,唔係固定嘅。每個工件生成完自動存到 openspec/changes/project-init/ 目錄下面。

可以隨時用 openspec status --change project-init --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: + 簡短描述:

### 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 個子任務:

## 任務清單

[ ] 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(路由配置)展示格式:

### 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 執行:

/opsx:apply project-init

AI 讀取 openspec/changes/project-init/ 下面嘅所有工件,然後按 tasks.md 入面嘅順序逐個實現。因為每個 step 都有完整代碼同命令,AI 基本上係執行一個精確嘅腳本。

apply 可能唔會一次過跑完。今次跑到 28/33 嘅時候暫停咗——AI 冇 GitHub 推送權限,需要人手協助。呢個係正常嘅,按提示操作之後輸入 continue 就行。

最終 AI 彙報完成:

## 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 自動執行嘅構建驗證:

> 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

import { getTools } from'../../tool-registry/catalog';

exportdefaultfunction 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>
            ))}
          </u
l>
        )}
      </section>
    </m
ain>
  );
}

留意幾個關鍵差異同草稿預期嘅唔同:組件名係 Home 不是 HomeView;導入了 getTools() 從 tool-registry/catalog;使用條件渲染——tools.length === 0 顯示"暫無工具",否則循環渲染。

工具註冊中心 src/tool-registry/catalog.ts

export interface ToolManifest {
  id: string;
  name: string;
  description: string;
  route: string;
  category: string;
}

const tools: ToolManifest[] = [];

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

catalog.ts 定義了 ToolManifest 接口和 getTools() 查詢函數。今期 MVP 嘅 tools 陣列係空嘅——首頁會顯示"暫無工具"。等到第 3 期做工具註冊中心時,只需要向呢個陣列加數據就得,接口同查詢函數唔使改。

路由配置 src/router/index.tsx

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 /> },
]);

exportdefaultfunction Router() {
return <RouterProvider router={router} />;
}

呢度用咗 react-router-dom 的 createBrowserRouter + RouterProvider API,唔係 react-router 的 BrowserRouter + Routes/Route。React Router v7 推薦用 data router 模式。

項目入口 src/main.tsx

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

openspec init --tools claude

輸出:

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

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、implementlater)

第 3 步:Fork Schema

openspec schema fork spec-driven with-review

輸出:

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 定義,設置依賴鏈:

- id:review
description:設計審查
requires:[design,proposal,specs]
generates:review.md
instruction: |
    對 design 和 specs 進行五維審查:邊界條件、回滾方案、測試覆蓋、
    向後兼容、任務粒度。每個維度給出 ✅ 通過 或 ⚠️ 警告 + 原因。

然後更新 tasks 嘅依賴,加上 review:

- 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 要直接執行 git 和 gh 命令,前提係你本地已經裝好 GitHub CLI 並完成認證。配置步驟:

# 安裝
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。貼上之後確認:

✓ Configured git protocol
✓ Logged in as shuge-x

認證完成後,返去 Claude Code 輸入 continue,AI 繼續完成剩低嘅 5 個 task——創建 GitHub 倉庫、推送代碼。最終推送成功嘅輸出:

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 全部完成後,項目目錄係咁樣:

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 執行:

/opsx:archive

AI 會將 change 目錄移到歸檔位置並輸出摘要:

## 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 步操作

系列持續更新中。關注唔迷路。

好啦,多謝你睇我嘅文章,如果鍾意可以點讚轉發俾需要嘅朋友,我哋下一期再見!敬請期待!

掃碼關注,獲取更多 AI 工具嘅實戰經驗同最佳實踐。唔好錯過每一篇乾貨!

圖片




🚩 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。

完整流程對應下面的流程圖:

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 邊界要劃清,不用的就別裝。

目錄結構設計:

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 中執行:

/opsx:propose

不需要在命令行指定 change name 和 schema——AI 會自動執行 openspec new change "project-init" 創建 change 目錄,schema 在 .openspec.yaml 中已配置。

執行後你會看到類似輸出:

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.md → design.md → specs/ → review.md → tasks.md。注意 design 和 specs 都只依賴 proposal,AI 可能先做 design——實際順序和依賴圖有關,不是固定的。每個工件生成完自動存到 openspec/changes/project-init/ 目錄下。

可以隨時用 openspec status --change project-init --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: + 簡短描述:

### 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 個子任務:

## 任務清單

[ ] 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(路由配置)展示格式:

### 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 中執行:

/opsx:apply project-init

AI 讀取 openspec/changes/project-init/ 下的所有工件,然後按 tasks.md 裏的順序逐個實現。因為每個 step 都有完整代碼和命令,AI 基本是在執行一個精確的腳本。

apply 可能不會一次跑完。這次跑到 28/33 的時候暫停了——AI 沒有 GitHub 推送權限,需要人工協助。這是正常的,按提示操作後輸入 continue 就行。

最終 AI 彙報完成:

## 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 自動執行的構建驗證:

> 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

import { getTools } from'../../tool-registry/catalog';

exportdefaultfunction 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>
            ))}
          </u
l>
        )}
      </section>
    </m
ain>
  );
}

注意幾個關鍵差異和草稿預期的不同:組件名是 Home 不是 HomeView;導入了 getTools() 從 tool-registry/catalog;使用條件渲染——tools.length === 0 顯示"暫無工具",否則循環渲染。

工具註冊中心 src/tool-registry/catalog.ts

export interface ToolManifest {
  id: string;
  name: string;
  description: string;
  route: string;
  category: string;
}

const tools: ToolManifest[] = [];

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

catalog.ts 定義了 ToolManifest 接口和 getTools() 查詢函數。這期 MVP 的 tools 數組是空的——首頁會顯示"暫無工具"。等到第 3 期做工具註冊中心時,只需要往這個數組裏加數據就行,接口和查詢函數不用改。

路由配置 src/router/index.tsx

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 /> },
]);

exportdefaultfunction Router() {
return <RouterProvider router={router} />;
}

這裏用的是 react-router-dom 的 createBrowserRouter + RouterProvider API,不是 react-router 的 BrowserRouter + Routes/Route。React Router v7 推薦用 data router 模式。

項目入口 src/main.tsx

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

openspec init --tools claude

輸出:

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

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、implementlater)

第 3 步:Fork Schema

openspec schema fork spec-driven with-review

輸出:

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 定義,設置依賴鏈:

- id:review
description:設計審查
requires:[design,proposal,specs]
generates:review.md
instruction: |
    對 design 和 specs 進行五維審查:邊界條件、回滾方案、測試覆蓋、
    向後兼容、任務粒度。每個維度給出 ✅ 通過 或 ⚠️ 警告 + 原因。

然後更新 tasks 的依賴,加上 review:

- 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 要直接執行 git 和 gh 命令,前提是你本地已經裝好 GitHub CLI 並完成認證。配置步驟:

# 安裝
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。粘貼後確認:

✓ Configured git protocol
✓ Logged in as shuge-x

認證完成後,回到 Claude Code 輸入 continue,AI 繼續完成剩餘的 5 個 task——創建 GitHub 倉庫、推送代碼。最終推送成功的輸出:

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 全部完成後,項目目錄長這樣:

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 中執行:

/opsx:archive

AI 會把 change 目錄移到歸檔位置並輸出摘要:

## 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 步操作

系列持續更新中。關注不迷路。

好啦,謝謝你觀看我的文章,如果喜歡可以點贊轉發給需要的朋友,我們下一期再見!敬請期待!

掃碼關注,獲取更多 AI 工具的實戰經驗和最佳實踐。不錯過每一篇乾貨!

圖片