OpenSpec 項目實戰(五)|UI 視覺打磨 + 改 template 讓 AI 寫出規範任務

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

整理版優先睇

速讀 5 個重點 高亮

改 template 搞掂 AI 輸出格式,順便升級 UI 視覺

整理版摘要

呢篇文章係術哥嘅 OpenSpec 項目實戰系列第五期。術哥係專注 AI 編程同開源技術嘅實踐者,今期主要做兩件事:UI 視覺升級同埋改 template 令 AI 寫出規範任務。

前四期 tasks.md 格式一直唔啱,明明 instruction 要求用 ### 任務 N 格式,AI 每次都出 ## 1.。術哥研究源碼後發現,根因係 template 嘅優先級高過 instruction。LLM 會跟 template 嘅格式走,而唔係 instruction 嘅文字描述。所以佢直接改咗 template,將標題從 ## 1. 改做 ### 任務 1:,加返涉及文件列表同 TDD 五步結構。

今期驗證成功,AI 生成嘅 tasks.md 格式終於變咗。同時完成 UI 視覺升級:品牌色由 Tailwind 默認藍轉做藍紫,引入 Lucide 圖標,加咗 hover 動效同 stagger 入場動畫,整體由「腳手架」變成有品牌感嘅產品。術哥總結:template 管格式,instruction 管內容,兩者要對齊。呢個發現唔單止適用於 OpenSpec,對任何 prompt + template 模式嘅工具都有啟發。

  • 結論:改 template 比改 instruction 更有效解決 AI 輸出格式問題,template 嘅格式暗示更強。
  • 方法:直接修改 templates/tasks.md,將標題從 ## 1. 改做 ### 任務 N:,加入涉及文件列表同 TDD 五步結構。
  • 差異:視覺類變更(如 UI 打磨)難以嚴格執行 TDD 五步,更接近回歸測試模式,顆粒度取決於變更類型。
  • 啟發:喺 prompt+template 模式下,模板嘅視覺暗示對 LLM 影響更大,設計配置時 template 同 instruction 要對齊。
  • 可行動點:如果你用 OpenSpec 發現改 instruction 冇用,檢查 template 文件並直接修改。
整理重點

前四期 tasks.md 格式問題

術哥發現前四期 tasks.md 嘅格式全部都用 ## 1. 開頭,而唔係 instruction 要求嘅 ### 任務 N:。即使 instruction 寫明「必須嚴格遵守」,AI 都冇一次遵守。

根因係 template 嘅優先級高過 instruction:LLM 會將 template 當作具體格式示例,而 instruction 只係補充說明。

舊 template 用 ## 1. 格式,AI 就跟住出 ## 1.。呢個唔係偶然,而係系統性問題。

4 期文章、4 個不同 change、幾十個任務,冇一個出 ### 任務 N 格式。

LLM 面對 template 同 instruction 時,會先睇 template 嘅格式示例,然後先睇 instruction 嘅文字描述。

整理重點

改 template 解決格式問題

術哥直接修改 openspec/schemas/with-review/templates/tasks.md,將標題從 ## 1. 改做 ### 任務 1:,加上「涉及文件」列表,每步跟 TDD 五步結構。

改造後嘅 template 結構 markdown
### 任務 1:<!-- Task Group Name -->
**涉及文件:**
- 新建/修改:exact/path/to/file
- 測試:tests/exact/path/to/test
- [ ] 1.1 **寫失敗測試**
```typescript
// test code here
```
- [ ] 1.2 **運行測試——確認失敗**
命令:`npx vitest run tests/path/test.ts`
預期:FAIL
- [ ] 1.3 **寫最小實現**
```typescript
// implementation code here
```
- [ ] 1.4 **運行測試——確認通過**
命令:`npx vitest run tests/path/test.ts`
預期:PASS
- [ ] 1.5 **提交**
```bash
git add path/to/files
git commit -m "feat: description"
```

今期 ui-visual-polish 係第一次驗證。AI 生成嘅任務開頭變咗「### 任務 1:安裝 lucide-react + 重建 tokens.css 配色」,後續仲有涉及文件同代碼塊,格式完全正確。

改 template 確實有效,格式問題一次解決。

新 template 令 AI 自然輸出涉及文件列表同代碼塊,歷史首次。

對比改造前嘅 ## 1. 格式,新 template 令輸出脱胎換骨。

整理重點

UI 視覺升級同 Apply 過程

