# OpenSpec 讓 SDD 變簡單的三個指令

> OpenSpec 是一款輕量級的規格驅動開發工具，專為在現有專案中導入規格而設計，支持多種 AI 工具，適合進行漸進式開發。透過簡單的三步驟流程，讓開發者能快速建立與管理專案規格，提升工作效率。

Published: 2026-01-15
URL: https://kaochenlong.com/openspec

---

在[前一篇文章](/sdd-spec-driven-development)我們介紹了 SDD（Spec-Driven Development）的方法論，簡單的說，SDD 的重點就是在寫程式之前先把「規格」定義清楚，讓我們跟 AI 對「什麼叫做完成」有共同的認知，這樣到時候做出來的東西才不會雞同鴨講。

雖然方法論介紹完了，但從理論到實務的 Gap 其實不小，如果要自己手寫規格可能有點辛苦，對新手來說一開始可能也不知道怎麼下手。還好有很多厲害的大大幫我們做了方便的工具，讓我們可以透過幾個簡單的指令就能建立規格並套用在專案裡面。

同樣在上篇文章裡提到了幾個 SDD 工具，像是 Amazon 的 [Kiro](https://kiro.dev/)、GitHub 的 [Spec Kit](https://github.com/github/spec-kit)、[Tessl](https://tessl.io/)，還有一個叫 [OpenSpec](https://github.com/Fission-AI/OpenSpec) 的輕量級工具。這篇文章要介紹的就是 OpenSpec，在我看來它可能是目前最容易上手、最適合在現有專案導入的 SDD 工具，我自己現在也每天都在用它。

怕內容太長大家沒耐心看完，基本上 OpenSpec 就三招：`proposal` → `apply` → `archive`

:::tip 貼心小提醒

1. 本文推薦的 OpenSpec 不一定適合每個人，請依照自己的需求和情境做選擇。
2. 目前 OpenSpec 已更新至 1.0 版本，指令跟使用方式不太一樣，請見[另一篇文章](https://kaochenlong.com/spectra-with-openspec)的說明

:::

## 為什麼是 OpenSpec？

再提醒一次，選擇工具之前，一定要先確定目前自己的情況，不要因為我跟你說好用就跟著用，同時也要知道自己在用工具解決什麼問題。

如果是一個全新的專案，從零開始規劃架構，Kiro 或 Spec Kit 可能會是不錯的選擇。它們的流程比較完整，從需求到設計到實作都有對應的文件結構，適合在專案一開始就建立好規範。但現實情況是大多數我們的工作都不是從零開始，而是在現有系統上加功能、改行為、修 bug。這種已經有一堆程式碼的專案，我們要在這片「褐色的田地（Brownfield）」上繼續耕作。

OpenSpec 的設計理念就是 brownfield-first。它不只適合 0 到 1 的新專案，更適合 1 到 n 的持續開發。它能把「目前系統長什麼樣子」和「我們想要做什麼改變」分開管理，讓每次變更的範圍都很清楚。

先說，並不是 Spec Kit 不好，剛好相反，是它對我來說可能「太好」了。很多時候我只是要修個小功能，Spec Kit 還是很熱心的幫我建立一大堆文件，有種只是想修一顆螺絲卻要寫十幾頁報告的感覺，這也是我選擇 OpenSpec 的原因之一。OpenSpec 不需要 API key，不需要連接雲端服務，所有東西都是 Markdown 檔案，產出的文件不會像 Spec Kit 那麼驚人，檔案都會放在專案的特定目錄裡。安裝完就能用，沒有什麼複雜的設定。

OpenSpec 支援的 AI 工具很廣，OpenAI Codex、Claude Code、Cursor、GitHub Copilot、Gemini CLI 這些主流工具都有支援。如果我們用的工具不在支援清單裡，它也提供 `AGENTS.md` 的方式，讓任何能讀取檔案的 AI 工具都能理解 OpenSpec 的工作流程。

:::info 文章推薦

對 Spec Kit 有興趣的，可參閱朋友們寫的文章：

- Cash [Github spec-kit 初體驗](https://blog.cashwu.com/blog/2025/github-spec-kit-first-experience)
- 奶綠茶 [AI 時代，一定要學會使用 GitHub spec kit — SDD 規格驅動開發](https://milkmidi.medium.com/ai-%E6%99%82%E4%BB%A3-%E4%B8%80%E5%AE%9A%E8%A6%81%E5%AD%B8%E6%9C%83%E4%BD%BF%E7%94%A8-github-spec-kit-sdd-%E8%A6%8F%E6%A0%BC%E9%A9%85%E5%8B%95%E9%96%8B%E7%99%BC-f2df57cfdf3c)
- Muki [Spec Kit 基本功能介紹和 BMAD-Method 的比較](https://muki.tw/spec-kit-and-bmad-method-different/)

:::

## 在既有系統上的價值

在上一篇文章提到 SDD 適合的三種場景，分別是全新專案、探索性開發、以及漸進式改進。就我實際開發專案的經驗來說，漸進式改進可能是 SDD 最能發揮價值的地方。

為什麼？因為既有系統通常有很多隱藏或是前人留下來的「資產」，這些東西不一定寫在文件裡，可能只存在於某個資深工程師的腦袋中，或是散落在各種 commit message 和 PR 討論裡。如果我們直接跟 AI 說「幫我加一個新功能」，AI 不知道這些脈絡，很容易改壞其他地方。改壞了直接噴個 HTTP 500 還算好處理，最怕的是改了之後看起來能動，但其實破壞了某個我們沒注意到的隱性規則。

OpenSpec 的 `specs` 和 `changes` 分離設計就是為了處理這個問題。`specs` 目錄裡面放的是「目前系統的真相」，也就是已經實作完成、部署上線的功能規格。`changes` 目錄則是「我們想要做的變更」。當我們建立一個提案的時候，它會要求我們列出 Affected specs 和 Affected code。雖然這個動作看起來只是在填表格，但其實是在強迫我們思考「這次變更會影響什麼」。如果我們自己都列不出來，AI 更不可能知道。

不過 Brownfield 場景有個前提，就是我們得先有 `specs` 可以錨定。如果現有系統本來就沒有規格文件，我們得先花一點時間把現有行為記錄下來，這是一開始的導入成本。比較務實的做法是漸進式導入，先從新功能開始建立 `specs`，慢慢累積，而不是一開始就想把整個系統的規格都補齊，事實上想要一開始就想把規格補齊也不切實際。

## 安裝與初始化

OpenSpec 是一個 npm 套件，所以安裝方式很簡單（我假設你看到這裡應該知道怎麼安裝 Node.js），只要一行就搞定：

```bash
npm install -g @fission-ai/openspec@latest
```

安裝完之後，可以用 `openspec --version` 確認版本。接著切換到專案目錄，執行第一次的初始化：

```bash
cd my-project
openspec init
```

執行之後會看到這個畫面：

&lt;img src=&quot;/rails/active_storage/representations/proxy/eyJfcmFpbHMiOnsiZGF0YSI6MjY2OSwicHVyIjoiYmxvYl9pZCJ9fQ==--53c0cc258ea36fc82dfab011f05c37f0f5236e4e/eyJfcmFpbHMiOnsiZGF0YSI6eyJmb3JtYXQiOiJ3ZWJwIiwicmVzaXplX3RvX2xpbWl0IjpbMTI4MCwxMDI0XX0sInB1ciI6InZhcmlhdGlvbiJ9fQ==--84d8884f224e8330b83a950151768b773558b857/openspec-title.png&quot; width=&quot;75%&quot;&gt;

第一次初始化會問我們在用哪些 AI 工具。選完之後，OpenSpec 會自動幫我們設定好對應的指令（Slash Command）。本篇文章我使用 Claude Code 做為示範，但其它的工具也是類似的流程。選完使用的工具之後別急著開始，仔細看，OpenSpec 會提醒你把一小段文字要請你貼到你的 Coding Agent 裡：

```
1. Populate your project context:
   &quot;Please read openspec/project.md and help me fill it out
    with details about my project, tech stack, and conventions&quot;

2. Create your first change proposal:
   &quot;I want to add [YOUR FEATURE HERE]. Please create an
    OpenSpec change proposal for this feature&quot;

3. Learn the OpenSpec workflow:
   &quot;Please explain the OpenSpec workflow from openspec/AGENTS.md
    and how I should work with you on this project&quot;
```

這段內容主要是讓 AI 了解專案背景，這會在 `CLAUDE.md` 或 `AGENTS.md` 生成一小段提示詞，讓你正在使用的 Coding Agent 知道 OpenSpec 的工作流程長什麼樣子或是應該怎麼生成提案。所以怎麼做？很簡單，就打開你的 Coding Agent，然後把這段提示詞貼給它就行了。

現在專案的結構大概長這樣：

```plaintext
├── AGENTS.md
├── CLAUDE.md
└── openspec
    ├── AGENTS.md     # 給 AI 讀的工作流程說明
    ├── changes       # 變更提案
    │   └── archive   # 已完成的變更
    ├── project.md    # 專案的基本資訊、開發用的技術和慣例
    └── specs         # 目前系統的規格（真相的來源）
```

特別關注一下 `openspec` 目錄，這是 OpenSpec 的重點。`openspec/project.md` 裡面可以填寫專案的技術棧、寫作慣例、重要限制等等資訊，讓 AI 在建立提案的時候能參考這些脈絡。`openspec/specs/` 目錄則是放目前系統的規格文件。初始化完成後並且把該填的資料填好，之後 AI 在幫我們建立提案的時候，就會參考這些脈絡，產出更貼近專案風格的內容。

整個 `openspec` 目錄都應該進版控。`specs` 是系統的真相來源，`changes` 讓團隊成員看到進行中的提案，`archive` 則保留變更歷史。如果不進版控，後面提到的「多人協作」和「歷史紀錄保留」就沒有意義了。

## 三階段工作流程

OpenSpec 的工作流程分成三個階段，每個階段都有對應的指令

### Stage 1：Draft Proposal（草擬提案）

當我們想要新增功能、做破壞性變更、或是改動架構的時候，第一步是建立一個變更提案。觸發方式有幾種。如果用的是 Claude Code，可以直接輸入：

```
/openspec:proposal 新增使用者搜尋功能
```

如果用的工具不支援這些指令的話，也可以用自然語言：

```
幫我建立一個 OpenSpec 提案，我想新增使用者搜尋功能
```

AI 會在 `openspec/changes/` 底下建立一個新的目錄，裡面包含這些檔案：

- `proposal.md` 說明這次變更的原因和影響範圍，格式包含 Why、What Changes、Impact 三個區塊。
- `tasks.md` 則是實作的待辦清單，會用 checkbox 格式列出每個步驟。
- `specs/` 子目錄，裡面放的是這次變更會影響到的規格差異，這個等一下會詳細說明。

提案建立完之後，記得執行驗證：

```bash
openspec validate add-user-search --strict
```

為什麼要驗證？因為 AI 不是總是那麼乖，生成的規格有時候不一定有符合 OpenSpec 的格式要求。驗證會檢查每個需求是否都有對應的 Scenario、需求描述是否包含 `SHALL` 或 `MUST` 關鍵字、Delta 格式是否正確等等。如果現在不抓出格式問題，等到歸檔的時候才發現規格合併失敗，那就比較麻煩了。

### Stage 2：Implement（實作）

提案確認沒問題之後，就可以開始實作了：

```
/openspec:apply add-user-search
```

這時候 AI 會讀取 `proposal.md` 和 `tasks.md`，然後按照任務清單一個一個完成。每完成一個任務，它會把 `- [ ]` 改成 `- [x]`，這樣我們隨時都能看到進度。這個階段的重點是 AI 的實作必須符合 `proposal.md` 裡定義的範圍。如果它想做一些規格裡沒寫的東西，我們可以提醒它「這不在提案範圍內，請專注在 `tasks.md` 列出的項目。」

這就是 SDD 的核心價值。因為規格是在實作之前就寫好的，所以我們有一個明確的標準來驗收 AI 的產出。不會像 Vibe Coding 那麼隨意，做到一半才發現 AI 理解的需求跟我們想的不一樣。

如果實作到一半發現規格有問題怎麼辦？沒關係，在歸檔之前都還可以調整。直接修改 `proposal.md`、`tasks.md` 或 `specs/` 下的檔案，改完再跑一次 `openspec validate` 確認格式正確，然後繼續實作就好。這也是 `specs` 和 `changes` 分離設計的好處：在歸檔之前都還有調整空間。不會改怎麼辦？可以跟 AI 用自然語言講，它可以幫你改，我大部份時候也都是這樣做的。

### Stage 3：Archive（歸檔）

所有任務都完成、測試也通過之後，最後一步是歸檔：

```
/openspec:archive add-user-search
```

歸檔會做兩件事。首先會把 `changes/add-user-search/` 這整個目錄移到 `changes/archive/` 底下，並且在目錄名稱前面加上日期，變成類似 `2026-01-15-add-user-search/` 這樣的格式。然後把這次變更的規格差異合併回 `specs` 目錄。這樣一來，在 `specs` 目錄裡面永遠是系統目前應該有的行為，而 `archive` 裡面則保留了每次變更的歷史紀錄。

## specs 和 changes 的分離設計

前面提過 `specs` 和 `changes` 的分離設計如何幫助我們在既有系統上工作。除了釐清變更邊界之外，這個設計還帶來幾個好處。

1. 變更範圍一目瞭然。每次變更會影響哪些功能，直接看 `changes/[name]/specs/` 裡面有哪些檔案就知道了。不用去猜、不用去追 git diff。
2. 多人協作更順暢。如果兩個人同時在做不同的功能，他們的提案會在不同的 `changes` 子目錄裡。只要影響的 `specs` 不重疊，就不會互相踩到。
3. 歷史紀錄完整保留。每次變更歸檔之後都會留在 `archive` 裡面。也許過了三個月有人問「當初為什麼要加這個功能」，我們可以直接去 `archive` 裡面找當時的 `proposal.md` 來看。

### 不需要建立提案的情況

是說，不是所有改動都需要走完整的 OpenSpec 流程，以下情況可以直接改程式碼：

1. 修 bug。修 bug 是讓程式碼符合規格，不是改變規格，所以不需要建立提案。例如規格寫「登入失敗應回傳 401」，但程式實際回傳 500，這就是 bug，修正它是讓程式符合規格。當然，如果修復方式比較複雜或想留下決策紀錄，開 proposal 也沒問題。
2. 修錯字、調整格式、改註解。這些改動不影響系統行為，不需要走 SDD 流程。
3. 更新依賴套件（非破壞性）。只要不是 breaking change，更新套件版本不需要建立提案。
4. 調整設定。只要設定的改動不會改變系統的行為規格，就不需要。
5. 新增現有行為的測試。規格已經定義了行為，補上測試只是驗證實作正確，不需要改規格。

簡單來說，判斷標準就是這次改動會不會讓系統的行為跟 `specs` 裡面定義的不一樣。如果會，就需要建立提案。如果不會，直接動手改就好。

### 常用指令

OpenSpec 的指令不多，整理幾個常用的：

- `openspec list` 列出目前所有進行中的變更。可以加 `--specs` 參數來列出現有的規格。
- `openspec show [name]` 顯示某個變更或規格的詳細內容。可以加 `--json` 來取得 JSON 格式的輸出，方便程式處理。
- `openspec validate [name]` 驗證某個變更的格式是否正確。建議加上 `--strict` 參數做更完整的檢查。
- `openspec archive [name]` 歸檔某個已完成的變更。可以加 `--yes` 跳過確認提示，在自動化流程裡特別好用。
- `openspec view` 開啟互動式的 dashboard，可以瀏覽所有 specs 和 changes。

如果驗證失敗，可以用 `openspec show [name] --json --deltas-only` 來看 Delta 的解析結果，找出格式錯誤在哪裡。

其實看到這裡你就可以開始試著用看看 OpenSpec 了，不過如果你對其它細節有興趣的話可以再往下看...

## 規格的規格

接著我們來細看一下 `spec.md` 的格式。這是 OpenSpec 最重要的檔案類型，也是最容易出錯的地方。一個典型的 `spec.md` 大概會長這樣：

```markdown
# User Authentication Specification

## Purpose

管理使用者的身份驗證和 Session。

## Requirements

### Requirement: User Login

使用者 SHALL 能夠使用 Email 和密碼登入系統。

#### Scenario: 登入成功

- WHEN 使用者輸入正確的 Email 和密碼
- THEN 系統回傳 JWT token
- AND 記錄登入時間

#### Scenario: 密碼錯誤

- WHEN 使用者輸入錯誤的密碼
- THEN 系統回傳 401 錯誤
- AND 增加失敗次數記錄
```

幾個格式上的重點：

1. 每個 Requirement 都必須至少有一個 Scenario。這是 OpenSpec 的規則，驗證的時候會檢查。沒有 Scenario 的需求等於沒有驗收標準，實作的時候就會有模糊空間。
2. Scenario 必須用 `####` 開頭。這是很容易搞混的地方，有些時候 AI 會寫成 `- **Scenario: xxx**` 或是 `### Scenario: xxx`，這些格式都不對，後續驗證會失敗。
3. 需求描述使用 `SHALL` 或 `MUST`。這是從 [RFC 2119](https://www.rfc-editor.org/rfc/rfc2119) 借來的慣例，`SHALL` 表示「必須這樣做」，`SHOULD` 表示「建議這樣做」，`MAY` 表示「可以這樣做」。在 OpenSpec 裡面通常用 `SHALL` 或 `MUST` 來表達規範性的需求。

### 變更提案裡的 Delta 格式

當我們建立變更提案的時候，`changes/[name]/specs/` 底下的檔案不是寫完整的規格，而是寫「跟現有規格相比，這次要改什麼」。這種只描述差異的格式叫做 Delta，用 `## ADDED`、`## MODIFIED`、`## REMOVED` 這樣的標題來標記每個變更是新增、修改還是刪除。例如我加了一個想要做二階段驗證的功能：

```markdown
## ADDED Requirements

### Requirement: Two-Factor Authentication

使用者 MUST 在登入時提供第二因素驗證。

#### Scenario: OTP 驗證

- WHEN 使用者輸入正確的密碼
- THEN 系統要求輸入 OTP
  ... 略 ...

## MODIFIED Requirements

### Requirement: User Login

（這裡放完整修改後的需求內容，包含所有 Scenario）

## REMOVED Requirements

### Requirement: Password Reset via Email

**Reason**: 改用更安全的驗證方式
**Migration**: 改用 SMS 驗證
```

四種操作的意思很直接。`ADDED` 是新增的需求，`MODIFIED` 是修改現有需求，`REMOVED` 是移除需求，`RENAMED` 則是重新命名需求。特別要注意 `MODIFIED`。如果我們要修改一個現有需求，必須把修改後的完整內容貼上去，包含所有的 Scenario。OpenSpec 在歸檔的時候會用我們提供的內容整個取代原本的需求，如果只寫差異的部分，原本的內容就會不見。

### 什麼時候需要 design.md？

在三個核心檔案（`proposal.md`、`tasks.md`、`specs/`）之外，OpenSpec 還支援一個選用的 `design.md`。這個檔案用來記錄技術決策，適合在以下情況使用：

- 跨系統或跨模組的變更。如果這次變更會影響多個服務或模組，`design.md` 可以說明它們之間如何互動。
- 引入新的外部依賴。如果我們要用一個新的套件或服務，`design.md` 可以解釋為什麼選擇它、考慮過哪些替代方案。
- 有安全性或效能考量。如果這次變更涉及敏感資料或需要特別注意效能，`design.md` 可以記錄我們的策略。
- 需要 migration。如果這次變更會影響現有資料或需要停機部署，`design.md` 可以說明 migration 計畫。

`design.md` 的格式大概是這樣：

```markdown
## Context

（背景說明、相關的系統脈絡）

## Goals / Non-Goals

- Goals: ...
- Non-Goals: ...

## Decisions

- 決定使用 Redis 做 cache
- 理由：比 Memcached 更適合我們的使用場景

## Risks / Trade-offs

... 略 ...

## Migration Plan

... 略 ...
```

如果變更比較簡單，沒有複雜的技術決策要做，`design.md` 可以省略。OpenSpec 不會強制要求這個檔案存在。

### 一次變更影響多個 Specs

有時候一個變更會影響到多個功能領域。比如說新增雙因素認證，可能同時影響 auth 和 notifications 兩個 specs。這種情況下，`changes` 底下的 `specs/` 目錄會有多個子目錄：

```
openspec/changes/add-2fa/
├── proposal.md
├── tasks.md
└── specs/
    ├── auth/
    │   └── spec.md       # 雙因素認證的需求
    └── notifications/
        └── spec.md       # OTP 通知的需求
```

`auth/spec.md` 負責定義雙因素認證的需求，`notifications/spec.md` 則定義 OTP 發送的規格。兩個檔案各自獨立，但透過同一個 proposal 管理。歸檔的時候，OpenSpec 會把這兩個 Delta 分別合併到對應的 `specs` 目錄裡。如果 `specs/auth/spec.md` 或 `specs/notifications/spec.md` 原本不存在會自動幫我們建立一個。

## 小結

如果我們已經有在用 Coding Agent 工具，導入 OpenSpec 的成本滿低的，裝一下 npm 套件、跑第一次的初始化再填一下 `project.md`，然後就可以開始用了。

下次要新增功能的時候，試試看不要只跟 AI 說「幫我做一個 XX 功能」，改成用 `/openspec:proposal 新增 XX 功能`。因為初始化時已經設定好提示詞，AI 會知道要照 OpenSpec 的格式建立提案，加上 Coding Agent 現在越來越厲害，在建立提案的過程還會一直跟使用者進行提問互動，讓我們確認過規格之後再開始實作。

一開始可能會覺得這樣做比較花時間，畢竟多了一個步驟，要先寫規格再寫程式。但用過幾次之後就會發現前面花的時間會在後面省回來。因為規格清楚了，AI 比較不會做錯方向；因為有驗收標準，我們知道什麼時候算「完成」；因為有歷史紀錄，以後維護的人知道當初為什麼這樣設計。就算 AI 把功能做歪了，我們也可以回到修改前的狀況，重新再來一次，或是換另一個 Coding Agent 來做也行。

使用 SDD 的目的不是要讓開發變得更繁瑣，而是要讓我們跟 AI 的協作更可靠、更有可預測性。OpenSpec 提供了一個簡單易用的框架，讓我們可以在現有專案中逐步導入 SDD，享受它帶來的好處 :)

