/decide
你是單一「架構決策記錄 (ADR)」的作者,文件位於 ai-docs/decisions/ 目錄下。決策註冊表是讓先前的推理可被追溯的基礎 — 每個會限制未來工作、明確排除某個替代方案或設有到期日的有意義選擇,都應被記錄下來,以便未來的工程師和 AI 代理能夠追溯。
在此技能中,你不編輯生產程式碼。你唯一要撰寫的產出物是新的或修訂後的 ADR 檔案。建議在你的摘要中提及對 canonical-patterns.md / architectural-smells.md 的反向引用,但不要由你執行(明確的編輯任務會在人類審查後才加入這些反向引用)。
如何判斷成功
- 新的/修訂後的 ADR 通過第 3 階段驗證:
.venv/bin/python scripts/decisions.py audit和link-check都乾淨通過,並回報實際輸出。 - 第 1 階段確認沒有既有的決策已涵蓋該主題 — 重複的內容會中止,並建議使用
--amend或取代,絕不會為同一個選擇建立第二個 ADR。 - 如果有的話,
related_smell/related_pattern反向引用會被設定,並且摘要會建議在相符的canonical-patterns.md/architectural-smells.md條目中加上Decided in: NNNN— 只建議,不自行執行。 ai-docs/decisions/以外的任何東西都不會被寫入。 從第 0 階段開始就朝這些門檻努力。
核心信念
- 決策的門檻是真實的。 任何一個選擇,如果 (a) 會限制未來的技能或重構,(b) 明確排除了某個替代方案,或 (c) 設定了到期日,就是一個候選項目。意外狀況、除錯筆記和專案狀態不算是決策 — 那些應該放在
.claude/tasks/lessons.md、提交訊息或任務清單中。 - 一個選擇一個 ADR。 如果工作跨越兩個耦合的選擇,就寫兩個 ADR。一個記錄了兩個獨立分支的單一 ADR 很難被取代、很難連結,最終會變成一個墳場條目。
- 反向引用讓註冊表易於瀏覽。 每個 ADR 在適用時都應設定
related_smell和/或related_pattern前置資料,並且你的摘要應建議在相符的canonical-patterns.md/architectural-smells.md條目中加上Decided in: NNNN反向引用。沒有反向引用,註冊表就只是唯寫的。 - 取代勝過刪除。 一個被取代的決策應留在註冊表中,狀態設為
superseded並加上superseded_by: NNNN。永遠不要刪除 ADR — 這個鏈結就是稽核軌跡。 - 目標頻率:每季度 2-5 個。 單一專案在一季內超過這個數量,表示過度記錄 — 分類帳會變成一個雜物抽屜。如果你發現自己在一週內起草了第三個 ADR,請暫停並問問自己,後面那些是否真的是決策,或者只是偏好。
- 回溯撰寫的 ADR 也是有效的。 一個長期存在的約定如果會限制未來的工作,就算它早於註冊表,也值得一個 ADR。在內文中標記它為此類(
> Retro-authored ADR.)。
參數解析
四種形式 — 請選擇其中一種。
形式 A — 新的 ADR(預設)
/decide <slug>
<slug> 是一個簡短的 kebab-case 主題識別碼(例如 textchoices-for-state、spec-first-refactor、celery-safe-dispatch)。協調器會選取下一個可用的 4 位數 id(最低未使用的整數,補零)、從 slug 衍生標題,並建立一個 proposed 狀態的 ADR。
形式 B — 取代現有 ADR
/decide --supersede <existing-id> --slug <new-slug>
寫入一個新的 ADR(下一個 id,狀態為 proposed),並帶有 supersedes: [<existing-id>]。同時也會準備編輯被取代的 ADR 的前置資料(status: superseded、superseded_by: <new-id>),但不會提交 — 新的 ADR 必須先經過人類核准。
形式 C — 修訂現有 ADR
/decide --amend <id>
編輯以下其中一個欄位:status、superseded_by、applies_to、tags、related_smell、related_pattern。內文編輯不在範圍內(要編輯內文請直接開啟檔案 — 修訂 ADR 的決策本身也是一個決策,所以通常應該改用取代)。
形式 D — 列出
/decide --list
簡寫為 .venv/bin/python scripts/decisions.py list。不寫入新檔案。
將解析後的規格回報給使用者(意圖 + 目標 id + 從 canonical-patterns.md / architectural-smells.md 中篩選出的 related_smell/related_pattern 候選項),並在形式 A 和 B 中等待核准,然後再寫入。形式 C / D 會立即執行。
核准令牌合約與 /extract-enum 和 /fix-workflow 相同:第一個非空白 token 必須是 approved、approve、go、lgtm、proceed 或 yes。
管線
第 0 階段 — 設定
前: 參數已解析。後: 下一個 id 已解析(形式 A, B);目標檔案路徑已解析(形式 C);${REPO_ROOT}/ai-docs/decisions/ 目錄已存在。
# 尋找下一個 id (形式 A, B)
NEXT_ID=$(.venv/bin/python -c "
import pathlib, re
ids = []
for p in pathlib.Path('ai-docs/decisions').glob('[0-9][0-9][0-9][0-9]-*.md'):
m = re.match(r'(\d{4})-', p.name)
if m: ids.append(int(m.group(1)))
print(f'{(max(ids)+1) if ids else 1:04d}')
")
NEW_PATH="ai-docs/decisions/${NEXT_ID}-${SLUG}.md"
如果這個 slug 在任何 id 下已存在,則中止並建議對現有 ADR 使用 --amend。
第 1 階段 — 收集上下文
前: 目標 id 已知。後: 相關模式(related-pattern)和相關氣味(related-smell)的候選項已識別。
讀取以下檔案(檔案小、速度快、範圍限於主題):
ai-docs/decisions/README.md— 註冊表慣例.claude/docs/canonical-patterns.md— 搜尋能匹配決策主題的模式名稱(對 slug 單字進行不區分大小寫的 grep).claude/docs/architectural-smells.md— 對氣味名稱進行相同的搜尋.venv/bin/python scripts/decisions.py list --json— 完整註冊表(這樣你就不會意外地針對已經決定過的問題再次做出決定)
對於形式 B(取代),也要讀取被取代的 ADR 的內文,以便新的 ADR 能說明變更了什麼。直接引用被取代決策中的決策句子,然後解釋分歧點。
第 2 階段 — 草擬 ADR
前: 上下文已收集。後: ${NEW_PATH} 已寫入(形式 A, B)或 --amend 的欄位已更新(形式 C)。
使用註冊表腳本為形式 A/B 建立骨架,然後編輯產生的檔案。骨架是前端資料形狀的可執行來源:
.venv/bin/python scripts/decisions.py init "${SLUG}"
scripts/decisions.py init 產生的 ADR 形狀 — 請保留以下前端資料欄位,即使其值為空:
---
id: "<NNNN>"
namespace: core
title: "<大寫開頭的標題句子 — 儘可能以動詞開頭>"
status: proposed # proposed | accepted | superseded | deprecated
date: <YYYY-MM-DD today>
deciders: [] # 如果不確定,在填入前先詢問
supersedes: [] # 僅在形式 B 中填入
superseded_by: null
applies_to: []
embodied_by: [] # 一旦 accepted 就必須填入;參見 ADR 0033
tags: []
related_smell: <smell-anchor 或 null> # 來自 architectural-smells.md
related_pattern: <pattern-anchor 或 null> # 來自 canonical-patterns.md
---
# <title>
<可選的回溯撰寫免責聲明>
## Context(上下文)
<2-4 個段落,解釋先前的狀態、反覆出現的問題以及觸發此決策的因素。要具體 — 引用實際的檔案、實際的事件、實際的失敗模式。模糊的上下文 = 日後無法被取代。>
## Decision(決策)
<一個簡短的段落,陳述規則,如果有多個子規則則加上項目符號。Decision(決策)章節是唯一承重的句子;其他所有內容都是為了支援它。>
## Alternatives considered(考慮過的替代方案)
- **<替代方案 1 名稱>.** <一行陳述>。拒絕理由:<原因>。
- **<替代方案 2 名稱>.** <一行陳述>。拒絕理由:<原因>。
- (至少兩個替代方案;「不決定」通常算作一個。)
## Consequences(後果)
**更容易:**
- <持久的改善>
**更困難:**
- <此決策接受的取捨>
**現在預期 / 現在不允許:**
- <lint、審查者或未來代理將強制執行新的限制>
## Verification(驗證)
- **工具:** <lint 規則 / 測試 / 稽核指令,包含檔案路徑>
- **文件反向引用:** <哪個 canonical-patterns.md / architectural-smells.md 條目將會帶有 `Decided in: <NNNN>`>
- **現有成品:** <指向已符合規定的規格 / 提交 / PR 的指標>
建立骨架後,填入標題/內文以及任何已知的 deciders、applies_to、tags、related_smell 和 related_pattern 值。對於形式 B,在新的 ADR 中編輯 supersedes: [<existing-id>]。
對於形式 C(修訂),僅透過「Edit(編輯)」工具編輯請求的前端資料欄位。不要碰觸內文。如果修訂會將 status 設為 superseded 但沒有 superseded_by,則中止並要求提供取代的 id。
第 3 階段 — 驗證
前: ADR 已寫入。後: decisions.py audit 和 link-check 退出碼為 0。
.venv/bin/python scripts/decisions.py audit && \
.venv/bin/python scripts/decisions.py link-check
如果任一項失敗,則顯示診斷資訊並停止 — ADR 存在於磁碟上但未註冊。常見的失敗原因:
proposed > 30 days— 僅與較舊的 ADR 相關(新撰寫的不會發生)broken supersedes— 形式 B 中被取代 ADR 的編輯未成功applies_to path missing— 修正applies_to的 glob 模式
第 4 階段 — 有效性記錄
前: 驗證通過。後: 在 reports/_meta/effectiveness.jsonl 中附加一行。
.venv/bin/python scripts/log_effectiveness.py \
--skill decide \
--scan-id "decision-${NEXT_ID}" \
--target "${NEW_PATH}" \
--findings-total 1 \
--buckets "{\"new_decision\": 1}"
對於形式 C(修訂),bucket 是 {"amended_decision": 1},findings-total 保持為 1。
第 5 階段 — 總結
向使用者回報,不超過 8 行:
- 新的(或修訂後的)ADR 的路徑。
- ID 和標題。
- 在第 1 階段中篩選出的相關模式(related-pattern)和相關氣味(related-smell)反向引用候選項,以及每個條目應新增的確切行:在相符的模式/氣味下加上
Decided in: ${NEXT_ID}。 - 建議的下一個指令:
- 形式 A/B:人類審查 → 核准後透過
/decide --amend ${NEXT_ID}將status標記為accepted。 - 形式 C:無 — 修訂本身就是工作。
- 形式 A/B:人類審查 → 核准後透過
不要自行編輯 canonical-patterns.md / architectural-smells.md。篩選出反向引用候選項就是工作;由人類決定是否要將其落地。
非目標
- 編輯
canonical-patterns.md或architectural-smells.md(建議反向引用,不要自行寫入 — 那是另一個審查) - 新增 lint 規則(那是
/prevent-regression的工作;ADR 可以在其 Verification(驗證)章節中建議一個) - 建立新功能 / 重構(ADR 是工作的動機;實際工作是
/plan-feature或/refactor-subsystem) - 記錄經驗教訓或意外狀況(那些應放在
.claude/tasks/lessons.md) - 在沒有相應的真實跨領域選擇激增的情況下,每季度超過 2-5 個 ADR — 暫停並重新評估。
發生問題時
| 症狀 | 行動 |
|---|---|
| Slug 在其他 id 下已存在 | 中止;建議改用 --amend <existing> |
--supersede 目標不存在 | 中止;要求提供正確的 id(使用 /decide --list 確認) |
--amend 目標的前端資料欄位未知 | 中止;列出支援的欄位(status、superseded_by、applies_to、tags、related_smell、related_pattern) |
decisions.py audit 退出碼為 1 | 顯示確切的診斷資訊;不要記錄有效性;要求使用者在重試前修復註冊表 |
link-check 在某處發現中斷的 Decided in: NNNN 引用 | 回報它,但不要編輯中斷的引用;那是另一個清理工作 |
| 形式 B 要求取代一個已被取代的 ADR | 沿著鏈結找到葉節點,並取代那個葉節點;在摘要中標記鏈結深度 |
| 第 1 階段發現一個既有的決策已經涵蓋此主題 | 中止新 ADR 的草擬;建議使用者執行 /decide --amend <existing> 來擴充 applies_to 或透過取代來升級 |
儲存庫佈局
.claude/skills/decide/
├── SKILL.md # 此檔案 — 協調器
└── knowledge/
└── rules.md # ADR 門檻啟發法、反模式
協調器(你)不會讀取 knowledge/rules.md — 該檔案是給設計者/未來維護者的離線參考資料,說明此技能設計要避免的門檻規則和常見 ADR 反模式。未來如果加入偵察子代理(如果有),它們會讀取它。