概念
本指南說明 OpenSpec 背後的核心理念,以及它們如何相互配合。關於實際使用方式,請參閱 快速入門 和 工作流程。
設計理念
OpenSpec 建立在四個原則之上:
流動而非僵化 — 沒有階段關卡,專注於有意義的工作
迭代而非瀑布式 — 在建構中學習,在過程中精進
簡易而非複雜 — 輕量級設定,最少的繁文縟節
棕地優先 — 適用於現有程式碼庫,而不僅是全新專案為何這些原則很重要
流動而非僵化。 傳統的規格系統將你鎖定在階段中:先規劃,然後實作,最後完成。OpenSpec 更為靈活——你可以按照對工作最有意義的順序來建立產出物。
迭代而非瀑布式。 需求會改變。理解會加深。一開始看似不錯的方法,在實際接觸程式碼庫後可能不再適用。OpenSpec 接受並擁抱這個現實。
簡易而非複雜。 有些規格框架需要大量的設定、僵化的格式或繁重的流程。OpenSpec 不會妨礙你。幾秒鐘內即可初始化,立即開始工作,僅在需要時才進行自訂。
棕地優先。 大多數的軟體工作並非從零開始建構——而是修改現有系統。OpenSpec 基於差異的方法,讓你輕鬆地規格化對現有行為的變更,而不僅僅是描述新系統。
全局概覽
OpenSpec 將您的工作組織為兩個主要區域:
┌────────────────────────────────────────────────────────────────────┐
│ openspec/ │
│ │
│ ┌─────────────────────┐ ┌───────────────────────────────┐ │
│ │ specs/ │ │ changes/ │ │
│ │ │ │ │ │
│ │ 真實來源 │◄─────│ 提出的修改 │ │
│ │ 描述您的系統 │ merge│ 每個變更 = 一個資料夾 │ │
│ │ 目前的運作方式 │ │ 包含產出物與差異 │ │
│ │ │ │ │ │
│ └─────────────────────┘ └───────────────────────────────┘ │
│ │
└────────────────────────────────────────────────────────────────────┘規格 (Specs) 是真實來源——它們描述了您的系統目前的行為。
變更 (Changes) 是提出的修改——它們存放在獨立的資料夾中,直到您準備好將它們合併。
這種分離是關鍵。您可以同時處理多個變更而不會產生衝突。您可以在變更影響主要規格之前對其進行審查。當歸檔一個變更時,其差異可以乾淨地合併到真實來源中。
規格 (Specs)
規格使用結構化的需求和情境來描述您的系統行為。
結構
openspec/specs/
├── auth/
│ └── spec.md # 認證行為
├── payments/
│ └── spec.md # 支付處理
├── notifications/
│ └── spec.md # 通知系統
└── ui/
└── spec.md # UI 行為與主題按領域組織規格——對您的系統有意義的邏輯分組。常見模式:
- 按功能區域:
auth/、payments/、search/ - 按組件:
api/、frontend/、workers/ - 按限界上下文:
ordering/、fulfillment/、inventory/
規格格式
一個規格包含需求,每個需求都有情境:
markdown
# 認證規格
## 目的
應用程式的認證與會話管理。
## 需求
### 需求:使用者認證
系統應在成功登入時發放 JWT 權杖。
#### 情境:有效的憑證
- 假設一個擁有有效憑證的使用者
- 當使用者提交登入表單
- 則返回一個 JWT 權杖
- 且使用者被重新導向至儀表板
#### 情境:無效的憑證
- 假設無效的憑證
- 當使用者提交登入表單
- 則顯示錯誤訊息
- 且不發放任何權杖
### 需求:會話過期
系統必須在 30 分鐘不活動後使會話過期。
#### 情境:閒置逾時
- 假設一個已認證的會話
- 當 30 分鐘過去且無活動
- 則該會話被失效
- 且使用者必須重新認證關鍵元素:
| 元素 | 用途 |
|---|---|
## 目的 | 此規格領域的高層次描述 |
### 需求: | 系統必須具備的特定行為 |
#### 情境: | 需求在實際運作中的具體範例 |
| SHALL/MUST/SHOULD | RFC 2119 關鍵字,表示需求的強度 |
為何要如此結構化規格
需求是「做什麼」——它們陳述系統應該做什麼,而不指定實作方式。
情境是「何時」——它們提供可被驗證的具體範例。好的情境:
- 是可測試的(您可以為它們編寫自動化測試)
- 涵蓋了正常路徑和邊緣情況
- 使用 Given/When/Then 或類似的結構化格式
RFC 2119 關鍵字(SHALL、MUST、SHOULD、MAY)傳達意圖:
- MUST/SHALL — 絕對需求
- SHOULD — 建議,但存在例外
- MAY — 可選
規格是什麼(以及不是什麼)
規格是一份行為合約,而不是實作計畫。
好的規格內容:
- 使用者或下游系統所依賴的可觀察行為
- 輸入、輸出和錯誤條件
- 外部約束(安全性、隱私、可靠性、相容性)
- 可被測試或明確驗證的情境
在規格中應避免:
- 內部類別/函數名稱
- 函式庫或框架的選擇
- 逐步的實作細節
- 詳細的執行計畫(這些應屬於
design.md或tasks.md)
快速測試:
- 如果實作可以改變而不改變外部可見的行為,它很可能不屬於規格。
保持輕量:漸進式嚴謹
OpenSpec 旨在避免官僚主義。使用最輕量級別,同時仍能使變更可驗證。
輕量規格(預設):
- 簡短的行為優先需求
- 清晰的範圍與非目標
- 幾個具體的驗收檢查
完整規格(用於較高風險):
- 跨團隊或跨儲存庫的變更
- API/合約變更、遷移、安全/隱私問題
- 歧義可能導致昂貴返工的變更
大多數變更應保持在輕量模式。
人類與代理協作
在許多團隊中,人類探索,代理起草產出物。預期的循環是:
- 人類提供意圖、上下文和約束。
- 代理將其轉換為行為優先的需求和情境。
- 代理將實作細節保留在
design.md和tasks.md中,而非spec.md。 - 驗證在實作前確認結構和清晰度。
這使得規格對人類可讀,對代理一致。
變更 (Changes)
一個變更是一個對您系統的修改提案,打包成一個資料夾,包含理解和實作它所需的一切。
變更結構
openspec/changes/add-dark-mode/
├── proposal.md # 為什麼與做什麼
├── design.md # 如何做(技術方法)
├── tasks.md # 實作檢查清單
├── .openspec.yaml # 變更中繼資料(可選)
└── specs/ # 差異規格
└── ui/
└── spec.md # ui/spec.md 中的變更內容每個變更是自包含的。它包含:
- 產出物 — 捕捉意圖、設計和任務的文件
- 差異規格 — 關於正在新增、修改或移除內容的規格
- 中繼資料 — 此特定變更的可選配置
為何變更是資料夾
將變更打包為資料夾有幾個好處:
所有內容集中。 提案、設計、任務和規格都在一個地方。無需在不同位置搜尋。
並行工作。 多個變更可以同時存在而不衝突。在
fix-auth-bug進行的同時處理add-dark-mode。乾淨的歷史。 歸檔時,變更會移動到
changes/archive/,並保留其完整上下文。您可以回顧並理解不僅僅是變更了什麼,還有為什麼。便於審查。 變更資料夾易於審查——打開它,閱讀提案,檢查設計,查看規格差異。
產出物 (Artifacts)
產出物是變更中指導工作的文件。
產出物流程
提案 ──────► 規格 ──────► 設計 ──────► 任務 ──────► 實作
│ │ │ │
為什麼 做什麼 如何做 要採取的
+ 範圍 變更內容 方法 步驟產出物相互構建。每個產出物都為下一個提供上下文。
產出物類型
提案 (proposal.md)
提案在高層次上捕捉意圖、範圍和方法。
markdown
# 提案:新增深色模式
## 意圖
使用者要求提供深色模式選項,以減少夜間使用時的眼睛疲勞,並符合系統偏好設定。
## 範圍
在範圍內:
- 設定中的主題切換
- 系統偏好偵測
- 在 localStorage 中保存偏好設定
不在範圍內:
- 自訂顏色主題(未來工作)
- 每頁主題覆蓋
## 方法
使用 CSS 自訂屬性進行主題化,並使用 React context 進行狀態管理。在首次載入時偵測系統偏好,允許手動覆蓋。何時更新提案:
- 範圍改變(縮小或擴大)
- 意圖更清晰(對問題有更好的理解)
- 方法根本性轉變
規格(specs/ 中的差異規格)
差異規格描述相對於當前規格正在改變的內容。請參閱下方的差異規格。
設計 (design.md)
設計捕捉技術方法和架構決策。
markdown
# 設計:新增深色模式
## 技術方法
透過 React Context 管理主題狀態,以避免屬性逐層傳遞。
CSS 自訂屬性實現運行時切換,無需切換類別。
## 架構決策
### 決策:使用 Context 而非 Redux
使用 React Context 來管理主題狀態,原因如下:
- 狀態簡單且為二元性質(淺色/深色)
- 無需複雜的狀態轉換
- 避免引入 Redux 依賴
### 決策:使用 CSS 自訂屬性
使用 CSS 變數而非 CSS-in-JS,原因如下:
- 與現有樣式表相容
- 無運行時效能開銷
- 瀏覽器原生解決方案
## 資料流
```
ThemeProvider (context)
│
▼
ThemeToggle ◄──► localStorage
│
▼
CSS Variables (applied to :root)
```
## 檔案變更
- `src/contexts/ThemeContext.tsx` (新增)
- `src/components/ThemeToggle.tsx` (新增)
- `src/styles/globals.css` (已修改)何時更新設計:
- 實作時發現該方法不可行
- 發現更好的解決方案
- 依賴項或限制條件發生變化
任務 (tasks.md)
任務是實作檢查清單 — 帶有核取方塊的具體步驟。
markdown
# 任務
## 1. 主題基礎架構
- [ ] 1.1 建立帶有亮色/暗色狀態的 ThemeContext
- [ ] 1.2 為顏色添加 CSS 自訂屬性
- [ ] 1.3 實作 localStorage 持久化
- [ ] 1.4 添加系統偏好偵測
## 2. UI 元件
- [ ] 2.1 建立 ThemeToggle 元件
- [ ] 2.2 在設定頁面添加開關
- [ ] 2.3 更新 Header 以包含快速開關
## 3. 樣式
- [ ] 3.1 定義暗色主題色盤
- [ ] 3.2 更新元件以使用 CSS 變數
- [ ] 3.3 測試無障礙對比度任務最佳實踐:
- 將相關任務分組置於標題下
- 使用階層式編號(1.1、1.2 等)
- 保持任務足夠小,以便在一次會話中完成
- 完成任務後將其核銷
增量規格
增量規格是讓 OpenSpec 適用於既有系統開發的關鍵概念。它們描述正在變更的內容,而非重述整個規格。
格式
markdown
# 認證的增量規格
## 新增需求
### 需求:雙因素驗證
系統必須支援基於 TOTP 的雙因素驗證。
#### 場景:2FA 註冊
- 給定一個未啟用 2FA 的使用者
- 當使用者在設定中啟用 2FA
- 則顯示一個 QR 碼以供驗證器應用程式設定
- 且使用者必須在啟用前使用驗證碼進行驗證
#### 場景:2FA 登入
- 給定一個已啟用 2FA 的使用者
- 當使用者提交有效的憑證
- 則呈現一個 OTP 挑戰
- 且僅在提供有效的 OTP 後才完成登入
## 修改需求
### 需求:Session 過期
系統必須在 Session 閒置 15 分鐘後使其過期。
(先前:30 分鐘)
#### 場景:閒置逾時
- 給定一個已認證的 Session
- 當 15 分鐘無活動過去
- 則該 Session 被失效
## 移除需求
### 需求:記住我
(已棄用,改為使用 2FA。使用者應在每次 Session 重新認證。)增量章節
| 章節 | 含義 | 封存時發生什麼 |
|---|---|---|
## 新增需求 | 新行為 | 附加至主規格 |
## 修改需求 | 已變更行為 | 替換現有需求 |
## 移除需求 | 已棄用行為 | 從主規格中刪除 |
為何使用增量而非完整規格
清晰度。 增量精確地顯示了正在變更的內容。閱讀完整規格時,你必須在腦中與當前版本進行差異比對。
避免衝突。 兩個變更可以觸及同一個規格檔而不衝突,只要它們修改的是不同的需求。
審查效率。 審查者看到的是變更,而非未變更的上下文。專注於重要的部分。
適合既有系統。 大部分工作是修改現有行為。增量使修改成為一等公民,而非事後才考慮。
結構描述
結構描述定義了工作流程的產物類型及其依賴關係。
結構描述如何運作
yaml
# openspec/schemas/spec-driven/schema.yaml
name: spec-driven
artifacts:
- id: proposal
generates: proposal.md
requires: [] # 無依賴,可首先建立
- id: specs
generates: specs/**/*.md
requires: [proposal] # 需要先有提案才能建立
- id: design
generates: design.md
requires: [proposal] # 可與規格平行建立
- id: tasks
generates: tasks.md
requires: [specs, design] # 需要先有規格和設計產物形成一個依賴圖:
proposal
(根節點)
│
┌─────────────┴─────────────┐
│ │
▼ ▼
specs design
(requires: (requires:
proposal) proposal)
│ │
└─────────────┬─────────────┘
│
▼
tasks
(requires:
specs, design)依賴是促成因素,而非關卡。 它們顯示了可以建立什麼,而非你必須接下來建立什麼。如果你不需要設計,可以跳過它。你可以在設計之前或之後建立規格——兩者都只依賴於提案。
內建結構描述
spec-driven(預設)
規格驅動開發的標準工作流程:
proposal → specs → design → tasks → implement適用於:大多數功能開發,你希望在實作前就規格達成共識。
自訂結構描述
為你的團隊工作流程建立自訂結構描述:
bash
# 從頭建立
openspec schema init research-first
# 或從現有結構描述分叉
openspec schema fork spec-driven research-first自訂結構描述範例:
yaml
# openspec/schemas/research-first/schema.yaml
name: research-first
artifacts:
- id: research
generates: research.md
requires: [] # 先進行研究
- id: proposal
generates: proposal.md
requires: [research] # 提案基於研究結果
- id: tasks
generates: tasks.md
requires: [proposal] # 跳過規格/設計,直接進入任務詳見 自訂 以了解建立和使用自訂結構描述的完整細節。
封存
封存透過將其增量規格合併到主規格中,並保留變更以供歷史記錄,從而完成一個變更。
封存時發生什麼
封存前:
openspec/
├── specs/
│ └── auth/
│ └── spec.md ◄────────────────┐
└── changes/ │
└── add-2fa/ │
├── proposal.md │
├── design.md │ 合併
├── tasks.md │
└── specs/ │
└── auth/ │
└── spec.md ─────────┘
封存後:
openspec/
├── specs/
│ └── auth/
│ └── spec.md # 現在包含 2FA 需求
└── changes/
└── archive/
└── 2025-01-24-add-2fa/ # 保留以供歷史記錄
├── proposal.md
├── design.md
├── tasks.md
└── specs/
└── auth/
└── spec.md封存流程
合併增量。 每個增量規格章節(新增/修改/移除)都套用到對應的主規格。
移至封存。 變更資料夾移至
changes/archive/,並加上日期前綴以便按時間順序排列。保留上下文。 所有產物在封存中保持完整。你隨時可以回顧以了解為何做出某個變更。
為何封存很重要
乾淨的狀態。 活動變更 (changes/) 僅顯示進行中的工作。已完成的工作會移開。
審計軌跡。 封存保留了每個變更的完整上下文——不僅是變更了什麼,還有解釋為何變更的提案、解釋如何變更的設計,以及顯示已完成工作的任務。
規格演進。 隨著變更被封存,規格有機地成長。每次封存都合併其增量,隨時間建立起全面的規格。
整體如何運作
┌──────────────────────────────────────────────────────────────────────────────┐
│ OPENSPEC 流程 │
│ │
│ ┌────────────────┐ │
│ │ 1. 開始 │ /opsx:propose (核心) 或 /opsx:new (擴展) │
│ │ 變更 │ │
│ └───────┬────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────┐ │
│ │ 2. 建立 │ /opsx:ff 或 /opsx:continue (擴展工作流程) │
│ │ 產物 │ 建立提案 → 規格 → 設計 → 任務 │
│ │ │ (基於結構描述依賴) │
│ └───────┬────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────┐ │
│ │ 3. 實作 │ /opsx:apply │
│ │ 任務 │ 逐步完成任務,並將其核銷 │
│ │ │◄──── 隨著你的了解更新產物 │
│ └───────┬────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────┐ │
│ │ 4. 驗證 │ /opsx:verify (可選) │
│ │ 工作 │ 檢查實作是否符合規格 │
│ └───────┬────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────┐ ┌──────────────────────────────────────────────┐ │
│ │ 5. 封存 │────►│ 增量規格合併到主規格 │ │
│ │ 變更 │ │ 變更資料夾移至 archive/ │ │
│ └────────────────┘ │ 規格現在是更新後的真實來源 │ │
│ └──────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────────────────┘良性循環:
- 規格描述當前行為
- 變更提出修改建議(以增量形式)
- 實作使變更成為現實
- 封存將增量合併到規格中
- 規格現在描述新的行為
- 下一個變更基於更新的規格建立
術語表
| 術語 | 定義 |
|---|---|
| Artifact | 變更中的一份文件(提案、設計、任務或差異規格) |
| Archive | 完成變更並將其差異合併至主規格的過程 |
| Change | 對系統的建議修改,以包含多個 artifact 的資料夾形式封裝 |
| Delta spec | 描述相對於當前規格之變更(新增/修改/移除)的規格 |
| Domain | 規格的邏輯分組(例如 auth/、payments/) |
| Requirement | 系統必須具備的特定行為 |
| Scenario | 需求的具體範例,通常採用 Given/When/Then 格式 |
| Schema | Artifact 類型及其依賴關係的定義 |
| Spec | 描述系統行為的規格,包含需求與情境 |
| Source of truth | openspec/specs/ 目錄,包含當前已達成共識的行為規範 |