•
OpenSpec 深度解析:把「規格」從聊天記錄裡救出來的 SDD 框架
19 分鐘閱讀 •

我之前在研究 SDD(Spec-Driven Development)時,核心觀點是「脈絡決定 AI 輸出品質」。那篇筆記從宏觀角度談了規格驅動開發的理念和流程。但這次讀完 OpenSpec 的完整研究報告後,我發現了一個更基礎的問題:當你用 AI coding assistant 寫程式時,需求到底存在哪裡?
答案通常是:散落在聊天記錄裡。
OpenSpec 要解決的就是這件事。它把需求從 chat history 搬進 repo,讓規格變成可審查、可追溯、可驗證的工程產出物(artifacts)。這篇文章會深入拆解 OpenSpec 的設計、實務痛點、以及它在整個 SDD 工具生態系中的位置。
上面提及的「脈絡決定 AI 輸出品質」那一篇文章是來自她的個人研究知識庫,沒有公開發佈。
OpenSpec 是什麼:三層架構拆解
OpenSpec 是 Fission AI 開發的開源 spec-driven development 框架,MIT License,GitHub 上有 25.6k 星。官方把自己定位為「lightweight、universal、open source、無需 API keys」的 framework,強調四個設計理念:fluid(流動)、iterative(迭代)、easy(簡單)、brownfield-first(優先處理既有專案)。
它的架構可以拆成三層來理解。
第一層是 CLI 工具。 用 TypeScript/ESM 打包,需要 Node.js 20.19.0+,提供 init、validate、status、archive 等指令。CLI 支援 JSON 輸出,方便 CI 腳本消費。值得注意的是它用了 PostHog 做匿名使用統計,這在企業內網環境造成了一些問題(後面會詳細談)。
第二層是 repo 內的資料夾結構。 初始化後建立 openspec/specs/(系統目前行為的真相來源)和 openspec/changes/(變更提案與差異),加上可選的 openspec/config.yaml(專案級 context、rules 和 schema 預設)。這個設計的關鍵在於 specs 和 changes 的分離:前者代表「系統現在長什麼樣」,後者代表「我想改成什麼樣」。
第三層是 OPSX(artifact-guided workflow)。 這是我認為最有意思的部分。它把工作流的定義從「寫死在程式碼裡」移到 schema.yaml + templates。你可以 fork 內建 schema,自訂 artifacts 的種類、依賴關係、輸出路徑和模板內容,然後 version control 在 openspec/schemas/ 裡。工作流隨團隊演進,不需要等工具本身更新。
your-project/
└── openspec/
├── specs/ # 真相來源:系統目前的行為
│ └── <domain>/
│ └── spec.md
├── changes/ # 變更提案:一個變更一個資料夾
│ └── <change-name>/
│ ├── proposal.md # Why / What
│ ├── design.md # How(SDD 文件)
│ ├── tasks.md # 可追蹤的實作清單
│ └── specs/ # Delta specs
│ └── <domain>/
│ └── spec.md
└── config.yaml # 專案級設定Delta Specs:OpenSpec 最聰明的設計
如果只能挑一個功能來說服你看下去,我選 Delta Specs。
傳統的規格管理有一個致命問題:brownfield 專案(也就是幾乎所有真實世界的專案)的變更本質是增量的。你不會每次改一個 API 就重寫整份 500 行的 spec。但如果不重寫,reviewer 就得在心裡 diff 兩份完整文件,才能搞清楚到底改了什麼。
OpenSpec 的解法是 Delta Specs:用 ADDED、MODIFIED、REMOVED、RENAMED 四種標記描述規格的差異。
## ADDED Requirements
### Requirement: 搜尋使用者
系統 SHALL 提供使用者搜尋 API,
支援以 email 前綴查詢,並以分頁回傳結果。
#### Scenario: 以 email 前綴搜尋
- **WHEN** 呼叫 GET /v1/users?emailPrefix=ali&page=1&pageSize=20
- **THEN** 回傳 200,且 items 內每筆 user.email 皆以 "ali" 開頭
## MODIFIED Requirements
### Requirement: Session Expiration
系統 MUST 在閒置 15 分鐘後過期 session。
## REMOVED Requirements
### Requirement: Remember Me
Reason: 已棄用,改為 2FA
Migration: 用戶需重新設定雙因素驗證Requirement 使用 RFC 2119(SHALL/MUST 等)關鍵字表達規範性要求,Scenario 用 When/Then 描述可驗證的行為。這個格式介於自然語言和 formal specification 之間:比口語精確,但比 TLA+ 好讀。
archive/sync 操作會把 delta specs 根據 ADDED/MODIFIED/REMOVED 的規則合併回主 specs,然後把 change folder 移到 openspec/changes/archive/ 保留歷史。reviewer 一眼就能看到「到底改了什麼」。
工作流程:動作而非階段
OpenSpec 的工作流程有一個核心概念值得特別強調:「動作而非階段」(actions not phases)。
傳統的開發流程用階段 gate 管控:需求分析 → 設計 → 實作 → 測試,每個階段有明確的進入和退出條件。OpenSpec 刻意不這樣做。它用依賴關係描述「什麼已就緒、什麼可做」,但不鎖死順序。你可以先寫 design 再寫 specs,或反過來。
最小路徑(core profile)只需要三步:
/opsx:propose "add-dark-mode" → 建立 change 資料夾,產生所有 artifacts
/opsx:apply → 按 tasks 實作
/opsx:archive → 合併 delta specs 到主 specs,封存expanded workflow 則提供更多動作:/opsx:new、/opsx:continue、/opsx:ff、/opsx:verify、/opsx:sync 等,但這些都是選用的。
這個依賴圖來自 OpenSpec 的 schema 定義。注意 proposal 同時指向 delta specs 和 design,而兩者都指向 tasks。這代表你可以平行處理 specs 和 design,只要在寫 tasks 之前兩者都就緒即可。
SDD 文件(design.md):不是每次都需要寫
OpenSpec 的 design.md 被定義為描述「how」的技術設計文件。schema 建議的段落包含 Context、Goals/Non-Goals、Decisions(含 alternatives)、Risks/Trade-offs、Migration Plan、Open Questions。
但 schema 同時明確指出:不是每個變更都需要 design.md。 建議在以下條件才寫得更完整:跨模組變更、外部依賴、安全/效能考量、遷移複雜度高。對於簡單的 API 新增或 bug fix,一份精簡的 proposal + delta specs + tasks 就足夠了。
這個設計選擇反映了 OpenSpec 的哲學:工具應該適應團隊,而不是團隊適應工具。
驗證機制:結構化 + 實作對齊
OpenSpec 把驗證拆成兩個層次。
第一層是結構化規格檢查:openspec validate 驗證 change/spec 的結構與格式是否符合 schema。支援 --strict、--all、--json 與 concurrency 設定,適合放進 CI 當 gate。
name: openspec-validate
on:
pull_request:
paths:
- "openspec/**"
jobs:
validate:
runs-on: ubuntu-latest
env:
OPENSPEC_TELEMETRY: "0"
DO_NOT_TRACK: "1"
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "20"
- run: npm install -g @fission-ai/openspec@latest
- run: openspec validate --all --strict --json第二層是實作對齊檢查:/opsx:verify 把 completeness/correctness/coherence 三個維度的結果整理成報告,以 warning/suggestion 呈現。這一層偏向 agent 檢查,不一定阻擋 archive。
Scenario 在 schema 中被直接描述為「each scenario is a potential test case」,但 OpenSpec CLI 並沒有內建「產生或執行測試」的命令。測試的產生仍然是人類或 AI coding assistant 的工作,OpenSpec 提供的是可測試的規格來源。
現實中的痛點:Issue 考古
任何 framework 的真實面貌不在 README,在 issue tracker。研究報告裡提到了幾個值得關注的問題。
Issue #754:企業內網的 PostHog 問題
Issue #754 指出 openspec init 在封閉企業網路會因為送 PostHog metrics 失敗而直接報錯。官方提供了 OPENSPEC_TELEMETRY=0 的 opt-out,CLI 也宣稱在 CI 內自動停用,但 init 時的例外處理不夠 graceful。
我的觀點:telemetry 是合理的(了解使用模式幫助改進產品),但「metrics 送不出去 → 程式崩潰」這種設計在任何 production-ready 的工具裡都不應該發生。先做 fail-safe,再談 metrics。
Issue #709:Archive 破壞 Git History
Issue #709 指出 archive 操作用「刪除再新建」取代 git mv,導致 git history 斷裂,PR diff 充滿純移動變更。
對一個把「可追溯性」當核心賣點的工具來說,這個問題頗為諷刺。你在 spec 層面建立了完美的 audit trail,結果在 git 層面把 history 搞斷了。在重視追溯性的團隊,導入時建議把「archive 後 specs 的 git history 是否保留」列為驗收項目。
Issue #243 / PR #284:非英文 Spec 的 RFC 2119 問題
Issue #243 指出 validate 強制要求 RFC 2119 關鍵字(SHALL/MUST 等),但非英文語系的 spec 作者(比如用正體中文寫 spec 的團隊)沒辦法自然地使用這些英文關鍵字。PR #284 嘗試將此驗證從 ERROR 降級為 WARNING,但最終被關閉而未合併。維護者表示「新的工作流程已經不再有此驗證」。
實際情況比較微妙。我去讀了目前 main 上的 validator.ts 原始碼,發現 OPSX 重構(v1.0.0)後驗證行為出現了分歧:
- 主規格驗證(
openspec validate --specs):applySpecRules()中已無 SHALL/MUST 檢查,非英文 spec 可以正常通過 - Delta spec 驗證(
openspec validate --changes):validateChangeDeltaSpecs()中仍然以 ERROR 等級強制要求 SHALL/MUST
也就是說,如果你的團隊用母語寫 delta specs 且完全不含 SHALL/MUST 關鍵字,openspec validate --changes 仍然會報錯。實務上的解法是在母語文件中嵌入英文 RFC 2119 關鍵字(例如「系統 SHALL 提供...」),這也是 OpenSpec 官方 schema 的建議寫法。Issue #243 截至本文發布時仍處於開啟狀態。
這觸及了一個更深層的問題:「規格的語言」。RFC 2119 的精確性確實有價值,但 spec 的可讀性和團隊的接受度同樣重要。一個團隊如果不得不在母語文件中硬插英文關鍵字,那這份 spec 對他們來說就不是「可讀的行為契約」,而是需要翻譯的官僚文件。
競爭者地圖:OpenSpec 的位置在哪
SDD 工具生態系比大多數人想像的更熱鬧。以下是主要框架的比較。
OpenSpec vs. GitHub Spec Kit
GitHub Spec Kit 有 71.9k 星,比 OpenSpec 更重量級。核心差異在於 Spec Kit 使用 Constitution 驅動設計(一份 constitution.md 定義不可違反的架構原則),並且有嚴格的 phase gates:constitution → specify → clarify → plan → tasks → implement。
OpenSpec 自己也把 Spec Kit 當對照組,定位自己為「更輕量、可自由迭代」的方案。我認為這個定位是準確的:Spec Kit 像是企業級的規格管理系統,OpenSpec 像是開發者友善的規格工作流。
OpenSpec vs. OpenAPI / AsyncAPI
OpenAPI 和 AsyncAPI 是「外部契約」類的規格標準。OpenAPI 描述 HTTP API 的介面,AsyncAPI 描述事件驅動系統的 channel/message/operation。兩者都是機器可讀格式,有成熟的驗證、文件生成和 codegen 工具鏈。
OpenSpec 和它們解決的問題不在同一個層面。OpenAPI/AsyncAPI 回答的是「系統的外部介面長什麼樣」,OpenSpec 回答的是「系統的行為本身要怎麼改」。兩者可以共存:把 OpenAPI/AsyncAPI 當作「機器可讀契約」,把 OpenSpec 的 spec.md/design.md 當作「行為規格 + SDD」,在 CI 裡各自驗證。
研究報告中甚至建議,如果 API/事件契約是核心痛點,可以 fork 一個自訂 schema,把 openapi.yaml 或 asyncapi.yaml 納入 OpenSpec 的 artifacts 依賴圖,使其成為「必產出物」。
比較摘要
| 面向 | OpenSpec | GitHub Spec Kit | OpenAPI / AsyncAPI |
|---|---|---|---|
| 規格重心 | 行為需求 + delta + SDD | Constitution + phase gates | API/事件介面契約 |
| 流程彈性 | 高(actions not phases) | 低(嚴格 gate) | 無流程(純規格) |
| brownfield 支援 | 原生(delta specs) | 有限 | 不適用 |
| 驗證工具 | validate + verify | 模板 + gate | JSON Schema + linter |
| 學習曲線 | 中 | 中到高 | 低到中 |
導入建議:部分採用,不要一次全上
研究報告的結論和我的判斷一致:部分採用。 把 OpenSpec 作為團隊統一的「變更封裝 + 行為規格 + SDD + 任務清單」骨架,而不是試圖用它取代 OpenAPI/AsyncAPI 這類既有的外部契約標準。
具體的導入節奏建議如下。
第一步:選一個中等複雜度的變更做 PoC。 用 core profile 走完 propose → validate → apply → archive,在同一個 PR 裡把 proposal/specs/design/tasks 當作審查物。
第二步:在 CI 加入 validate gate。 openspec validate --all --strict --json,並預設 OPENSPEC_TELEMETRY=0 和 DO_NOT_TRACK=1 以避免內網問題。
第三步:建立 config.yaml。 把最重要的工程共識(測試要求、回滾策略、命名規範)寫成可注入的 context/rules,讓每次產生 artifact 時都自動帶入。
等前三步穩定後,再考慮按需擴充 schema:如果團隊需要 API 契約或安全審查等額外的 artifacts,fork 一個自訂 schema 加入依賴圖。
不要一次全上。用 OpenSpec 的 full workflow 修一個 typo 是殺雞用牛刀;但在一個多人團隊裡做跨服務的大功能,沒有 spec 就是在黑暗中奔跑。
更深層的思考:規格是一種介面
讀完整份報告後,我最大的收穫是這個:
Spec 是人和 AI 之間的介面,品質要求因此與傳統文件不同。
在傳統開發裡,spec 是「寫給人看的」;在 AI 時代,spec 同時是「寫給 AI 執行的」。這個雙重身份改變了 spec 的品質要求。它不能只是「大致描述意圖」,需要足夠精確到 AI 能正確實作,同時又足夠人類可讀到 reviewer 能快速理解。
OpenSpec 的 Requirements + Scenarios 格式是在試圖找到這個平衡點。RFC 2119 關鍵字提供精確性,Given/When/Then 提供可驗證性,Markdown 格式提供可讀性。
這個平衡也呼應了 Andrej Karpathy 和 Simon Willison 推廣的 Context Engineering 概念:「prompt engineering 是問得好;context engineering 是讓 AI 知道所有它需要知道的事。」OpenSpec 的 config.yaml 注入團隊共識、schema 定義 artifact 依賴圖,本質上就是在建立一套可複製的 agent onboarding SOP。
時間軸與成熟度
OpenSpec 目前是 v1.2.0(2026-02-23 發布),支援 20+ AI 工具的整合。從它的 issue tracker 來看,它正處於從「個人開發者工具」向「團隊/企業工具」的過渡期。企業網路 telemetry 問題、archive 的 git history 斷裂、非英文 spec 的驗證困難,這些都是過渡期的典型症狀。
但它提出的核心問題是對的:在 AI 幫你寫程式碼的時代,「規格」應該是 repo 內的、增量的、可驗證的、schema-driven 的。這個方向不會因為 OpenSpec 本身是否成功而改變。