OpenSpec 項目實戰(一) | 從零搭建項目骨架:OpenSpec 工作流跑通全流程實錄
整理版優先睇
實測 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,避免中途卡住。
shuge AI Toolbox 項目代碼
項目源碼,可參考初始化骨架同 OpenSpec 配置
內容片段
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。無界探索,有術而行。

圖 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 嘅粒度到底有冇達到上期講嘅標準。

圖 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 最終輸出嘅決策結論
技術棧確認:
揀 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 就唔會生成。
審查結論:
重點睇任務粒度維度:⚠️ 警告(待複審)。呢個並唔係話任務粒度有問題——而係 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 跑完之後,做咗兩件事:
打開 review.md,瞄一眼任務粒度維度嘅狀態。⚠️ 警告,等 tasks 生成後複審。冇問題。 打開 tasks.md,快速檢查有冇 TBD、TODO、implement later 呢類佔位符。冇。
兩個文件加埋睇咗唔夠 2 分鐘。如果發現問題,直接編輯 Markdown 改咗就得,唔使重跑 propose。呢個就係第 1 期講嘅第三層防線——收尾確認,1-2 分鐘,做快唔做重。
到呢度,5 個工件全部生成同檢查完畢。下一步係 apply。

圖 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>
))}
</ul>
)}
</section>
</main>
);
}
留意幾個關鍵差異同草稿預期嘅唔同:組件名係 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.yaml,with-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:repo、read:org、workflow。貼上之後確認:
✓ 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.
歸檔做咗兩件事:
把 openspec/changes/project-init/目錄移到openspec/changes/archive/2026-05-11-project-init/檢查 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
如果你都想跟住做,建議先搞掂兩件事:
安裝 OpenSpec(v1.3.1): npm install -g @fission-ai/openspec@latest配好 GitHub CLI:按本文第 7 步操作
系列持續更新中。關注唔迷路。
好啦,多謝你睇我嘅文章,如果鍾意可以點讚轉發俾需要嘅朋友,我哋下一期再見!敬請期待!
掃碼關注,獲取更多 AI 工具嘅實戰經驗同最佳實踐。唔好錯過每一篇乾貨!

🚩 2026 年「術哥無界」系列實戰文檔 X 篇原創計劃 第 109 篇,OpenSpec 最佳實戰「2026」系列第 1
大家好,歡迎來到 術哥無界 | ShugeX | 運維有術。
我是術哥,一名專注於 AI 編程、AI 智能體、Agent Skills、MCP、雲原生、AIOps、Milvus 向量數據庫的技術實踐者與開源佈道者!
Talk is cheap, let's explore。無界探索,有術而行。

圖 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 的粒度到底有沒有達到上期說的標準。

圖 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 最終輸出的決策結論
技術棧確認:
選 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 就不會生成。
審查結論:
重點看任務粒度維度:⚠️ 警告(待複審)。這並不是說任務粒度有問題——而是 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 跑完之後,做了兩件事:
打開 review.md,掃一眼任務粒度維度的狀態。⚠️ 警告,待 tasks 生成後複審。沒問題。 打開 tasks.md,快速檢查有沒有 TBD、TODO、implement later 這類佔位符。沒有。
兩個文件加起來看了不到 2 分鐘。如果發現問題,直接編輯 Markdown 改掉就行,不用重跑 propose。這就是第 1 期說的第三層防線——收尾確認,1-2 分鐘,做快不做重。
到這裏,5 個工件全部生成並檢查完畢。下一步是 apply。

圖 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>
))}
</ul>
)}
</section>
</main>
);
}
注意幾個關鍵差異和草稿預期的不同:組件名是 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.yaml,with-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:repo、read:org、workflow。粘貼後確認:
✓ 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.
歸檔做了兩件事:
把 openspec/changes/project-init/目錄移到openspec/changes/archive/2026-05-11-project-init/檢查 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
如果你也想跟着做,建議先跑通兩件事:
安裝 OpenSpec(v1.3.1): npm install -g @fission-ai/openspec@latest配好 GitHub CLI:按本文第 7 步操作
系列持續更新中。關注不迷路。
好啦,謝謝你觀看我的文章,如果喜歡可以點贊轉發給需要的朋友,我們下一期再見!敬請期待!
掃碼關注,獲取更多 AI 工具的實戰經驗和最佳實踐。不錯過每一篇乾貨!
