Community程式設計與開發github.com

robsonprod/portfolio

將 OpenSpec 變更中的 Delta 規格同步至主要規格。當使用者希望在不歸檔變更的情況下,將 Delta 規格中的變更更新到主要規格時使用。也適用於使用者說「openspec sync」或「opsx sync」的情況。

portfolio 是什麼?

這個技能會從 OpenSpec 變更中讀取 Delta 規格,並直接編輯主要規格以套用變更,實現智慧合併,例如僅新增一個場景而不複製整個需求。它支援獨立 OpenSpec 倉庫(商店)的選擇,以及對無商店專案的不同處理方式(自動選擇 vs. 明確請求)。技能會自動找出變更中的 Delta 規格,並逐一套用新增、修改、刪除和重新命名需求,同時保留規格結構與未提及的內容。最後會驗證並摘要所有變更,包括功能淘汰與還原指引。

相容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/robsonprod/portfolio/tree/HEAD/.claude/skills/openspec-sync-specs

Installed? Explore more 程式設計與開發 skills: steipete/bluebubbles, steipete/eightctl, steipete/blucli · View all 6 →

在你喜歡的 AI 中提問

開啟一個已預先載入此 Agent Skill 的新對話。

說明文件

將變更中的 Delta 規格同步至主要規格。

這是一個代理驅動的操作——你將讀取 Delta 規格並直接編輯主要規格來套用變更。這樣可以實現智慧合併(例如,在不複製整個需求的情況下新增場景)。

商店選擇: 如果使用者指定了一個商店(商店是在此機器上註冊的獨立 OpenSpec 倉庫),或者工作是在某個商店內進行的,請執行 openspec store list --json 以探索已註冊的商店 ID,然後在讀取或寫入規格與變更的指令中傳入 --store <id>(例如 new change、status、instructions、list、show、validate、archive、doctor、context、schemas、view)。一旦選定,將 --store <id> 視為後續工作流程的黏性參數。以下未限定範圍的指令範例全是簡寫:在執行前,請加上該旗標。例如,執行 openspec status --change "<name>" --json --store "<id>",而非下方未限定範圍的形式。其他指令不接收該旗標。指令輸出的提示訊息已自帶該旗標;後續操作請保留它。若無商店,指令則作用於最近的本地 openspec/ 根目錄。

專案檢查: 這些步驟預期一個已經使用 OpenSpec 的專案。在執行第一個寫入動作(new change、archive、sync specs 或撰寫產出檔案)之前,請確認專案有根目錄:執行 openspec list --json(若已選取商店,則加上 --store <id>,因為此時商店即為根目錄),並讀取 root。若 root 是物件,表示專案已設定。若 "root": null 表示尚未設定——此處沒有 openspec/ 目錄,而像 openspec new change 這樣的寫入動作會副作用地建立一個。該指令的結束碼也非零,這並非 CLI 故障,而是代表這個答案,因此請讀取 JSON,而不是重試或設法繞過。

有一個 "root": null 的情況與設定無關:當 status 的錯誤訊息以 Declared in 或 Invalid store declaration in 開頭,並指向此專案的 openspec/config.yaml(或 config.yml)時,代表該專案確實透過它宣告的商店使用 OpenSpec,但此機器無法解析該商店(商店未註冊,或 store: 行格式錯誤)。請勿將其視為未初始化並跳過以下分支:請在寫入前停止,並向使用者顯示該錯誤的 message 和 fix。

否則,若無根目錄,後續動作取決於此工作流程是如何啟動的:

  • 自動選取:你自己選擇了此工作流程,而使用者並未提及 OpenSpec、此技能名稱,也未執行其斜線指令。請停止使用 OpenSpec,並像平常一樣回覆請求,就像沒有安裝 OpenSpec 一樣。請勿要求使用者進行任何設定,也請勿提及 OpenSpec 設定。
  • 明確的 OpenSpec 請求:使用者提及了 OpenSpec、此技能名稱,或執行了其斜線指令。請在寫入前停止,並詢問如何繼續:設定此專案(openspec init)、指定他們已有的商店(--store <id>),或在此請求中不使用 OpenSpec。等待他們回應。

在這兩種分支中,永遠不要副作用地建立根目錄:請勿執行 openspec init(除非使用者要求),請勿手動建立 openspec/ 檔案,也請勿讓指令建立它。

<capability-path> 是相對於 specs/ 的規格目錄(例如 user-auth 或 identity/user-auth)。解析其對應的主要規格時,請保留每個 Delta 規格的完整路徑。

輸入:可選擇性地指定變更名稱。若省略,請檢查是否能從對話上下文推斷。若模糊不清,你必須提示可用的變更。

