spec-doctor
openspec 生態的 spec 品質 skill,可跨專案使用——「通用」指不綁定單一 repo(任何 openspec 專案直接可用),不是格式無關。確定性掃描交給腳本(零 token),模型只做規範載入、參數組裝、報告判讀。
適用前提:spec 必須是 openspec 結構(### Requirement:、#### Scenario:、delta 區段、@trace)。非 openspec 專案:腳本不適用(會報 NOT-OPENSPEC 而非靜默通過);僅通用句型規則(單一 SHALL、禁模糊詞、THEN 可觀測)的精神可供人工參考。
- 模式 A — lint delta:輸入是一個 change 目錄。驗 delta 格式合規與對 canonical 的一致性。
- 模式 B — 體檢 canonical:輸入是 canonical specs 根目錄(或單一 capability)。驗結構不變量與 @trace 路徑存在性。
模式判定
- 給 change 名稱/目錄、說「delta 寫完了檢查一下」→ 模式 A。
- 給
openspec/specs/或問「主 spec 乾不乾淨 / 有沒有 drift / archive 後檢查」→ 模式 B。 - 不確定就問。
規則分層(兩模式共用,照 log-doctor 的規矩)
- 依序找專案自己的 spec 規範(找到就用,為現行硬規則):
- 使用者明確指定的規範路徑
openspec/config.yaml的rules.specs段(openspec 專案)docs/**/spec-convention*.md、專案 CLAUDE.md 內的 spec 段落
- 有專案規範 → 硬規則;
references/generic-rules.md降為建議升級維度。 - 沒有 → generic-rules 即硬規則。
- 衝突時專案優先,不混血;把差異列出讓人決定。
- 專案規範中可機械化的差異(額外禁字、豁免規則)以
--banned等參數傳給腳本;不可機械化的(語意類規則)由模型在判讀階段補查。
執行
# 模式 A:lint 一個 change 的 delta(自動找 canonical 做標題交叉驗證)
python <skill-dir>/scripts/spec_lint.py <change-dir> --specs-root <repo>/openspec/specs
# 模式 B:體檢 canonical(@trace 路徑以 --repo-root 解析;預設自動找 .git)
python <skill-dir>/scripts/spec_lint.py <repo>/openspec/specs --mode canonical --repo-root <repo>
# 機器可讀輸出
... --json
- exit 1 = 有 ERROR(必修);exit 0 = 乾淨或僅 WARN。
- parked change 不在
openspec/changes/時,spectra 專案的 parked 目錄在.git/spectra-app/changes/<name>。
報告
分兩類(同 log-doctor):
- [必修] ERROR:
file:line+ rule + 問題 + 可貼上的修正。全部修完才 validate/commit。 - [建議] WARN:同格式;THEN-UNOBSERVABLE 與 TRACE-PATH-MISSING 屬啟發式,逐項判讀(見 generic-rules 的判讀指引),大量誤報時回報並建議擴充關鍵詞表,不要靜默忽略。
規範來源是規則檔,不是既有 spec 寫法——不要因「現有 spec 都這樣寫」反推規則去遷就它。
邊界
- 腳本只驗機械可判定的事實;語意歧義(一句話兩種讀法)與 spec-code 語意 drift(spec 說 A 程式做 B)不在腳本能力內,屬模式 B 判讀階段的模型工作,且只在 @trace 路徑消失等線索出現時往上追,不做全量語意比對。
- 本 skill 不改檔案。要套修正由使用者決定,修完重跑至 exit 0。