儲存庫:在獨立倉庫中進行規劃
Beta。 儲存庫(Stores)、參考資料、工作上下文和工作集為新功能。指令名稱、旗標、檔案格式和 JSON 輸出格式在版本之間可能仍會發生變化。以下每個操作指南都是針對當前構建版本執行的,但在升級後請重新閱讀本指南。
此方案解決的問題
OpenSpec 通常位於單一程式碼倉庫內:一個 openspec/ 資料夾緊鄰您的程式碼,存放該倉庫的規格與變更。
然而,當您的規劃範圍超過單一倉庫時,這種做法就不再適用:
- 您的工作跨越多個倉庫——一項功能同時涉及 API 伺服器、Web 應用程式和共用程式庫。那麼,規劃應該存放在哪個倉庫的
openspec/資料夾中? - 您的團隊在程式碼尚未存在時就進行規劃,或者規劃的內容在本倉庫中永遠不會轉化為程式碼。
- 需求由某個團隊擁有,但被其他團隊使用。Wiki 上的版本容易產生分歧,而且您的程式碼代理工具也無法讀取它。
儲存庫(Store) 正是解決方案:一個專門用於規劃的獨立倉庫。它具備您已熟悉的相同 openspec/ 結構——包含規格與變更——以及一個小型的身份識別檔案。只需透過名稱在您的機器上註冊一次,之後所有正常的 OpenSpec 指令都能從任何位置對其進行操作。
結構
team-plans (一個商店:在其獨立倉庫中進行規劃)
├── .openspec-store/store.yaml identity: "I am team-plans"
└── openspec/
├── specs/ 確定的事實
└── changes/ 進行中的事項
▲
│ 按名稱在每台機器上註冊;
│ 像普通倉庫一樣透過推送/克隆來共享
┌─────────────┼─────────────┐
│ │ │
web-app api-server mobile-app
(程式碼倉庫) (程式碼倉庫) (程式碼倉庫)有兩條規則讓這個模型保持簡潔:
- 商店就是一個 Git 倉庫。 你可以自行提交、推送、拉取和審查它。OpenSpec 不會自行克隆、同步或推送任何內容。
- 宣告,而非機制。 倉庫可以宣告它們與商店的關係(如下所示)。宣告會改變 OpenSpec 能告訴你的資訊——但從不會改變你的命令作用的範圍。
五分鐘建立第一個商店
兩個命令即可讓你從無到有,建立一個可工作的、針對商店範圍的變更:
openspec store setup team-plans --path ~/openspec/team-plansStore ready: team-plans
Location: /Users/you/openspec/team-plans
OpenSpec root: ready
Registry: registered
Next: run normal OpenSpec commands against this store, for example:
openspec new change <change-id> --store team-plans
Share this store by committing and pushing it like any Git repo.openspec new change add-login --store team-plansUsing OpenSpec root: team-plans (/Users/you/openspec/team-plans)
Created change 'add-login' at /Users/you/openspec/team-plans/openspec/changes/add-login/
Schema: spec-driven
Next: openspec status --change add-login --store team-plans這就是整個模型。從這裡開始,生命週期正是你所熟悉的——status、instructions、validate、archive——只需在每个命令後加上 --store team-plans,且每個列印出的提示都會為你包含該旗標。Using OpenSpec root: 行始終告訴你命令作用的範圍。
故事:一個團隊,一個規劃倉庫
團隊將其規格和變更保存在 team-plans 中,而不是將它們分散到各個程式碼倉庫中。
第一天(由設定者執行):
openspec store setup team-plans --path ~/openspec/team-plans \
--remote git@github.com:acme/team-plans.git
git -C ~/openspec/team-plans push -u origin main傳遞 --remote 會在商店的身份檔案(.openspec-store/store.yaml)的初始提交中記錄克隆 URL。每一次未來的克隆都會知道其來源,因此健康檢查和錯誤訊息可以為尚未擁有該商店的隊友列印出完整且可直接貼上的修復步驟。
每位隊友(每台機器一次):
git clone git@github.com:acme/team-plans.git ~/openspec/team-plans
openspec store register ~/openspec/team-plans從那時起,每個人都在同一個規劃倉庫中以名稱工作:
openspec status --store team-plans --change add-login
openspec show add-login --store team-plans共享工作是 Git,這是故意的。 你建立的變更僅存在於你的簽出副本中,直到你提交並推送它——這與程式碼相同。因為商店是一個普通的倉庫,所以計畫自然擁有分支、拉取請求和審查功能。
連接團隊的程式碼倉庫。 一個規劃完全外部化的程式碼倉庫只需要一行配置,位於 openspec/config.yaml 中:
# web-app/openspec/config.yaml
store: team-plans現在,在 web-app 內執行的每個 OpenSpec 命令都會作用於 team-plans,無需任何旗標:
cd ~/src/web-app
openspec status --change add-loginUsing OpenSpec root: team-plans (/Users/you/openspec/team-plans)
...這個指標是備用方案,絕非覆蓋:明確的 --store 始終優先,並且如果倉庫發展出自己真正的規劃資料夾,那些資料夾將優先(並發出警告以移除過時的指標)。
每台機器上每個倉庫的預設值。 如果你在多個程式碼倉庫之間工作,且這些倉庫都規劃到同一個商店,則只需全局設定一次,而不必在每個倉庫中添加 store: 行:
openspec config set defaultStore team-plans現在,在任何規劃根目錄之外執行的命令——以及沒有 --store 和沒有專案指標的情況下——都會解析為 team-plans。它位於優先級列表的底部,因此 --store、本地根目錄和專案 store: 指標仍然優先。根標題和 JSON root 區塊會報告 source: "global_default" 並附上商店 ID,以便你總是能夠區分機器範圍的預設值和倉庫自己的指標。使用 openspec config unset defaultStore 清除它。如果 ID 未註冊,命令會報錯並提示你註冊它或清除過時的預設值。
範例:一個功能,兩個元件倉庫
假設 add-checkout-promo 同時影響 checkout-api 和 checkout-web。團隊希望有一個共享的產品合約,而每個程式碼倉庫仍需要自己的實施任務、分支和審查。
使用兩層結構:
- 將共享行為保留在
team-plans中。 - 將實施計畫保留在每個元件倉庫中,並將商店作為唯讀上游上下文進行引用。
首先,在商店中規劃共享合約:
openspec new change add-checkout-promo --store team-plans
openspec status --change add-checkout-promo --store team-plans提案和規格應描述元件邊界處的行為——例如,服務返回的優惠活動欄位,以及前端如何處理不合資格的結帳。像審查其他分支和拉取請求一樣,在商店倉庫中審查此變更。
規劃能看到什麼上下文?
選擇商店會改變 OpenSpec 根目錄;它不會發現或讀取每個使用該商店的程式碼倉庫。商店指令可以看到商店中的工件和配置的上下文。只有當這些資料夾也可供代理程式或編輯器使用,且代理程式讀取了它們時,商店指令才能看到元件程式碼。
工作集(workset)是一種方便的方式,可以同時開啟規劃商店和兩個程式碼倉庫:
openspec workset create checkout-promo \
--member ~/openspec/team-plans \
--member ~/src/checkout-api \
--member ~/src/checkout-web \
--tool code
openspec workset open checkout-promo這使得這些資料夾在一個 IDE 工作區中可見。它不會將源上下文複製到商店中,也不會選擇受影響的倉庫,或授予代理程式編輯它們的權限。將持久的跨元件事實放在共享規格中;不要依賴規劃者記住它偶然檢查過的源代碼。
如何在每個倉庫中開始實施?
當沒有明確的 --store 或更近的 openspec/ 根目錄適用時,store: team-plans 指標會將命令路由到該商店。它不會根據調用 apply 的目錄將一個商店任務列表拆分。OpenSpec 目前不會將任務路由到倉庫。
當每個元件需要獨立範圍的 apply/審查循環時,為其提供本地 OpenSpec 根目錄,並引用中央商店,而不是指向它:
# checkout-api/openspec/config.yaml (checkout-web 同理)
schema: spec-driven
references:
- team-plans在共享合約獲得批准並在商店的主規格中可用後,為該元件的部分創建一個小型本地變更:
cd ~/src/checkout-api
openspec new change implement-checkout-promo-api
cd ~/src/checkout-web
openspec new change implement-checkout-promo-ui每個倉庫指令中的引用索引提供了商店規格的摘要和確切的 openspec show ... --store team-plans 獲取命令。每個本地提案都引用該共享合約,其任務僅描述該元件中的工作。然後在每個倉庫中分別運行 /opsx:apply;根解析會將工件和實施編輯限制在該倉庫內。現在,服務端和前端更改可以獨立進行測試、審查、合併和歸檔。
如果必須在共享商店變更仍在活躍時開始實施,請使用 openspec show add-checkout-promo --store team-plans 顯式獲取它;引用索引列出的是規範的商店規格,而非活躍的商店變更。在拉取請求描述中保持商店分支和元件分支的連結,以便審查者可以看到每個實施遵循哪個版本的合約。
故事:跨越團隊界限的需求
平台團隊負責需求。產品團隊在自己的倉庫中,基於這些需求並使用自己的設計進行構建。引用描述了這種關係,而無需移動任何人的工作。
platform-reqs (商店) api-server (程式碼倉庫)
由平台團隊擁有 由產品團隊擁有
┌──────────────────────────┐ ┌──────────────────────────┐
│ openspec/specs/ │ ◀────────│ openspec/config.yaml │
│ payments/spec.md │ 讀取 │ references: │
│ auth/spec.md │ │ - platform-reqs │
│ │ │ openspec/specs/ │
│ openspec/changes/ │ │ (他們自己的設計) │
│ platform work │ │ openspec/changes/ │
│ │ │ (他們自己的工作) │
│ │ └──────────────────────────┘
└──────────────────────────┘產品團隊在其倉庫的 openspec/config.yaml 中宣告它所引用的內容:
references:
- platform-reqs引用是唯讀上下文。倉庫保留自己的 openspec/ 根目錄;工作仍在那裡。發生變化的是:該倉庫中的 openspec instructions 現在包含了所引用商店規格的索引——每個規格都有一行摘要和確切的獲取命令(openspec show <spec-id> --type spec --store platform-reqs)。在 api-server 中工作的代理程式可以找到上游的支付需求,引用它們,並在倉庫自己的根目錄中撰寫其低層級設計——無需任何人手動複製上下文。
引用可以攜帶其克隆源,因此尚未擁有該商店的隊友會得到完整的修復步驟,而不是死胡同:
references:
- { id: platform-reqs, remote: "git@github.com:acme/platform-reqs.git" }當你希望同時開啟計畫和程式碼時,建立一個工作集。 這是個人化且明確的:每個人選擇他們在機器上實際使用的資料夾。這些本地簽出路徑的任何內容都不會提交到共享規劃倉庫中。
openspec workset create platform \
--member ~/openspec/platform-reqs \
--member ~/src/api-server \
--member ~/src/web-app兩個你隨時可以問的問題
「我的設定是否健康?」 —— openspec doctor 會檢查當前根目錄及其引用的商店,只讀模式,並為每個發現提供可直接貼上的修復步驟:
Doctor
Root
Location: /Users/you/src/api-server
OpenSpec root: ok
References
- platform-reqs: ok (/Users/you/openspec/platform-reqs)
- design-system: Referenced store 'design-system' is not registered on this machine.
Fix: git clone -- git@github.com:acme/design-system.git '/Users/you/openspec/design-system' && openspec store register '/Users/you/openspec/design-system' --id design-system「我正在使用什麼?」 —— openspec context 從 OpenSpec 宣告中組裝工作集:根目錄及其引用的商店。
Working context for api-server (/Users/you/src/api-server)
OpenSpec root
api-server /Users/you/src/api-server
Referenced stores
platform-reqs /Users/you/openspec/platform-reqs
Fetch: openspec show <spec-id> --type spec --store platform-reqs兩者都支援 --json 以供代理程式使用。openspec context --code-workspace <path> 還會寫入一個包含整個集合的 VS Code 工作區檔案——這是該命令唯一執行的寫入操作。
工作集:重新開啟你一起工作的資料夾
與上述所有功能獨立:大多數人每次工作階段都會一起開啟相同的幾個資料夾——規劃儲存庫加上兩三個程式碼儲存庫。工作集(workset) 就是針對此情境的個人化命名檢視,可用單一指令在你選擇的工具中重新開啟。
workset "platform" openspec workset open platform
├── team-plans ~/openspec/team-plans │
├── api-server ~/src/api-server ▼
└── web-app ~/src/web-app all three open in your toolopenspec workset create platform \
--member ~/openspec/team-plans --member ~/src/api-server \
--tool code
openspec workset listplatform (opens in VS Code)
team-plans /Users/you/openspec/team-plans
api-server /Users/you/src/api-serveropenspec workset open platform 會啟動已儲存的工具:編輯器(VS Code、Cursor)會開啟一個包含所有成員的視窗並返回。第一個成員為主要成員。隨時可用 --tool <id> 覆寫工具。
工作集刻意設計為非共享狀態。它們存在於你的機器上,絕不會被提交,也不會對工作內容做任何聲稱——它們只記錄你喜歡一起開啟的內容。移除工作集絕不會影響成員資料夾。新工具屬於設定而非程式碼:任何透過工作區檔案或逐資料夾附加旗標啟動的工具,都可以新增到全域設定(openspec config edit)的 openers 鍵下。
指令如何決定作用位置
每個常規指令都以相同方式解析其根目錄,順序如下:
1. --store <id> you said so explicitly → that store
2. nearest openspec/ a real planning root here → this repo
(walking up from cwd)
3. store: pointer config.yaml declares a store → that store
4. defaultStore global config sets a machine → that store
default
5. none of the above stores registered on this → error with a
machine? selection hint
no stores registered? → the current
directory
(classic behavior)Using OpenSpec root: 這一行(以及 --json 輸出中的 root 區塊)會告訴你目前處於哪種情況。
已知限制
- Beta 階段。 本頁所有內容可能在版本之間有所變動——名稱、旗標、檔案格式、JSON 鍵。
- 每台機器每個 store id 僅限一個 checkout。 在同一 id 下註冊第二個 checkout 會失敗,並提示先執行
store unregister。 - 永不同步——這是設計決策。 OpenSpec 絕不會 clone、pull 或 push。過期的 checkout 會顯示過期的規格,直到你執行 pull;引用會從磁碟上的實際內容即時索引。
- 空的規劃資料夾可能不存在。 新的 store 在 Git 中可能尚未包含
openspec/changes/、openspec/specs/或openspec/changes/archive/。在 Beta 階段這是可接受的;當常規指令為這些資料夾建立檔案後,它們就會出現。 - 指標儲存庫仍是指標。 僅含設定的儲存庫,若其
openspec/config.yaml宣告了store: <id>,則視為外部化規劃,而非需要註冊的 store checkout。如果你有意將該儲存庫轉換為本地 store 根目錄,請先移除store:這一行。 - 部分指令維持原狀。
templates和已棄用的名詞形式(openspec change show、...)僅作用於目前目錄——不支援--store。schemas遵循標準的根目錄選擇優先順序,接受--store <id>,同時保持其成功時的 JSON 陣列格式不變。 - 每台機器的狀態僅限該機器。 Store 註冊表和工作集都是本地設定。你的機器佈局資訊絕不會被提交到共享規劃中。
- 工作集有兩種啟動方式。 無法透過工作區檔案或逐資料夾附加旗標啟動的工具,無法新增為 opener。
- Agent JSON 存在已知的命名風格差異(store 系列鍵使用 snake_case,workflow 系列使用 camelCase)。詳見 agent contract;統一命名風格將留待版本化發布。
各項內容的存放位置
| 項目 | 位置 | 共享? |
|---|---|---|
| Store 的規劃 | <store>/openspec/(specs、changes) | 是——提交並推送 |
| Store 的識別資訊 | <store>/.openspec-store/store.yaml | 是——與 store 一起提交 |
| Store 註冊表 | <data dir>/openspec/stores/registry.yaml | 否——僅限本機 |
| 工作集 | <data dir>/openspec/worksets/ | 否——僅限本機 |
<data dir> 在 macOS 和 Linux 上為 ~/.local/share/openspec(若已設定則為 $XDG_DATA_HOME/openspec),在 Windows 上為 %LOCALAPPDATA%\openspec。
參考
本頁每個指令的精確旗標和 JSON 格式:CLI reference(Stores、Doctor、Working context、Personal worksets)以及 agent contract。