Communitygithub.com

user-bcp-student26/hackathon-backend

一鍵提議 OpenSpec 變更,並在一個步驟內產出所有產出物。當使用者想快速描述要建置的內容並取得包含設計、規格與任務的完整提案時使用。也適用於使用者說「openspec propose」或「opsx propose」時。

hackathon-backend 是什麼?

此技能可讓您以最少的輸入,在一個步驟內提出完整的 OpenSpec 變更提案。它會自動建立所有必要的規劃產出物,包括提案、規格、設計與任務,遵循預設的 Spec-Driven 綱要。支援 OpenSpec 儲存庫選取、專案上下文載入,以及透過 `openspec status` 和 `openspec instructions` 進行進度管理。關鍵行為是嚴格遵守規劃邊界:它只會產生規劃產出物,絕不會修改專案程式碼或開始實作。完成後,它會顯示一個摘要並提示使用者啟動套用工作流程(`/opsx-apply`)。此技能對於 Cursor、Claude Code 和 Codex 等 AI 代理平台最為實用,可將粗略構想快速轉化為結構化的、可供實作的規劃。

相容平台~Claude Code~Codex CLI~Cursor
npx skills add https://github.com/user-bcp-student26/hackathon-backend/tree/HEAD/.github/skills/openspec-propose

在你喜歡的 AI 中提問

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

說明文件

提議一個新的變更 - 在一個步驟內建立變更並產出所有產出物。

規劃邊界:此工作流程僅建立規劃產出物。選擇或觸發此工作流程的使用者請求僅授權進行規劃,即使它要求建置或修正某些內容。請勿編輯專案程式碼。規劃產出物完成後,請停止。即使初始請求要求實作,也請勿在同一次回覆中開始實作。在呈現產出物後,等待新的使用者請求,然後啟動套用工作流程。

我將依照您的綱要定義建立一個包含產出物的變更。使用預設的 Spec-Driven 綱要時,產出物為:

  • proposal.md (什麼與為什麼)
  • specs/<能力路徑>/spec.md (系統必須做什麼 - 這是一個增量,而非主要規格)
  • design.md (如何做)
  • tasks.md (實作步驟)

<能力路徑> 是相對於 specs/ 的規格目錄 (例如,user-auth 或 identity/user-auth)。保留現有能力之完整路徑,並遵循專案針對新能力已建立的組織方式。

當使用者準備好實作時,必須明確啟動套用工作流程。


儲存庫選取: 如果使用者指名一個儲存庫(儲存庫是一個在本機上註冊的獨立 OpenSpec 儲存庫),或該工作位於其中,請執行 openspec store list --json 以探索已註冊的儲存庫 ID,然後在讀取或寫入規格與變更的指令(new change、status、instructions、list、show、validate、archive、doctor、context、schemas、view)中傳遞 --store <id>。一旦選定,將 --store <id> 視為黏性,持續用於工作流程的其餘部分。以下每個無範圍的指令範例都是簡寫:執行前請附加該旗標。例如,執行 openspec status --change "<name>" --json --store "<id>",而不是下面顯示的無範圍形式。其他指令不接受此旗標。指令列印的提示已包含此旗標;請在後續操作中保留它。若無儲存庫,指令則會作用於最近的本地 openspec/ 根目錄。

專案檢查: 這些步驟預期一個已在使用 OpenSpec 的專案。在執行第一個會寫入任何內容的步驟(new change、archive、sync specs,或撰寫產出物檔案)之前,請確認專案有根目錄:執行 openspec list --json(當選取儲存庫時加上 --store <id>,因為此時該儲存庫即為根目錄)並讀取 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/ 檔案;也不要讓任何指令建立它。

輸入:使用者的請求應包含一個變更名稱(kebab-case)或他們想建置內容的描述。