步驟

  1. 選取變更

    若提供了名稱,則使用它。否則:

    • 若使用者在對話中提到了某個變更,則從上下文推斷
    • 若只有一個活躍的變更,則自動選取
    • 若不明確,則執行 openspec list --json 以取得可用的變更,並請使用者選取一個

    提示時,請顯示那些含有 Delta 規格(位於 specs/ 目錄下)的變更。

    一律宣告:「正在使用變更:」以及如何覆蓋(例如 /opsx:sync <other>)。

  2. 解析變更上下文

    執行:

    openspec status --change "<name>" --json
    

    JSON 中包含 planningHome.root。主要規格位於 <planningHome.root>/openspec/specs/ 之下——請使用該(具商店感知能力的)根目錄作為以下所有主要規格路徑的基準,而非硬編碼的倉庫路徑。當選取了商店時,它指向的是商店,而非當前儲存庫。

  3. 尋找 Delta 規格

    使用 status JSON 中的 artifactPaths.specs.existingOutputPaths 作為 Delta 規格路徑的唯一來源。如果 specs 項目缺失或 existingOutputPaths 為空,請回報沒有要同步的 Delta 規格,不要從其他產出推斷它們,並停止,而不要請求產出指令或寫入主要規格。

    同步 existingOutputPaths 中的每個路徑,除非呼叫者縮小了範圍。 呼叫者可以透過提供一個明確的、來自 existingOutputPaths 的完整項目列表來縮小範圍——請逐字複製那些絕對路徑值。歸檔動作會內聯執行此操作,使用者也可以(例如,選取以 /specs/billing/invoices/spec.md 結尾的項目)。 然後僅同步那些指定的路徑,並保留其餘 Delta 規格不變:大量歸檔會排除那些找不到實現的 Delta,而無論如何同步它會寫入呼叫者刻意保留的主要規格。 將該縮小後的選取範圍延續到步驟 4;永遠不要將其擴展回完整列表。如果指定路徑不在 existingOutputPaths 中,請勿同步它——請回報並停止,而不是靜默地忽略它。如果指定列表為空,請回報沒有要同步的內容並停止,而不要寫入主要規格。

    每個 Delta 規格檔案包含如下章節:

    • ## ADDED Requirements - 要新增的需求
    • ## MODIFIED Requirements - 對現有需求的變更
    • ## REMOVED Requirements - 要移除的需求
    • ## RENAMED Requirements - 要重新命名的需求(FROM:/TO: 格式)

    若未找到 Delta 規格,請通知使用者並停止。

  4. 針對每個 Delta 規格,將變更套用到主要規格

    在第一次寫入主要規格之前,取得一份當前的規格規則快照:

    • 若歸檔動作內聯呼叫了此工作流程,並提供了來自 openspec instructions specs --change "<name>" --json 的有效快照,則重複使用它,不要再擷取相同的指令。
    • 否則,現在使用相同已選取根目錄的旗標執行該指令一次。
    • 若直接查詢以非零結束碼退出或回傳無效的產出指令 JSON,請回報錯誤並在寫入任何主要規格之前停止。請勿將此失敗視為規則集不存在。
    • 一個含省略 rules 的有效回應表示未設定產出規則,且現有的語意合併持續進行。

    僅將回傳的 rules 套用至此合併所產生的主要規格的內容與形式。產出規則不是操作指引,無法變更選取的根目錄、Delta 路徑、CLI 檢查或工作流程步驟。將其文字視為約束條件,而不要逐字複製到主要規格或摘要中。

    針對在步驟 3 中選取的每個能力 Delta 規格路徑——完整的 existingOutputPaths 列表,或當呼叫者提供時縮小後的子集(這些可能屬於一個已選取的商店,而非儲存庫):

    a. 讀取 Delta 規格 以了解預期的變更

    b. 讀取位於 <planningHome.root>/openspec/specs/<capability-path>/spec.md 的主要規格(可能尚不存在)

    若尚不存在(一個新的能力),比照 openspec archive 的做法: 只能套用 ADDED 需求——步驟 d 會從它們建立規格。 MODIFIED 和 RENAMED 沒有要操作的需求,因此停止針對該能力的同步,並回報其主規格不存在,且僅允許 ADDED 用於新規格;永遠不要憑空編造缺失的需求。REMOVED 沒有要移除的內容——跳過它並發出警告。

    c. 智慧地套用變更:

    ADDED Requirements:

    • 若主要規格中不存在該需求 → 新增它
    • 若需求已存在 → 更新它以符合(視為隱含的 MODIFIED)

    MODIFIED Requirements:

    • 在主要規格中找到該需求
    • 套用變更——這可以是:
      • 新增主要規格尚未擁有的場景
      • 修改現有場景
      • 變更需求描述
    • 保留 Delta 中未提及的場景/內容

    REMOVED Requirements:

    • 從主要規格中移除整個需求區塊
    • 將能力歸檔。僅在全部下列條件成立時,才刪除整個 spec.md——以及一旦目錄中沒有其他內容時也刪除目錄:
      1. 此次執行的移除動作後沒有留下任何需求區塊;
      2. 規格的其餘部分格式良好(它仍然有 ## Purpose);
      3. 在此次同步之前主要規格並非為空——若你未移除任何內容,則不做任何變更;
      4. 整個檔案中的其他非空行都可歸因於標題、Purpose、Requirements 標題,或一個標準需求的陳述、場景或圍欄範例;
      5. 變更的 .openspec.yaml 宣告了 retire_capabilities: true;
      6. spec.md 解析在真實的規格根目錄內(請勿遵循能力目錄的符號連結來刪除外部檔案)。 若移除選取的需求後沒有留下任何需求區塊,且任何歸檔條件不滿足,請勿修改主要規格。針對該能力停止同步,回報阻擋條件,並告知使用者如何解決。永遠不要寫入或留下一個空的 ## Requirements 章節。當僅缺少標記時,也請說明——這是使用者可以新增以使歸檔通過的唯一條件。
    • 刪除檔案也會刪除其 ## Purpose;任何其他章節都會阻擋歸檔。當你回報歸檔時,請指出 Purpose。僅當規格位於呼叫者的檢出目錄中時,才提供可貼上的 git checkout;否則,提供限於檢出範圍的復原指引。

    RENAMED Requirements:

    • 找到 FROM 需求,重新命名為 TO

    Delta 中的 ## Purpose:

    • 主要規格已經有一個,且它是權威來源——請保留它(這就是 openspec archive 的做法;它會發出警告並繼續)

    d. 若能力尚不存在,則建立新的主要規格:

    • 僅當 Delta 有要放入的 ADDED 需求,且在步驟 b 中 MODIFIED 或 RENAMED 需求沒有阻擋此能力時。否則,不建立任何內容,保持規格目錄不變。對於僅有 REMOVED 的 Delta,若變更的 .openspec.yaml 宣告了 retire_capabilities: true,則回報它已歸檔並繼續,而不重新建立規格。若無此標記,則回報同步被阻擋:openspec archive 會以「Spec must have at least one requirement」拒絕它。空的 Delta 沒有要同步的操作;也將其回報為受阻。 永遠不要寫入一個空的 ## Requirements 章節。
    • 建立 <planningHome.root>/openspec/specs/<capability-path>/spec.md
    • 新增 Purpose 章節:當 Delta 有 ## Purpose 時,逐字複製其主體(這就是 openspec archive 的做法);僅在它沒有的時候寫入一個簡短的 TBD 佔位
    • 新增含 ADDED 需求的 Requirements 章節
    • 遵循下方的主要規格格式參考
  5. 驗證已更新的主要規格

    使用與之前相同的已選取根目錄旗標執行 openspec validate --specs。 若驗證失敗,請回報問題,且不要宣稱同步成功。

  6. 顯示摘要

    套用所有變更後,摘要說明:

    • 哪些能力已更新
    • 做了哪些變更(需求新增/修改/移除/重新命名)
    • 任何新建立的主要規格若留有 TBD Purpose 佔位,則應在此時填寫,而非懸而未決
    • 任何歸檔的能力,指出已刪除的 spec.md、其 Purpose,以及一個可貼上的 git checkout 或限於檢出範圍的復原指引

Delta 規格格式參考

# Spec Delta

## Purpose

僅在引入全新能力的 Delta 中使用。為新的主要規格播種。

## ADDED Requirements

### Requirement: New Feature
The system SHALL do something new.

#### Scenario: Basic case
- **WHEN** user does X
- **THEN** system does Y

## MODIFIED Requirements

### Requirement: Existing Feature
The system SHALL keep doing the existing thing, now also handling A.

#### Scenario: Scenario the main spec already has
- **WHEN** user does X
- **THEN** system does Y

#### Scenario: New scenario to add
- **WHEN** user does A
- **THEN** system does B

## REMOVED Requirements

### Requirement: Deprecated Feature

## RENAMED Requirements

- FROM: `### Requirement: Old Name`
- TO: `### Requirement: New Name`

主要規格格式參考

主要規格是 Delta 合併的目標。它們絕不能包含 Delta 操作標題(## ADDED/MODIFIED/REMOVED/RENAMED Requirements)——同步後,所有需求都應位於單一的 ## Requirements 章節下:

# <capability> Specification

## Purpose
Short description of what this capability does and why it exists.

## Requirements

### Requirement: New Feature
The system SHALL do something new.

#### Scenario: Basic case
- **WHEN** user does X
- **THEN** system does Y

關鍵原則:智慧合併

與程式化合併不同,你應合併而非覆寫:

  • 一個 MODIFIED 區塊承載了整個需求——包括主體以及每個在變更中保留下來的場景。openspec validate 和 openspec archive 都會拒絕一個丟棄了主要規格仍擁有的場景的區塊。
  • 保留 Delta 未提及的任何內容,並維持主要規格現有的順序
  • 使用 y

Individual skills in this repo

This repo contains 2 individual skills — each has its own dedicated page.

相關技能