視覺升級方面,品牌色由 Tailwind 默認藍轉做藍紫(#8B5CF6),用 Lucide 圖標系統,分類各有專屬圖標,BadgeBeaker 同 ClipboardList。

  • 卡片 hover 加 scale 1.02 同 shadow 效果,動畫 200ms ease-out
  • stagger 入場動畫用 fadeInUp,400ms cubic-bezier,100ms 間隔
  • Tab 滑動指示器用 JS left/width,250ms cubic-bezier
  • Header 背景用中性色到 primary-50 嘅微漸變,加 Wand2 圖標

Apply 過程有33步,出現三個小插曲:Flask 圖標唔存在,AI 自動改用 Beaker;index.css 意外被覆蓋,AI 自己補返;NotFound.tsx 無需修改,因為用 CSS 變量自動跟隨。

AI 嘅自適應同自我修復能力令執行過程更順暢,係純腳本自動化做唔到嘅。

CSS 變量體系令換色變成改一行值嘅事,之前嘅投資回報顯現。

Badge 從純文字變成圖標+文字,更加專業。

整理重點

實驗結論同啟發

今期最重要嘅發現係:template 管格式,instruction 管內容,兩者要對齊。改 template 係解決格式問題嘅正確手段,而改 instruction 隻影響內容質量。

呢個結論唔單止適用於 OpenSpec,對任何 prompt+template 模式嘅 AI 工具都有啟發。

改 instruction 佔 20% 投入獲 80% 質量提升,但那 80% 嘅質量提升裏可能有結構性缺陷。

另外,視覺類變更難以嚴格執行 TDD 五步,實際更接近回歸測試模式。呢個係正常現象,唔需要強求。

🚩 2026 年「術哥無界」系列實戰文檔 X 篇原創計劃 第 115 篇,OpenSpec 項目實戰「2026」系列第 5 篇

大家好,歡迎嚟到 術哥無界 | ShugeX | 運維有術

我是術哥,一個專注於 AI 編程、AI 智能體、Agent Skills、MCP、雲原生、AIOps、Milvus 向量數據庫嘅技術實踐者同開源佈道者

Talk is cheap, let's explore。無界探索,有術而行。

封面圖
封面圖

封面:UI 視覺打磨 + 改 template 令 AI 寫出規範任務

說明:本文內容係根據 OpenSpec(Fission-AI/OpenSpec)v1.3.1 同 React 19 + TypeScript + Tailwind CSS v4 嘅實際操作記錄整理出嚟嘅。文入面嘅配置模板同參數建議只係畀你參考,實際效果請以你嘅業務數據同環境測試結果為準。如果有實際使用經驗,歡迎喺評論區分享交流。

1. 視覺要升級,但更緊要嘅係一個實驗

第 4 期整咗佈局骨架。首頁有咗 Tab 分類導航,5 個工具、4 個分類,撳 Tab 切換分類,唔使再喺長列表裏面碌嚟碌去。

但係頁面一打開——灰白一片。品牌色係 Tailwind 默認藍(#3B82F6),冇圖標,卡片同導航樣式好單調,冇動效。好聽啲叫「簡潔」,講直白啲就係「未做完」。

今期要做兩件事。

第一件:視覺層面真正嘅升級。根據第 3 期整好嘅 CSS 變量體系同第 4 期嘅佈局骨架,將配色、組件樣式、圖標、動效加上去,令頁面由「腳手架」變成「產品」。change name: ui-visual-polish

第二件更重要嘅係,亦係今期文章嘅重點。前 4 期嘅 tasks.md 格式一直有問題——schema instruction 裏面明明要求用 ### 任務 N:[名稱] + 涉及文件 + TDD 五步結構,但 AI 每次生成嘅都係 ## 1. 任務名稱 + - [ ] 1.1 呢種格式。改咗好幾次 instruction,冇用。

後來睇咗 OpenSpec 源碼,揾到根本原因:template 嘅優先級高過 instruction。舊 template 用 ## 1. 格式,LLM 就跟住 template 行。今期將 template 改咗,今日係第一次驗證效果。

完整流程唔變:

工作流總覽:5 步從探索到歸檔
工作流總覽:5 步由探索到歸檔

2. 點解前 4 期嘅 tasks.md 格式都唔啱

先睇問題。第 1 期到第 4 期嘅 tasks.md 開頭係咁嘅樣。

第 1 期(project-init)

## 1. 項目腳手架初始化

[x] 1.1 使用 Vite 初始化 React + TypeScript 項目
  命令:`npx create-vite@latest . --template react-ts --yes`
  預期:項目文件生成

第 2 期(tool-registry)

## 1. 更新 catalog.ts(添加 stage 字段和初始工具數據)

**涉及文件:**
修改:`src/tool-registry/catalog.ts`

[x] **1.1:更新 ToolManifest 接口**

第 3 期(ui-redesign)

## 1. 設計系統基礎

[x] 1.1 創建 design-tokens.css 文件

第 4 期(layout-restructure)

## 1. Tab 導航組件測試

[ ] 1.1 編寫 Tab 導航組件測試

見到未?全部都係 ## 1. + - [x] 1.1 格式。4 期文章、4 個唔同嘅 change、幾十個任務,冇一次出現 ### 任務 N 嘅格式。

再嚟睇 instruction 裏面寫咗啲乜。逐字引用 openspec/schemas/with-review/schema.yaml 入面 tasks 嘅 instruction 部分(截取關鍵段落):

- id:tasks
generates:tasks.md
description:Implementationchecklistwithtrackabletasks
template:tasks.md
instruction:|
    創建細粒度的實現計劃。每個任務的工作量應在 2-5 分鐘之間。

    ## 任務格式(必須嚴格遵守)

    每個任務必須遵循以下格式:

    ### 任務 N:[組件名稱]

    **涉及文件:**
    -新建/修改:exact/path/to/file
    -測試:tests/exact/path/to/test

    -[]**第1步:寫失敗測試**
    -[]**第2步:運行測試——確認失敗**
    -[]**第3步:寫最小實現**
    -[]**第4步:運行測試——確認通過**
    -[]**第5步:提交**

    ## 禁止事項(出現即視為計劃不合格)
    -「TBD」「TODO」「implementlater」「fillindetails」

instruction 裏面寫得清清楚楚:### 任務 N:[組件名稱],涉及文件列表,TDD 五步。甚至用咗「必須嚴格遵守」呢種措辭。

但 AI 一次都冇遵守。

第 2 期好少少,出現咗「涉及文件」呢一行,但標題仲係 ## 1.,步驟仲係 - [x] 1.1。第 3 期同第 4 期連涉及文件都冇咗。

呢個唔係偶然。4 期都係同一個模式,說明唔係某次生成時嘅隨機偏差,而係有系統性嘅原因。

根本原因分析:template 嘅優先級高過 instruction

OpenSpec 生成工件嗰陣,同時讀取兩個輸入:template(模板文件,喺 schemas/with-review/templates/ 目錄下)同 instruction(指令文本,喺 schema.yaml 的 instruction 字段裏面)。

LLM 面對呢兩個輸入嗰陣嘅行為模式係:template 提供具體嘅格式示例,instruction 提供文字描述。當兩者格式衝突嗰陣,LLM 傾向跟 template 行。

呢個判斷係嚟自對 OpenSpec 源碼嘅調研。生成工件嗰陣,template 嘅內容被當做「參考格式」先展示畀 LLM,instruction 作為「補充說明」跟喺後面。順序上嘅差異導致 template 嘅格式暗示更強——LLM 會將 template 當作「你應該係咁樣」嘅範本,將 instruction 當作「內容上注意呢啲」嘅建議。

舊 template 嘅格式係咁嘅:

## 1. <!-- Task Group Name -->

[ ] 1.1 <!-- Step description -->
[ ] 1.2 <!-- Step description -->

AI 見到呢個模板,個腦入面形成咗一個框架:「標題用 ## 1.,步驟用 - [ ] 1.1」。然後 instruction 話「用 ### 任務 N」,但佢已經被 template 嘅格式錨定咗,改唔到。

呢個就好似你叫一個人跟住模板寫公文,模板係表格格式,你喺旁邊話「請用列表格式」,佢大機會都係跟住模板寫表格。唔係因為唔聽,而係模板嘅視覺暗示太強嘞。

改造方案:直接改 template

既然 instruction 管唔到格式,咁就改 template。逐字引用改造後嘅 openspec/schemas/with-review/templates/tasks.md

### 任務 1:<!-- Task Group Name -->

**涉及文件:**
新建/修改:exact/path/to/file
測試:tests/exact/path/to/test

[ ] 1.1 **寫失敗測試**
```typescript
// test code here
```


[ ] 1.2 **運行測試——確認失敗**
命令:`npx vitest run tests/path/test.ts`
預期:FAIL — <!-- expected error -->

[ ] 1.3 **寫最小實現**
```typescript
// implementation code here
```


[ ] 1.4 **運行測試——確認通過**
命令:`npx vitest run tests/path/test.ts`
預期:PASS

[ ] 1.5 **提交**
```bash
git add path/to/files
git commit -m "feat: description"
```


### 任務 2:<!-- Task Group Name -->

**涉及文件:**
新建/修改:exact/path/to/file
測試:tests/exact/path/to/test

[ ] 2.1 <!-- Continue with the same pattern -->

改動點好明確:

維度
舊 template
新 template
標題格式
## 1.### 任務 1:
涉及文件
**涉及文件:**
 + 文件路徑列表
步驟結構
- [ ] 1.1 描述
TDD 五步(寫失敗測試 → 確認失敗 → 寫實現 → 確認通過 → 提交)
代碼佔位
每步都有代碼塊或命令行
第二個任務
同上
重複模板結構

從 ## 1. 變成 ### 任務 1:,睇落只係標記層級同命名方式嘅變化,但對 LLM 嚟講,呢個格式改變會產生唔同嘅輸出模式。加咗「涉及文件」列表,AI 就會習慣性咁列出每個任務涉及嘅文件。加咗 TDD 五步結構,AI 就會跟呢個節奏組織每個任務。

本期 ui-visual-polish 今次 change 係改造 template 之後嘅第一次驗證。

如果 AI 跟新 template 行,tasks.md 嘅格式就會變成 ### 任務 N + 涉及文件 + TDD 五步。如果仲係 ## 1. 格式,說明問題唔止喺 template,需要再進一步排查。

當前項目狀態

順便講下今期開始之前嘅項目狀態。

逐字引用 src/theme/tokens.css(第 3 期產出,77 行):

:root {
/* 品牌色板 - 冷色系 */
--color-primary-500#3B82F6;
--color-primary-600#2563EB;
--color-primary-700#1D4ED8;

/* 強調色 - 琥珀色 */
--color-accent-500#F59E0B;
--color-accent-600#D97706;

/* 中性色 - 冷灰 */
--color-neutral-50#F8FAFC;
--color-neutral-200#E2E8F0;
--color-neutral-500#64748B;
--color-neutral-900#0F172A;
/* ... 字體、間距、圓角等 */
}

CSS 變量體繫有咗,但 Home 頁面嘅 ToolCard 組件大量用 inline style,冇充分重用呢啲變量。TopNav 都好基本——一個 logo + 一個「首頁」連結。配色係 Tailwind 默認藍,冇品牌辨識度。

呢啲就係今期視覺升級嘅起點。

3. Explore → Propose:由需求釐清到 5 個工件一步到位

今期有個重要發現:Explore 同 Propose 唔係兩個獨立步驟,而係連續流程。執行 /opsx:explore,多輪對話確認方向之後,AI 輸出 Design Doc,確認之後直接自動創建 change 同生成全部 5 個工件——中間冇單獨嘅 /opsx:propose 步驟。

以下係完整互動過程。

多輪對話:確認視覺升級方向

執行 /opsx:explore,AI 先問咗一句:

AI:What's on your mind? An idea, a problem, a comparison — or just wander?

輸入今期需求:

用戶:本期做一個 ui-visual-polish 變更。當前頁面的 CSS 變量體系已搭好但未充分使用,配色是默認藍沒有辨識度,沒有圖標系統,卡片和導航樣式單調。需要全面升級視覺層——配色、圖標、動效,讓頁面從腳手架變成產品。

AI 睇咗一遍源碼,做咗一輪 Gap 分析:

AI:{讀源碼,做 Gap 分析}

現狀梳理:
Primary (藍):    50→700   ← 幾乎未使用
Accent (琥珀):   50→600   ← Beta/Planned badge,active tab border
Neutral (冷灰):  50→900   ← 大量使用
Semantic:        success/warning/error  ← 未使用

Gap 分析:
| 維度 | 現狀 | 問題 |
|------|------|------|
| 配色 | 變量定義好了,但只用 neutral | 藍得很默認,缺乏辨識度 |
| 圖標 | 僅有一個 ⏳ emoji | 分類/Tab/卡片均無圖標 |
| 動效 | 僅 transition-colors,hover:shadow-md | 沒有微交互 |
| 卡片 | 純 flat border + opacity | 沒有層次感 |
| 導航 | border-b-2 amber 作為 active indicator | 與品牌藍不一致 |

幾個思考方向:1. 配色策略 2. 圖標系統 3. 動效深度 4. 視覺錨點。你傾向於先攻哪個方向?或者想先聊聊整體的設計語言定位再動手?

Gap 分析好準確——變量體系整好咗但幾乎冇用上,中性灰堆滿咗成個頁面。一口氣畀咗 4 個方向都定咗:

用戶:1. 配色:換掉默認藍,選一個有辨識度的品牌色。primary 做交互色,accent 保持琥珀做功能區分。具體的色值你來定,不要用 Tailwind 默認藍。2. 圖標:用 Lucide,每個 category 配一個 icon,badge 用小圖標輔助(Beta 用 🧪 / Planned 用 📋)。3. 動效:做到中等——卡片 hover scale + shadow + stagger 入場動畫,tab 切換加滑動指示器。不需要 page transition。4. Header:保持純文字,但加一個簡潔的 icon 或 logo mark,背景用微漸變提升層次。整體方向:乾淨、專業、有品牌感,不要花哨。參考 Linear 或 Vercel 的設計風格。

AI 又追問咗 4 個關鍵問題:

AI:方向清晰了。再摸幾個關鍵問題:

1. 
**品牌色定位** — 推薦藍紫(blue-violet),比純藍更有辨識度,比純紫更穩。你接受嗎?
2. **Lucide React 安裝了嗎?**
3. **背景漸變** — 淺色 header + subtle gradient 還是深色 header?
4. **動效節奏** — 快速連續(30-50ms)還是柔和錯落(80-120ms)?
用戶:1. 藍紫方向接受,你來定具體色值。2. Lucide 沒裝,本期 install 進去。3. 淺色 header + subtle gradient,保持整體 light theme 基調。4. 柔和錯落 80-120ms,偏產品感。

跟住係圖標分配同 Badge 方案:

AI:好,我來分配圖標,附上理由:
文本處理 → Type ← 文字輸入/編輯感
數據轉換 → RefreshCw ← 轉換/循環感
開發工具 → Code2 ← 開發者身份明確
內容創作 → Feather ← 創作、手寫感
Badge: Beta → Flask, Planned → ClipboardList。確認這 6 個 icon 分配?
用戶:確認
AI:最後確認——Badge 的 emoji 方案:純圖標 vs 圖標+emoji 混搭?
用戶:純圖標

到呢度所有細節都定咗。AI 輸出完整 Design Doc。

Design Doc + 自動生成 5 個工件

AI 輸出嘅 Design Doc 關鍵內容:

AI:{輸出完整 Design Doc}

## UI Visual Polish — Design Doc

### 1. 配色體系
品牌色:藍紫 (Blue-Violet)
Primary (藍紫)              Accent (琥珀)              Semantic
─────────────────           ─────────────────           ────────
50: #F5F3FF   極淺紫          50: #FFFBEB               success: #10B981
100: #EDE9FE                 100: #FEF3C7              warning: #F59E0B
200: #DDD6FE                 200: #FDE68A              error: #EF4444
300: #C4B5FD                 300: #FCD34D
400: #A78BFA                 400: #FBBF24
500: #8B5CF6   ← 品牌主色     500: #F59E0B
600: #7C3AED   ← 深色交互     600: #D97706
700: #6D28D9   ← 強調/hover
語義映射:交互色 primary-500, Beta badge accent-500, Active tab indicator primary-500

### 2. 圖標系統
Category Icons: 文本處理→Type, 數據轉換→RefreshCw, 開發工具→Code2, 內容創作→Feather
Badge Icons: Beta→Flask(替代🧪), Planned→ClipboardList(替代📋)

### 3. 動效
卡片 Hover: scale 1.02, shadow rgba(139,92,246,0.15), 200ms ease-out
Stagger: fadeInUp 400ms, cubic-bezier(0.22,1,0.36,1), 100ms stagger
Tab 指示器: JS left/width, 250ms cubic-bezier(0.4,0,0.2,1)

### 4. Header
background: linear-gradient(135deg, neutral-50 → primary-50)
標題左側: Wand2 icon + "shuge AI Toolbox"

### 5. 修改文件清單
tokens.css, index.css, Home.tsx, NotFound.tsx, PlaceholderPage.tsx, package.json

Design Doc 確認嗎?可以的話我們開 change 了。

確認之後,AI 直接自動執行 openspec new change "ui-visual-polish" 同生成全部 5 個工件,冇等用戶再去執行乜嘢 propose 命令:

用戶:確認
AI:{自動執行 openspec new change "ui-visual-polish",生成 5 個工件}

Change `ui-visual-polish` 創建完成。所有 artifacts 位於 `openspec/changes/ui-visual-polish/`
| Artifact | 說明 |
|----------|------|
| proposal.md | 變更動機 + 影響範圍 |
| design.md | 藍紫色值決策、Lucide 選型、Stagger/Tab 指示器實現方案對比 |
| specs/visual-identity/spec.md | 4 個 capability 的場景定義(配色/圖標/動效/Header) |
| review.md | 5 維度審查,重點關注任務粒度和測試覆蓋 |
| tasks.md | 9 個任務組,涵蓋安裝依賴 → 配色 → 4 類圖標 → stagger → tab 指示器 → header → NotFound → Placeholder → 提交 |

下一步:運行 `/opsx:apply` 開始實現。

template 改造效果:格式變咗

呢個係今期最有價值嘅觀察點。直接睇 tasks.md 實際生成嘅第一個任務組:

### 任務 1:安裝 lucide-react + 重建 tokens.css 配色

**涉及文件:**
修改:`package.json`
修改:`src/theme/tokens.css`

[ ] 1.1 **安裝 lucide-react**

```bash
npm install lucide-react
```


[ ] 1.2 **更新 package.json 並驗證 lockfile**

```bash
cat package.json | grep lucide-react
```

預期:`"lucide-react": "^0.468.0"`(或當前最新版本)

[ ] 1.3 **重建 tokens.css 的 primary 色板為藍紫系**

```css
  /* 品牌色板 - 藍紫 (Blue-Violet) */
  --color-primary-50: #F5F3FF;
  --color-primary-100: #EDE9FE;
  --color-primary-200: #DDD6FE;
  --color-primary-300: #C4B5FD;
  --color-primary-400: #A78BFA;
  --color-primary-500: #8B5CF6;
  --color-primary-600: #7C3AED;
  --color-primary-700: #6D28D9;
```


[ ] 1.4 **運行測試——確認 CSS 變量正確**

```bash
npx vitest run
```

預期:PASS

對比改造前:

## 1. 任務名稱

[x] 1.1 步驟描述
[x] 1.2 步驟描述

結論好清晰:標題從 ## 1. 變成了 ### 任務 1:,涉及文件列表成咗標配,每個步驟都有代碼塊。 改 template 確實生效咗。

9 個任務組入面 8 個都有涉及文件列表,代碼塊總共 34 個,係前 4 期嘅歷史高點。

不過都有一個未完全到位嘅地方:TDD 五步(寫失敗測試→確認失敗→寫實現→確認通過→提交)冇嚴格跟足。實際更接近「改 code → 運行測試確認冇壞」嘅迴歸測試模式。review.md 都指出咗呢個問題,標咗 ⚠️ 警告:視覺類任務好難按 TDD 節奏嚴格拆分。呢個觀察好重要,後面回顧章節會再講。

4. Apply:33 步全部執行 + 三個小插曲

執行 /opsx:apply,AI 開始逐個任務執行。

AI:Using change: **ui-visual-polish** (schema: with-review). Reading context files...

AI:Implementing: ui-visual-polish (schema: with-review). Progress: 0/33 tasks complete. Working on Task 1/9: 安裝 lucide-react + 重建 tokens.css 配色

33 個步驟,9 個任務組,AI 一路落去。

三個小插曲

執行過程入面出現咗三個幾得意嘅問題,AI 都自己發現同修復咗。

插曲 1:Flask 圖標唔存在,改用 Beaker

Explore 階段 Design Doc 規劃咗 Beta badge 用 Flask 圖標。但 apply 執行嗰陣,AI 發現 lucide-react 裏面根本冇 Flask 呢個組件,自動改用咗 Beaker

規劃時揀咗 Flask,實際發現 lucide-react 冇 Flask,改用咗 Beaker——呢種規劃→執行嘅偏差喺真實項目入面好常見。AI 編程助手喺執行嗰陣嘅呢種自適應能力,係佢比純腳本自動化更有價值嘅地方。

插曲 2:index.css 內容被意外覆蓋

AI:我發現一個問題——我把 index.css 的原有內容(imports)覆蓋了。需要補回來。

AI 喺編輯 index.css 嗰陣唔小心覆蓋咗原有 imports 內容,隨即自己發現同補返。呢種自我修復係 AI 編程助手嘅常見行為——佢會犯錯,但都會監控自己嘅輸出同喺發現問題嗰陣立即修正。

插曲 3:NotFound.tsx 唔需要改

AI:NotFound.tsx already uses `var(--color-primary-500)` — no changes needed.

tasks.md 任務 7 規劃咗 NotFound 配色更新。但 apply 嗰陣 AI 發現 NotFound.tsx 已經用咗 var(--color-primary-500) CSS 變量——tokens.css 嘅 primary 色值由 #3B82F6 改為 #8B5CF6 之後,404 頁面嘅顏色自動跟住變,唔需要改 code。

呢個就係用 CSS 變量嘅好處:一處修改,全局生效。

另外仲有一個 bug 修復:AI 用咗 React.createElement 但冇導入 React,測試失敗之後快速定位同添加咗 import React

Apply 完成報告

AI:## Implementation Complete

**Change:**`ui-visual-polish`
**Schema:**`with-review`
**Progress:** 33/33 tasks complete ✓

### Completed This Session
Task 1: npm install lucide-react + tokens.css primary 色板重建為藍紫系
Task 2: index.css 添加 fadeInUp keyframes + .animate-fadeInUp class
Task 3: Home.tsx 導入 Lucide 圖標 + categoryIcon 映射 + Badge Lucide 圖標 + Category 圖標
Task 4: Home.tsx stagger 入場動畫 + hover scale/shadow 效果
Task 5: Home.tsx Tab 滑動指示器 (JS ref + CSS transition)
Task 6: Home.tsx Header Wand2 icon + 135deg 微漸變
Task 7: NotFound.tsx 配色確認(已是 primary-500)
Task 8: PlaceholderPage.tsx ⏳ → Clock icon
Task 9: 全量測試 PASS + commit

### 發現並解決的問題
Flask 在 lucide-react 中不存在 → 改用 Beaker
Tab 指示器高亮從 className border-b-2 改為 style.borderColor(無侵入)
Active Tab 樣式用 inline style 替代 class 注入(避免 CSS 類名測試失效)

### Bug 修復
React.createElement 未導入 React → 添加 import React

所有 30 個測試全部通過。變更已提交。可以 `/opsx:archive` 歸檔。

關鍵文件變更摘要

唔貼咁多 code,講幾個關鍵變化。

tokens.css:primary 色板由默認藍換成藍紫。

/* Before */
--color-primary-500#3B82F6;
--color-primary-600#2563EB;
--color-primary-700#1D4ED8;

/* After */
--color-primary-500#8B5CF6;
--color-primary-600#7C3AED;
--color-primary-700#6D28D9;

Home.tsx:由 146 行增加到 210 行,新增咗 7 個 Lucide 圖標導入、categoryIcons 映射、stagger 入場動畫(useEffect + CSS 變量注入)、Tab 滑動指示器(ref + indicator state + resize 監聽)、Header 嘅 Wand2 圖標 + 135deg 微漸變背景。Badge 由純文字變咗做圖標+文字(Beaker / ClipboardList)。

PlaceholderPage.tsx:⏳ emoji 替換做 <Clock size={16}> 圖標。

5. Verify:構建通過 + 30 測試全部過 + 視覺對比

構建同測試

Apply 之後跑咗一次構建:

> shuge-ai-toolbox@0.0.0 build
> tsc -b && vite build

vite v8.0.12 building client environment for production...
✓ 1753 modules transformed.
rendering chunks...
computing gzip size...
dist/index.html                   0.46 kB │ gzip:  0.30 kB
dist/assets/index-DfrT9w8n.css   19.57 kB │ gzip:  4.67 kB
dist/assets/index-UZjH-ntc.js   295.01 kB │ gzip: 94.25 kB

✓ built in 306ms

一個細節:1753 modules。引入 lucide-react 之前係 31 個 modules,引入之後暴增到 1753 個——圖標庫嘅 tree-shaking 確實喺度 work,但 lucide-react 嘅總量都唔細。

再跑測試:

> shuge-ai-toolbox@0.0.0 test
> vitest run

 ✓ src/router/index.test.tsx (3 tests) 2ms
 ✓ src/tool-registry/catalog.test.ts (7 tests) 7ms
 ✓ src/layout/TopNav.test.tsx (3 tests) 31ms
 ✓ src/layout/Layout.test.tsx (2 tests) 34ms
 ✓ src/app/views/PlaceholderPage.test.tsx (5 tests) 82ms
 ✓ src/app/views/Home.test.tsx (10 tests) 205ms

 Test Files  6 passed (6)
      Tests  30 passed (30)
   Start at  11:41:23
   Duration  1.15s

30 個測試全部通過,說明視覺變更冇破壞任何功能。

Before / After 視覺對比

視覺變更,截圖比 code 更有說服力。

首頁 Before

首頁 Before
首頁 Before

視覺升級前——Tailwind 默認藍、冇圖標、灰白色調

首頁 After

首頁 After
首頁 After

視覺升級後——藍紫品牌色、Lucide 圖標、Header 微漸變、Tab 滑動指示器、分類圖標

變化好明顯:Header 有咗 Wand2 圖標同藍紫微漸變背景,Tab 欄有咗滑動指示器,每個分類標題前有咗 Lucide 圖標,卡片有咗 hover scale + shadow 效果同 stagger 入場動畫,Beta 同 Planned badge 由純文字變咗做圖標+文字。

佔位頁 Before / After

佔位頁 Before
佔位頁 Before

升級前——⏳ emoji 提示

佔位頁 After
佔位頁 After

升級後——Clock 圖標代替 emoji

404 頁 Before / After

404 頁 Before
404 頁 Before

升級前——默認藍數字

404 頁 After
404 頁 After

升級後——品牌色自動跟住 tokens.css 變更(冇改一行 code)

404 頁呢個對比值得講多一句:NotFound.tsx 一行 code 都冇改,但顏色由默認藍變咗做品牌藍紫。原因就係佢用咗 var(--color-primary-500) 呢個 CSS 變量,tokens.css 入面換咗色值,404 頁自動跟住變。呢個就係第 3 期整 CSS 變量體系嗰陣埋落嚟嘅福利。

6. Archive:歸檔 + spec 同步

執行 /opsx:archive

AI:Delta specs exist for a new capability (`visual-identity`) — no main spec exists yet. This is a pure ADD, so syncing will create `openspec/specs/visual-identity/spec.md` for the first time.

Sync needed: visual-identity (new) — no main spec exists
  → Will create: openspec/specs/visual-identity/spec.md
AI:## Archive Complete

**Change:** `ui-visual-polish`
**Archived to:** `openspec/changes/archive/2026-05-17-ui-visual-polish/`
**Specs:** Synced to main specs (`openspec/specs/visual-identity/spec.md`)

All artifacts complete. All tasks complete.

一個值得記錄嘅點:delta specs 嘅同步。今期新增咗 visual-identity 呢個 capability,歸檔嗰陣 OpenSpec 自動檢測到主 specs 目錄下面仲未有對應嘅 spec 文件,於是創建咗 openspec/specs/visual-identity/spec.md。呢個自動同步省咗人手搬運嘅麻煩。

另外,第 4 期 archive 報咗成功但文件實際上冇移走。今期歸檔之前專登 ls openspec/changes/ 確認咗一下——目錄下面剩返 archive/,個坑已經填咗。

7. Git Push

推送環節好簡單,用自然語言指令觸發:

用戶:請幫我推送到遠程倉庫
AI:已推送。從 `229e2a0` 到 `423723b`,main 分支已更新。

8. 回顧

template 改造實驗嘅結論

先講結論:template 改造確實解決咗格式問題。 標題、涉及文件、步驟描述都變咗。

但比預期多咗一個發現:TDD 五步嘅嚴格執行取決於變更類型。今期係視覺類變更,9 個任務組入面冇一個係嚴格嘅「寫失敗測試 → 確認失敗 → 寫最小實現 → 確認通過 → 提交」循環。實際更接近「改 code → 跑測試確認冇壞」嘅迴歸測試模式。review.md 都指出咗呢一點,標咗 ⚠️。

所以更精確嘅結論係:template 管格式唔管顆粒度。 格式係結構性嘅,可以靠 template 解決——由 ## 1. 變成 ### 任務 N:、加上涉及文件列表、畀每個步驟配 code block,呢啲 template 一改就生效。但顆粒度係內容性嘅,取決於你改啲乜——視覺類變更天然難啲拆出獨立嘅「失敗測試」,而純邏輯變更(好似第 2 期嘅工具註冊中心)就更適合行 TDD 節奏。

呢個對之前講過嘅「2/8 法則」係一個重要補充。改 instruction 佔 20% 投入得到 80% 質量提升,解決嘅係內容層面嘅問題——任務描述更具體咗,佔位符少咗,code block 完整咗。但嗰 80% 嘅質量提升入面可能仲有結構性缺陷——格式始終唔啱。改 template 係補返呢一塊嘅正確手段。

講得再直白啲:你喺 schema.yaml 入面寫嘅 instruction,AI 睇咗。但佢身邊嘅 template 格式暗示更強,AI 跟 template 行咗。 呢個唔係 bug,係 LLM 嘅特性——對具體示例嘅跟隨度高過對文字描述嘅跟隨度。

呢個結論唔單止適用於 OpenSpec,都適用於任何「prompt + template」模式嘅 AI 工具。你喺設計配置嘅時候,template 同 instruction 要對齊——你想令 AI 輸出乜嘢格式,template 就係乜嘢樣。

視覺升級的效果

配色由 Tailwind 默認藍 #3B82F6 換咗做藍紫 #8B5CF6,辨識度高咗唔少。圖標系統用 Lucide 整好咗,4 個分類各有專屬圖標,badge 由純文字變咗做圖標+文字。Header 有咗微漸變同 Wand2 圖標。Tab 有咗滑動指示器。卡片有咗 hover scale + shadow + stagger 入場動畫。

整體由「腳手架」升級到有品牌感嘅「產品」。第 3 期整嘅 CSS 變量體系同第 4 期整嘅佈局骨架,喺今期真正發揮咗作用——變量體系令換色變成改一行值嘅事,佈局骨架令新增 UI 層唔需要改結構。

對 OpenSpec 用戶嘅啟發

如果你都有用 OpenSpec,而且發現改咗 instruction 但 AI 產出嘅格式始終冇變,檢查一下 template。template 文件喺 openspec/schemas/<schema-name>/templates/ 目錄下面,每個工件類型都有一個對應嘅 .md 文件。改 instruction 管內容,改 template 管格式——呢兩件事係獨立嘅。

你有冇遇到過類似嘅情況——改咗配置但 AI 就係唔聽?評論區講下,睇下係咪同一個原因。

9. 下期預告

根據系列規劃,第 6 期主題係「工具市場 + 搜索/篩選」。

如果今期 template 改造效果明顯,第 6 期會係第二次驗證——連續兩期都用新 template 生成 tasks.md,睇效果係咪穩定。一次生效可能係巧合,兩次都生效先至可以話改 template 係可靠嘅策略。

視覺層面,今期做完之後頁面已經由「腳手架」升級到有品牌感嘅「產品」。第 6 期可以聚焦功能層——畀工具列表加上搜索同篩選,令用戶唔止係按分類瀏覽,仲可以按關鍵詞快速揾到目標工具。

相關資源

OpenSpec GitHub:https://github.com/shuge-x/shuge-ai-toolbox

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


🚩 2026 年「術哥無界」系列實戰文檔 X 篇原創計劃 第 115 篇,OpenSpec 項目實戰「2026」系列第 5 篇

大家好,歡迎來到 術哥無界 | ShugeX | 運維有術

我是術哥,一名專注於 AI 編程、AI 智能體、Agent Skills、MCP、雲原生、AIOps、Milvus 向量數據庫的技術實踐者與開源佈道者

Talk is cheap, let's explore。無界探索,有術而行。

封面圖
封面圖

封面:UI 視覺打磨 + 改 template 讓 AI 寫出規範任務

說明:本文內容基於 OpenSpec(Fission-AI/OpenSpec)v1.3.1 和 React 19 + TypeScript + Tailwind CSS v4 的實際操作記錄整理而成。文中的配置模板和參數建議僅供參考,實際效果請以你的業務數據和環境測試結果為準。如果有實際使用經驗,歡迎在評論區分享交流。

1. 視覺要升級,但更重要的是一個實驗

第 4 期做了佈局骨架。首頁有了 Tab 分類導航,5 個工具、4 個分類,點 Tab 切分類,不用再在長列表裏滾來滾去。

但頁面打開一看——灰白一片。品牌色是 Tailwind 默認藍(#3B82F6),沒有圖標,卡片和導航樣式單調,沒有動效。說好聽叫「簡潔」,說直白就是「沒做完」。

這期做兩件事。

第一件:視覺層真正的升級。基於第 3 期搭好的 CSS 變量體系和第 4 期的佈局骨架,把配色、組件樣式、圖標、動效做上去,讓頁面從「腳手架」變成「產品」。change name: ui-visual-polish

第二件更重要,也是這期文章的重點。前 4 期的 tasks.md 格式一直有問題——schema instruction 裏明明要求用 ### 任務 N:[名稱] + 涉及文件 + TDD 五步結構,但 AI 每次生成的都是 ## 1. 任務名稱 + - [ ] 1.1 這種格式。改了好幾次 instruction,沒用。

後來讀了 OpenSpec 源碼,找到根因:template 的優先級高於 instruction。舊 template 用 ## 1. 格式,LLM 就跟 template 走。這期把 template 改了,今天是第一次驗證效果。

完整流程不變:

工作流總覽:5 步從探索到歸檔
工作流總覽:5 步從探索到歸檔

2. 為什麼前 4 期的 tasks.md 格式都不對

先看問題。第 1 期到第 4 期的 tasks.md 開頭長這樣。

第 1 期(project-init)

## 1. 項目腳手架初始化

[x] 1.1 使用 Vite 初始化 React + TypeScript 項目
  命令:`npx create-vite@latest . --template react-ts --yes`
  預期:項目文件生成

第 2 期(tool-registry)

## 1. 更新 catalog.ts(添加 stage 字段和初始工具數據)

**涉及文件:**
修改:`src/tool-registry/catalog.ts`

[x] **1.1:更新 ToolManifest 接口**

第 3 期(ui-redesign)

## 1. 設計系統基礎

[x] 1.1 創建 design-tokens.css 文件

第 4 期(layout-restructure)

## 1. Tab 導航組件測試

[ ] 1.1 編寫 Tab 導航組件測試

看到了嗎?全部都是 ## 1. + - [x] 1.1 格式。4 期文章、4 個不同的 change、幾十個任務,沒有一次出現 ### 任務 N 的格式。

再來看 instruction 裏寫了什麼。逐字引用 openspec/schemas/with-review/schema.yaml 中 tasks 的 instruction 部分(截取關鍵段落):

- id:tasks
generates:tasks.md
description:Implementationchecklistwithtrackabletasks
template:tasks.md
instruction:|
    創建細粒度的實現計劃。每個任務的工作量應在 2-5 分鐘之間。

    ## 任務格式(必須嚴格遵守)

    每個任務必須遵循以下格式:

    ### 任務 N:[組件名稱]

    **涉及文件:**
    -新建/修改:exact/path/to/file
    -測試:tests/exact/path/to/test

    -[]**第1步:寫失敗測試**
    -[]**第2步:運行測試——確認失敗**
    -[]**第3步:寫最小實現**
    -[]**第4步:運行測試——確認通過**
    -[]**第5步:提交**

    ## 禁止事項(出現即視為計劃不合格)
    -「TBD」「TODO」「implementlater」「fillindetails」

instruction 裏寫得清清楚楚:### 任務 N:[組件名稱],涉及文件列表,TDD 五步。甚至用了「必須嚴格遵守」這種措辭。

但 AI 一次都沒遵守。

第 2 期稍微好一點,出現了「涉及文件」這一行,但標題還是 ## 1.,步驟還是 - [x] 1.1。第 3 期和第 4 期連涉及文件都沒有了。

這不是偶然。4 期都是同一個模式,說明不是某次生成時的隨機偏差,而是有系統性的原因。

根因分析:template 的優先級高於 instruction

OpenSpec 生成工件時,同時讀取兩個輸入:template(模板文件,在 schemas/with-review/templates/ 目錄下)和 instruction(指令文本,在 schema.yaml 的 instruction 字段裏)。

LLM 面對這兩個輸入時的行為模式是:template 提供具體的格式示例,instruction 提供文字描述。當兩者格式衝突時,LLM 傾向於跟 template 走。

這個判斷來自對 OpenSpec 源碼的調研。生成工件時,template 的內容被作為「參考格式」先展示給 LLM,instruction 作為「補充說明」跟在後面。順序上的差異導致 template 的格式暗示更強——LLM 會把 template 當作「你應該長成這樣」的範本,把 instruction 當作「內容上注意這些」的建議。

舊 template 的格式是這樣的:

## 1. <!-- Task Group Name -->

[ ] 1.1 <!-- Step description -->
[ ] 1.2 <!-- Step description -->

AI 看到這個模板,腦子裏形成了一個框架:「標題用 ## 1.,步驟用 - [ ] 1.1」。然後 instruction 說「用 ### 任務 N」,但它已經被 template 的格式錨定了,改不過來。

這就像你讓一個人照着模板寫公文,模板是表格格式的,你在旁邊說「請用列表格式」,他大概率還是照着模板寫表格。不是因為不聽,而是模板的視覺暗示太強了。

改造方案:直接改 template

既然 instruction 管不了格式,那就改 template。逐字引用改造後的 openspec/schemas/with-review/templates/tasks.md

### 任務 1:<!-- Task Group Name -->

**涉及文件:**
新建/修改:exact/path/to/file
測試:tests/exact/path/to/test

[ ] 1.1 **寫失敗測試**
```typescript
// test code here
```


[ ] 1.2 **運行測試——確認失敗**
命令:`npx vitest run tests/path/test.ts`
預期:FAIL — <!-- expected error -->

[ ] 1.3 **寫最小實現**
```typescript
// implementation code here
```


[ ] 1.4 **運行測試——確認通過**
命令:`npx vitest run tests/path/test.ts`
預期:PASS

[ ] 1.5 **提交**
```bash
git add path/to/files
git commit -m "feat: description"
```


### 任務 2:<!-- Task Group Name -->

**涉及文件:**
新建/修改:exact/path/to/file
測試:tests/exact/path/to/test

[ ] 2.1 <!-- Continue with the same pattern -->

改動點很明確:

維度
舊 template
新 template
標題格式
## 1.### 任務 1:
涉及文件
**涉及文件:**
 + 文件路徑列表
步驟結構
- [ ] 1.1 描述
TDD 五步(寫失敗測試 → 確認失敗 → 寫實現 → 確認通過 → 提交)
代碼佔位
每步都有代碼塊或命令行
第二個任務
同上
重複模板結構

從 ## 1. 變成 ### 任務 1:,看起來只是標記層級和命名方式的變化,但對 LLM 來說,這個格式改變會產生不同的輸出模式。加了「涉及文件」列表,AI 就會習慣性地列出每個任務涉及的文件。加了 TDD 五步結構,AI 就會按這個節奏組織每個任務。

本期 ui-visual-polish change 是改造 template 後的第一次驗證。

如果 AI 跟新 template 走了,tasks.md 的格式就會變成 ### 任務 N + 涉及文件 + TDD 五步。如果還是 ## 1. 格式,說明問題不止在 template,需要進一步排查。

當前項目狀態

順便說明一下本期開始前的項目狀態。

逐字引用 src/theme/tokens.css(第 3 期產出,77 行):

:root {
/* 品牌色板 - 冷色系 */
--color-primary-500#3B82F6;
--color-primary-600#2563EB;
--color-primary-700#1D4ED8;

/* 強調色 - 琥珀色 */
--color-accent-500#F59E0B;
--color-accent-600#D97706;

/* 中性色 - 冷灰 */
--color-neutral-50#F8FAFC;
--color-neutral-200#E2E8F0;
--color-neutral-500#64748B;
--color-neutral-900#0F172A;
/* ... 字體、間距、圓角等 */
}

CSS 變量體系有了,但 Home 頁面的 ToolCard 組件大量使用 inline style,沒有充分複用這些變量。TopNav 也很基礎——一個 logo + 一個「首頁」連結。配色是 Tailwind 默認藍,沒有品牌辨識度。

這些就是本期視覺升級的起點。

3. Explore → Propose:從需求澄清到 5 個工件一步到位

這期有個重要發現:Explore 和 Propose 不是兩個獨立步驟,而是連續流程。執行 /opsx:explore,多輪對話確認方向後,AI 輸出 Design Doc,確認後直接自動創建 change 並生成全部 5 個工件——中間沒有單獨的 /opsx:propose 步驟。

以下是完整交互過程。

多輪對話:確認視覺升級方向

執行 /opsx:explore,AI 先問了一句:

AI:What's on your mind? An idea, a problem, a comparison — or just wander?

輸入本期需求:

用戶:本期做一個 ui-visual-polish 變更。當前頁面的 CSS 變量體系已搭好但未充分使用,配色是默認藍沒有辨識度,沒有圖標系統,卡片和導航樣式單調。需要全面升級視覺層——配色、圖標、動效,讓頁面從腳手架變成產品。

AI 讀了一遍源碼,做了一輪 Gap 分析:

AI:{讀源碼,做 Gap 分析}

現狀梳理:
Primary (藍):    50→700   ← 幾乎未使用
Accent (琥珀):   50→600   ← Beta/Planned badge,active tab border
Neutral (冷灰):  50→900   ← 大量使用
Semantic:        success/warning/error  ← 未使用

Gap 分析:
| 維度 | 現狀 | 問題 |
|------|------|------|
| 配色 | 變量定義好了,但只用 neutral | 藍得很默認,缺乏辨識度 |
| 圖標 | 僅有一個 ⏳ emoji | 分類/Tab/卡片均無圖標 |
| 動效 | 僅 transition-colors,hover:shadow-md | 沒有微交互 |
| 卡片 | 純 flat border + opacity | 沒有層次感 |
| 導航 | border-b-2 amber 作為 active indicator | 與品牌藍不一致 |

幾個思考方向:1. 配色策略 2. 圖標系統 3. 動效深度 4. 視覺錨點。你傾向於先攻哪個方向?或者想先聊聊整體的設計語言定位再動手?

Gap 分析很準確——變量體系搭好了但幾乎沒用上,中性灰堆滿了整個頁面。一口氣給 4 個方向都定了:

用戶:1. 配色:換掉默認藍,選一個有辨識度的品牌色。primary 做交互色,accent 保持琥珀做功能區分。具體的色值你來定,不要用 Tailwind 默認藍。2. 圖標:用 Lucide,每個 category 配一個 icon,badge 用小圖標輔助(Beta 用 🧪 / Planned 用 📋)。3. 動效:做到中等——卡片 hover scale + shadow + stagger 入場動畫,tab 切換加滑動指示器。不需要 page transition。4. Header:保持純文字,但加一個簡潔的 icon 或 logo mark,背景用微漸變提升層次。整體方向:乾淨、專業、有品牌感,不要花哨。參考 Linear 或 Vercel 的設計風格。

AI 又追問了 4 個關鍵問題:

AI:方向清晰了。再摸幾個關鍵問題:

1. 
**品牌色定位** — 推薦藍紫(blue-violet),比純藍更有辨識度,比純紫更穩。你接受嗎?
2. **Lucide React 安裝了嗎?**
3. **背景漸變** — 淺色 header + subtle gradient 還是深色 header?
4. **動效節奏** — 快速連續(30-50ms)還是柔和錯落(80-120ms)?
用戶:1. 藍紫方向接受,你來定具體色值。2. Lucide 沒裝,本期 install 進去。3. 淺色 header + subtle gradient,保持整體 light theme 基調。4. 柔和錯落 80-120ms,偏產品感。

接下來是圖標分配和 Badge 方案:

AI:好,我來分配圖標,附上理由:
文本處理 → Type ← 文字輸入/編輯感
數據轉換 → RefreshCw ← 轉換/循環感
開發工具 → Code2 ← 開發者身份明確
內容創作 → Feather ← 創作、手寫感
Badge: Beta → Flask, Planned → ClipboardList。確認這 6 個 icon 分配?
用戶:確認
AI:最後確認——Badge 的 emoji 方案:純圖標 vs 圖標+emoji 混搭?
用戶:純圖標

到這裏所有細節都定了。AI 輸出完整 Design Doc。

Design Doc + 自動生成 5 個工件

AI 輸出的 Design Doc 關鍵內容:

AI:{輸出完整 Design Doc}

## UI Visual Polish — Design Doc

### 1. 配色體系
品牌色:藍紫 (Blue-Violet)
Primary (藍紫)              Accent (琥珀)              Semantic
─────────────────           ─────────────────           ────────
50: #F5F3FF   極淺紫          50: #FFFBEB               success: #10B981
100: #EDE9FE                 100: #FEF3C7              warning: #F59E0B
200: #DDD6FE                 200: #FDE68A              error: #EF4444
300: #C4B5FD                 300: #FCD34D
400: #A78BFA                 400: #FBBF24
500: #8B5CF6   ← 品牌主色     500: #F59E0B
600: #7C3AED   ← 深色交互     600: #D97706
700: #6D28D9   ← 強調/hover
語義映射:交互色 primary-500, Beta badge accent-500, Active tab indicator primary-500

### 2. 圖標系統
Category Icons: 文本處理→Type, 數據轉換→RefreshCw, 開發工具→Code2, 內容創作→Feather
Badge Icons: Beta→Flask(替代🧪), Planned→ClipboardList(替代📋)

### 3. 動效
卡片 Hover: scale 1.02, shadow rgba(139,92,246,0.15), 200ms ease-out
Stagger: fadeInUp 400ms, cubic-bezier(0.22,1,0.36,1), 100ms stagger
Tab 指示器: JS left/width, 250ms cubic-bezier(0.4,0,0.2,1)

### 4. Header
background: linear-gradient(135deg, neutral-50 → primary-50)
標題左側: Wand2 icon + "shuge AI Toolbox"

### 5. 修改文件清單
tokens.css, index.css, Home.tsx, NotFound.tsx, PlaceholderPage.tsx, package.json

Design Doc 確認嗎?可以的話我們開 change 了。

確認後,AI 直接自動執行 openspec new change "ui-visual-polish" 並生成全部 5 個工件,沒有等用戶再去執行什麼 propose 命令:

用戶:確認
AI:{自動執行 openspec new change "ui-visual-polish",生成 5 個工件}

Change `ui-visual-polish` 創建完成。所有 artifacts 位於 `openspec/changes/ui-visual-polish/`
| Artifact | 說明 |
|----------|------|
| proposal.md | 變更動機 + 影響範圍 |
| design.md | 藍紫色值決策、Lucide 選型、Stagger/Tab 指示器實現方案對比 |
| specs/visual-identity/spec.md | 4 個 capability 的場景定義(配色/圖標/動效/Header) |
| review.md | 5 維度審查,重點關注任務粒度和測試覆蓋 |
| tasks.md | 9 個任務組,涵蓋安裝依賴 → 配色 → 4 類圖標 → stagger → tab 指示器 → header → NotFound → Placeholder → 提交 |

下一步:運行 `/opsx:apply` 開始實現。

template 改造效果:格式變了

這是本期最有價值的觀察點。直接看 tasks.md 實際生成的第一個任務組:

### 任務 1:安裝 lucide-react + 重建 tokens.css 配色

**涉及文件:**
修改:`package.json`
修改:`src/theme/tokens.css`

[ ] 1.1 **安裝 lucide-react**

```bash
npm install lucide-react
```


[ ] 1.2 **更新 package.json 並驗證 lockfile**

```bash
cat package.json | grep lucide-react
```

預期:`"lucide-react": "^0.468.0"`(或當前最新版本)

[ ] 1.3 **重建 tokens.css 的 primary 色板為藍紫系**

```css
  /* 品牌色板 - 藍紫 (Blue-Violet) */
  --color-primary-50: #F5F3FF;
  --color-primary-100: #EDE9FE;
  --color-primary-200: #DDD6FE;
  --color-primary-300: #C4B5FD;
  --color-primary-400: #A78BFA;
  --color-primary-500: #8B5CF6;
  --color-primary-600: #7C3AED;
  --color-primary-700: #6D28D9;
```


[ ] 1.4 **運行測試——確認 CSS 變量正確**

```bash
npx vitest run
```

預期:PASS

對比改造前:

## 1. 任務名稱

[x] 1.1 步驟描述
[x] 1.2 步驟描述

結論很清晰:標題從 ## 1. 變成了 ### 任務 1:,涉及文件列表成了標配,每個步驟都有代碼塊。 改 template 確實生效了。

9 個任務組裏 8 個都有涉及文件列表,代碼塊總共 34 個,是前 4 期的歷史高點。

不過也有一個沒完全到位的地方:TDD 五步(寫失敗測試→確認失敗→寫實現→確認通過→提交)沒有嚴格遵循。實際更接近「改代碼 → 運行測試確認沒壞」的迴歸測試模式。review.md 也指出了這個問題,標了 ⚠️ 警告:視覺類任務難以按 TDD 節奏嚴格拆分。這個觀察很重要,後面回顧章節會展開。

4. Apply:33 步全量執行 + 三個小插曲

執行 /opsx:apply,AI 開始逐任務執行。

AI:Using change: **ui-visual-polish** (schema: with-review). Reading context files...

AI:Implementing: ui-visual-polish (schema: with-review). Progress: 0/33 tasks complete. Working on Task 1/9: 安裝 lucide-react + 重建 tokens.css 配色

33 個步驟,9 個任務組,AI 一路往下跑。

三個小插曲

執行過程中出現了三個有意思的問題,AI 都自行發現並修復了。

插曲 1:Flask 圖標不存在,改用 Beaker

Explore 階段 Design Doc 規劃了 Beta badge 用 Flask 圖標。但 apply 執行時,AI 發現 lucide-react 里根本沒有 Flask 這個組件,自動改用了 Beaker

規劃時選了 Flask,實際發現 lucide-react 沒有 Flask,改用了 Beaker——這種規劃→執行的偏差在真實項目裏很常見。AI 編程助手在執行時的這種自適應能力,是它比純腳本自動化更有價值的地方。

插曲 2:index.css 內容被意外覆蓋

AI:我發現一個問題——我把 index.css 的原有內容(imports)覆蓋了。需要補回來。

AI 在編輯 index.css 時不小心覆蓋了原有 imports 內容,隨即自己發現並補回。這種自我修復是 AI 編程助手的常見行為——它會犯錯,但也會監控自己的輸出並在發現問題時立即修正。

插曲 3:NotFound.tsx 不需要改

AI:NotFound.tsx already uses `var(--color-primary-500)` — no changes needed.

tasks.md 任務 7 規劃了 NotFound 配色更新。但 apply 時 AI 發現 NotFound.tsx 已經使用了 var(--color-primary-500) CSS 變量——tokens.css 的 primary 色值從 #3B82F6 改為 #8B5CF6 後,404 頁面的顏色自動跟隨變化,不需要改代碼。

這就是使用 CSS 變量的好處:一處修改,全局生效。

另外還有一個 bug 修復:AI 使用了 React.createElement 但沒導入 React,測試失敗後快速定位並添加了 import React

Apply 完成報告

AI:## Implementation Complete

**Change:**`ui-visual-polish`
**Schema:**`with-review`
**Progress:** 33/33 tasks complete ✓

### Completed This Session
Task 1: npm install lucide-react + tokens.css primary 色板重建為藍紫系
Task 2: index.css 添加 fadeInUp keyframes + .animate-fadeInUp class
Task 3: Home.tsx 導入 Lucide 圖標 + categoryIcon 映射 + Badge Lucide 圖標 + Category 圖標
Task 4: Home.tsx stagger 入場動畫 + hover scale/shadow 效果
Task 5: Home.tsx Tab 滑動指示器 (JS ref + CSS transition)
Task 6: Home.tsx Header Wand2 icon + 135deg 微漸變
Task 7: NotFound.tsx 配色確認(已是 primary-500)
Task 8: PlaceholderPage.tsx ⏳ → Clock icon
Task 9: 全量測試 PASS + commit

### 發現並解決的問題
Flask 在 lucide-react 中不存在 → 改用 Beaker
Tab 指示器高亮從 className border-b-2 改為 style.borderColor(無侵入)
Active Tab 樣式用 inline style 替代 class 注入(避免 CSS 類名測試失效)

### Bug 修復
React.createElement 未導入 React → 添加 import React

所有 30 個測試全部通過。變更已提交。可以 `/opsx:archive` 歸檔。

關鍵文件變更摘要

不多貼代碼,說幾個關鍵變化。

tokens.css:primary 色板從默認藍換成藍紫。

/* Before */
--color-primary-500#3B82F6;
--color-primary-600#2563EB;
--color-primary-700#1D4ED8;

/* After */
--color-primary-500#8B5CF6;
--color-primary-600#7C3AED;
--color-primary-700#6D28D9;

Home.tsx:從 146 行增加到 210 行,新增了 7 個 Lucide 圖標導入、categoryIcons 映射、stagger 入場動畫(useEffect + CSS 變量注入)、Tab 滑動指示器(ref + indicator state + resize 監聽)、Header 的 Wand2 圖標 + 135deg 微漸變背景。Badge 從純文字變成了圖標+文字(Beaker / ClipboardList)。

PlaceholderPage.tsx:⏳ emoji 替換為 <Clock size={16}> 圖標。

5. Verify:構建通過 + 30 測試全過 + 視覺對比

構建和測試

Apply 後跑了一遍構建:

> shuge-ai-toolbox@0.0.0 build
> tsc -b && vite build

vite v8.0.12 building client environment for production...
✓ 1753 modules transformed.
rendering chunks...
computing gzip size...
dist/index.html                   0.46 kB │ gzip:  0.30 kB
dist/assets/index-DfrT9w8n.css   19.57 kB │ gzip:  4.67 kB
dist/assets/index-UZjH-ntc.js   295.01 kB │ gzip: 94.25 kB

✓ built in 306ms

一個細節:1753 modules。引入 lucide-react 之前是 31 個模塊,引入後暴增到 1753 個——圖標庫的 tree-shaking 確實在工作,但 lucide-react 的總量還是不小。

再跑測試:

> shuge-ai-toolbox@0.0.0 test
> vitest run

 ✓ src/router/index.test.tsx (3 tests) 2ms
 ✓ src/tool-registry/catalog.test.ts (7 tests) 7ms
 ✓ src/layout/TopNav.test.tsx (3 tests) 31ms
 ✓ src/layout/Layout.test.tsx (2 tests) 34ms
 ✓ src/app/views/PlaceholderPage.test.tsx (5 tests) 82ms
 ✓ src/app/views/Home.test.tsx (10 tests) 205ms

 Test Files  6 passed (6)
      Tests  30 passed (30)
   Start at  11:41:23
   Duration  1.15s

30 個測試全部通過,說明視覺變更沒有破壞任何功能。

Before / After 視覺對比

視覺變更,截圖比代碼更有說服力。

首頁 Before

首頁 Before
首頁 Before

視覺升級前——Tailwind 默認藍、無圖標、灰白色調

首頁 After

首頁 After
首頁 After

視覺升級後——藍紫品牌色、Lucide 圖標、Header 微漸變、Tab 滑動指示器、分類圖標

變化很明顯:Header 有了 Wand2 圖標和藍紫微漸變背景,Tab 欄有了滑動指示器,每個分類標題前有了 Lucide 圖標,卡片有了 hover scale + shadow 效果和 stagger 入場動畫,Beta 和 Planned badge 從純文字變成了圖標+文字。

佔位頁 Before / After

佔位頁 Before
佔位頁 Before

升級前——⏳ emoji 提示

佔位頁 After
佔位頁 After

升級後——Clock 圖標替代 emoji

404 頁 Before / After

404 頁 Before
404 頁 Before

升級前——默認藍數字

404 頁 After
404 頁 After

升級後——品牌色自動跟隨 tokens.css 變更(沒改一行代碼)

404 頁這個對比值得多說一句:NotFound.tsx 一行代碼都沒改,但顏色從默認藍變成了品牌藍紫。原因就是它用了 var(--color-primary-500) 這個 CSS 變量,tokens.css 裏換了色值,404 頁自動跟着變。這就是第 3 期搭 CSS 變量體系時埋下的福利。

6. Archive:歸檔 + spec 同步

執行 /opsx:archive

AI:Delta specs exist for a new capability (`visual-identity`) — no main spec exists yet. This is a pure ADD, so syncing will create `openspec/specs/visual-identity/spec.md` for the first time.

Sync needed: visual-identity (new) — no main spec exists
  → Will create: openspec/specs/visual-identity/spec.md
AI:## Archive Complete

**Change:** `ui-visual-polish`
**Archived to:** `openspec/changes/archive/2026-05-17-ui-visual-polish/`
**Specs:** Synced to main specs (`openspec/specs/visual-identity/spec.md`)

All artifacts complete. All tasks complete.

一個值得記錄的點:delta specs 的同步。本期新增了 visual-identity 這個 capability,歸檔時 OpenSpec 自動檢測到主 specs 目錄下還沒有對應的 spec 文件,於是創建了 openspec/specs/visual-identity/spec.md。這個自動同步省去了手動搬運的麻煩。

另外,第 4 期 archive 報了成功但文件實際沒移走。這期歸檔前特意 ls openspec/changes/ 確認了一下——目錄下只剩 archive/,坑已填。

7. Git Push

推送環節很簡單,自然語言指令觸發:

用戶:請幫我推送到遠程倉庫
AI:已推送。從 `229e2a0` 到 `423723b`,main 分支已更新。

8. 回顧

template 改造實驗的結論

先說結論:template 改造確實解決了格式問題。 標題、涉及文件、步驟描述都變了。

但比預期多了一個發現:TDD 五步的嚴格執行取決於變更類型。本期是視覺類變更,9 個任務組裏沒有一個是嚴格的「寫失敗測試 → 確認失敗 → 寫最小實現 → 確認通過 → 提交」循環。實際更接近「改代碼 → 跑測試確認沒壞」的迴歸測試模式。review.md 也指出了這一點,標了 ⚠️。

所以更精確的結論是:template 管格式不管顆粒度。 格式是結構性的,可以靠 template 解決——從 ## 1. 變成 ### 任務 N:、加上涉及文件列表、給每個步驟配代碼塊,這些 template 一改就生效。但顆粒度是內容性的,取決於你改什麼——視覺類變更天然難以拆出獨立的「失敗測試」,而純邏輯變更(比如第 2 期的工具註冊中心)就更適合走 TDD 節奏。

這對前傳說過的「2/8 法則」是一個重要補充。改 instruction 佔 20% 投入獲 80% 質量提升,解決的是內容層面的問題——任務描述更具體了,佔位符少了,代碼塊完整了。但那 80% 的質量提升裏可能有結構性缺陷——格式始終不對。改 template 是補上這一塊的正確手段。

說得更直白:你在 schema.yaml 裏寫的 instruction,AI 看了。但它身邊的 template 格式暗示更強,AI 跟 template 走了。 這不是 bug,是 LLM 的特性——對具體示例的遵循度高於對文字描述的遵循度。

這個結論不僅適用於 OpenSpec,也適用於任何「prompt + template」模式的 AI 工具。你在設計配置的時候,template 和 instruction 要對齊——你想讓 AI 輸出什麼格式,template 就長什麼樣。

視覺升級的效果

配色從 Tailwind 默認藍 #3B82F6 換成了藍紫 #8B5CF6,辨識度高了不少。圖標系統用 Lucide 搭好了,4 個分類各有專屬圖標,badge 從純文字變成圖標+文字。Header 有了微漸變和 Wand2 圖標。Tab 有了滑動指示器。卡片有了 hover scale + shadow + stagger 入場動畫。

整體從「腳手架」升級到了有品牌感的「產品」。第 3 期搭的 CSS 變量體系和第 4 期搭的佈局骨架,在這期真正發揮了作用——變量體系讓換色變成改一行值的事,佈局骨架讓新增 UI 層不需要動結構。

對 OpenSpec 用戶的啓發

如果你也在用 OpenSpec,而且發現改了 instruction 但 AI 產出的格式始終沒變,檢查一下 template。template 文件在 openspec/schemas/<schema-name>/templates/ 目錄下,每個工件類型都有一個對應的 .md 文件。改 instruction 管內容,改 template 管格式——這兩件事是獨立的。

你有沒有遇到過類似的情況——改了配置但 AI 就是不聽?評論區說說,看看是不是同一個原因。

9. 下期預告

根據系列規劃,第 6 期主題是「工具市場 + 搜索/篩選」。

如果本期 template 改造效果明顯,第 6 期會是第二次驗證——連續兩期都用新 template 生成 tasks.md,看效果是否穩定。一次生效可能是巧合,兩次都生效才能說明改 template 是可靠的策略。

視覺層面,本期做完後頁面已經從「腳手架」升級到有品牌感的「產品」。第 6 期可以聚焦功能層——給工具列表加上搜索和篩選,讓用戶不只是按分類瀏覽,還能按關鍵詞快速找到目標工具。

相關資源

OpenSpec GitHub:https://github.com/shuge-x/shuge-ai-toolbox

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