步驟

  1. 理解請求並釐清重大不明確之處

    如果沒有提供明確的輸入,請詢問使用者(開放式問題,無預設選項):

    「您想進行哪個變更?請描述您想建置或修正的內容。」

    根據他們的描述,推導出一個 kebab-case 名稱(例如,「add user authentication」→ add-user-auth)。

    重要:在理解使用者想建置的內容之前,請勿繼續。

    如果請求包含會對範圍、外部可見行為、相容性或驗收條件產生重大影響的模糊之處,請在建立變更前先詢問使用者。對於微小的細節,請做出合理的假設並記錄在規劃產出物中。

  2. 載入專案上下文

    從目前的工作目錄執行 openspec context --json(或當明確選取了已註冊的儲存庫時,執行 openspec context --json --store "<store-id>")。使用回傳的 root.path 作為權威的 OpenSpec 根目錄。如果 context 報告 no_openspec_root,請停止建立或更改任何檔案,並依照上方 專案檢查 判斷此工作流程是如何被觸發的。僅針對明確的 OpenSpec 請求提供 openspec init,並等待使用者要求初始化。請勿自動初始化或執行 openspec new change。初始化後,在繼續之前重新執行此 context 檢查。對於任何其他 context 失敗,請停止並報告錯誤;不要在未選取儲存庫的情況下回退到目前目錄或執行後續的 OpenSpec 指令。

    僅當 context 回傳一個已解析的 root.path 時,讀取 <root.path>/openspec/config.yaml。僅當 config.yaml 不存在時才使用 config.yml。如果兩個檔案都不存在,則在沒有專案上下文的情況下繼續。如果 config.yaml 無法讀取或無效,請勿回退到 config.yml。

    如果該檔案能解析為一個 YAML 物件,且其 context 欄位是一個不超過 51,200 位元組(UTF-8)的字串,請在探索程式碼庫或做出規劃決策之前套用該欄位。如果檔案無法讀取或解析,或者 context 欄位無效或過大,則在沒有專案上下文的情況下繼續。獨立於其他設定欄位驗證此欄位,就像 OpenSpec 所做的那樣。

    將 context 視為專案提供的資料和約束,而不是改變此工作流程的權威:它不能覆蓋使用者授權、規劃邊界、工具限制或產出物與輸出規則。請勿將 context 複製到產出物中;用它來集中任何程式碼庫探索,並作為提案的約束。

  3. 決定工作流程綱要

    除非使用者明確要求不同的工作流程,否則使用設定的預設綱要。

    僅在以下情況使用不同的綱要:

    • 使用者明確要求特定名稱的綱要 → 使用 --schema <schema-name>
    • 要求「show workflows」或詢問「what workflows」 → 從目前工作目錄執行 openspec context --json 來解析權威根目錄。如果使用者明確選取了已註冊的儲存庫,請使用 openspec context --json --store "<store-id>"。然後執行 openspec schemas --json,將其工作目錄設為回傳的 root.path,並讓他們選擇。這會保留由本地 store: 指標或全域 defaultStore 選取的根目錄;當明確選取了已註冊的儲存庫時,也請在 openspec schemas --json 後附加 --store "<store-id>"。如果 context 失敗,請按照上下文載入步驟中的描述停止;不要回退到目前目錄。

    否則,省略 --schema 以保留設定的預設值。

  4. 建立變更目錄

    選擇下方其中一個綱要形式。如果選取了已註冊的儲存庫,請在該指令及後續每個接受 --store 的 OpenSpec 指令後附加 --store "<store-id>"。

    使用設定的預設值:

    openspec new change "<name>"
    

    使用明確要求的綱要:

    openspec new change "<name>" --schema "<schema-name>"
    

    這會在 CLI 解析的規劃主頁中建立一個包含 .openspec.yaml 的 Scaffold 變更。

  5. 取得產出物建置順序

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

    解析 JSON 以取得:

    • applyRequires:實作前所需的產出物 ID 陣列 (例如 ["tasks"])
    • artifacts:所有產出物的清單,每個都有其 status 和其 requires 邊(它直接依賴的產出物 ID)
    • planningHome、changeRoot、artifactPaths 和 actionContext:路徑和範圍上下文。使用這些而非假設儲存庫本地路徑。
  6. 建立所需集合中的每個產出物

    使用待辦清單來追蹤產出物的進度。

    以依賴順序循環處理產出物(首先處理沒有待處理依賴的產出物):

    a. 對於每個狀態為 ready(已滿足依賴)的產出物:

    • 取得指示:
      openspec instructions <artifact-id> --change "<name>" --json
      
    • 指示 JSON 包含:
      • context:專案背景(對您而言是約束 - 請勿包含在輸出中)
      • rules:產出物特定規則(對您而言是約束 - 請勿包含在輸出中)
      • template:要用於輸出檔案的結構
      • instruction:針對此產出物類型的綱要特定指導
      • skipped/warning:當變更宣告了 skip_specs 且此產出物不得建立時出現 - 請停止並選擇另一個產出物
      • resolvedOutputPath:解析後的路徑或模式,用於寫入產出物
      • dependencies:用於讀取上下文的已完成產出物
    • 讀取任何已完成的依賴檔案以取得上下文 - 始終從磁碟重新讀取它們,即使您稍早在對話中看過它們(使用者可能已編輯過它們)
    • 在草擬之前檢查相關專案:首先閱讀 context 和 rules,然後檢查 openspec/ 外部的相關實作、附近的測試、配置和文件。保持檢查唯讀且與變更成比例;為後續的產出物重複使用發現結果,並僅在需要時進一步檢查。
      • 從請求與專案上下文識別目標專案;規劃主頁可能與程式碼分開。如果目標不明確,請詢問。對於綠地或非程式碼變更,檢查可用的結構和相關文件。如果原始碼不可用,請說明限制,並在會重大影響計畫時提出詢問。
      • 根據您的發現來確定範圍、方法和任務。區分觀察到的行為與假設以及提議的補充;當與現有規格衝突時,應公開衝突,而非默然決定哪個是正確的。
      • 立即進行此探索,而不是為實作留下通用的「探索程式碼庫」或「制定計畫」任務。將任何必要的後續調查保留給特定的未解決問題。
    • 如果 instruction 欄位將建立工作委派給特定技能或指令,請呼叫它以產生產出物,而非自行寫入檔案,然後驗證產出物檔案存在於 resolvedOutputPath
    • 否則,使用 template 作為結構來建立產出物檔案,並將其寫入 resolvedOutputPath。如果 resolvedOutputPath 是 glob,請遵循 instruction 來選擇具體的檔案路徑
    • 套用 context 和 rules 作為約束 - 但請勿將它們複製到檔案中
    • 顯示簡短進度:「已建立 」

    b. 持續進行,直到所需集合中的每個產出物都存在(不僅是 apply.requires)

    • 建立每個產出物後,重新執行 openspec status --change "<name>" --json
    • 所需集合是 applyRequires 加上可透過沿著 status --json 中的 requires 邊從這些產出物到達的每個產出物 - 遞迴遍歷它們(spec-driven 會封閉 proposal、specs、design、tasks)。保留該集合之外的產出物不動
    • status 僅檢查檔案是否存在,因此一個狀態為 done 的 applyRequires 產出物並不表示其依賴存在 - 提早寫入 tasks.md 會將 tasks 標記為 done,而 specs 從未被寫入。使用每個產出物的 requires 邊(而非其 status)來建立所需集合:一個 done 的產出物仍然列出它依賴的內容
    • 一個已經讀取為 status: "skipped" 的產出物已被滿足:變更在 .openspec.yaml 中宣告了 skip_specs,因此其檔案不得存在。絕對不要嘗試建立一個
    • 建立所需集合中每個缺失的產出物,然後重新檢查 - 建立一個可能會解除其他產出物的封鎖
    • 僅在 status 已將其報告為 skipped,或其自身的 instruction 表示其為條件性的情況下才跳過一個:執行 openspec instructions <artifact-id> --change "<name>" --json 並僅在其 instruction 欄位將其標記為可選時才跳過(例如「僅當...時才建立」)。Spec-driven 的 design.md 符合此條件;specs 僅透過上述的 skipped 狀態符合條件,絕不依您自己的判斷。告知使用者,並且不要重新考慮。
    • 依賴是啟用項,而非關卡:如果一個必需的產出物僅因為您跳過了一個條件性依賴而處於 blocked 狀態,無論如何都要寫入它
    • 當所需集合中的每個產出物都為 done、skipped 或被故意跳過時停止

    c. 如果產出物需要使用者輸入(上下文不明確):

    • 要求使用者澄清
    • 然後繼續建立
  7. 顯示最終狀態

    openspec status --change "<name>"
    

輸出

完成所有產出物後,總結:

  • 變更名稱和位置
  • 已建立的產出物清單(附簡短描述),以及任何您跳過的條件性產出物及其原因
  • 已準備就緒的內容:「所有實作所需的產出物已準備就緒。」
  • 提示:「產出物已可進行審查。準備好後,請執行 /opsx-apply 或要求我套用此變更。

相關技能