Files
meta/references/guidelines.md
T
jiantw83 651dc19be9 docs(guidelines): 改寫相依版本準則並補上技能行為清單合約
What:「Manifest 相依版本」第 5 條改成部署端照樣更新,只在回報裡寫明缺哪一版。「版本前置檢查」補上相依版本檢查三列。新增「技能行為清單」一節,訂出位置、標題、節、表格、欄位與更新時機。審核檢查清單加上行為清單這一項。README 補上 behaviors.md 與 check-behaviors.sh 兩列,並把 skill-check 段落改成三組腳本。

Why:跳過更新會讓落後的 domain 永遠更新不到。它落後所以被跳過,被跳過所以永遠落後。相依版本不符要擋的是拿舊版去跑,不是把舊版換成新版。阻擋改到技能被呼叫的當下,才擋得住真正會出事的動作。行為清單要有一份格式合約,check-behaviors.sh 才有判定依據。

How:阻擋交給 jsc-hooks/hooks/version-guard.sh。版本比對由它自己實作,不呼叫 jsc-cli/tools/check-requires.sh。hook 專屬存放於 jsc-hooks,而且 jsc-cli 已宣告相依 jsc-hooks,反向呼叫會做出循環相依。兩道檢查共用同一份豁免清單。行為清單一個 domain 一份,放進該 domain 的 references/behaviors.md,技能改動與清單改動才進得了同一個 PR。

Who:涵蓋這次兩件需求的準則與說明文件,一件是相依版本不符改為阻擋執行,一件是技能行為清單。
2026-08-31 13:37:22 +08:00

28 KiB
Raw Blame History

JSC 技能準則

本文件是 jsc 技能組的唯一準則來源。skill-new、skill-update、skill-delete 與技能審核都必須依此檢查。

命名

  1. Plugin 名稱:jsc-{domain},domain 用一個簡短的英文代表詞(例:ask、sdlc、gitea)。
  2. Marketplace 統一為 jsc,正本在 https://gitea.jsc.idv.tw/plugins/meta.git;安裝 token 一律 jsc-{domain}@jsc。每個 domain 存取庫都帶同一份 marketplace 檔(.claude-plugin/marketplace.json 與 .agents/plugins/marketplace.json,內容與正本完全一致),所以任何一個 repo 都能當註冊入口,互相覆蓋沒關係。
  3. Skill 名稱:小寫、數字、連字號(-),最長 64 字元。名稱即指令(/jsc-{domain}:{name})。
  4. 每個 domain 是一個獨立存取庫 https://gitea.jsc.idv.tw/plugins/{domain}.git。新 domain 必須依 https://gitea.jsc.idv.tw/plugins/template 的結構建立新存取庫(三份 plugin manifest、skills/、README.md、AGENTS.md),並把 plugin 條目(URL 來源指向新存取庫)加入 plugins/meta 正本的兩份 marketplace 檔,再把更新後的檔案同步到所有 domain 存取庫(含新存取庫自己)。
  5. Git 分支名只允許 ASCII(a-z0-9 與 /、-);中文需求或標題先翻譯成英文短語再 slug 化。
  6. Manifest 版本號從 0.0.1 開始,三份 manifest 同步 bump;minor 與 patch 不得超過 9,滿 9 就往左進位,major 可以超過 9。

PR 分支階梯

所有存取庫的 PR 一律照階梯逐級上推,禁止越級。

類型 階梯
feat、docs、style、refactor、perf、test、chore、revert {類型}/{子功能} → {類型}/{功能}/main → develop → master
fix fix/{修改} → develop → master
  1. {子功能} = {功能}/{子功能內容中文簡述},可以多層,例如 {A}/{A的子功能B}/{B的子功能C}/{C的子功能}。
  2. {功能} = 功能內容中文簡述;{修改} = 修改內容中文簡述。
  3. 中文簡述先交給 jsc-git/tools/slugify.sh 轉成 ASCII slug,再組成分支名;分支名本身的字元限制見「命名」第 5 條。
  4. base 一律由 jsc-git/tools/base-branch.sh --derive 推導。推不出唯一合法基底就中止並詢問使用者,不猜,也不退回 develop。
  5. 功能主幹 {類型}/{功能}/main 不在 origin 上時,自動從 develop 建立並推上去,收尾要回報建立了哪一條分支。
  6. 階梯最後一級不能省:develop 併進 master 才會生效,marketplace 與 version-guard.sh 都讀存取庫的預設分支。

PR 開立、更新、留言修正的收尾回報格式只看 references/pr-report.md。所有會產生 PR 的技能都引用那份文件,不在技能內各自抄欄位。

Description 規則

  1. frontmatter 的 description 為一行英文,不超過 5 句或 5 個步驟——兩個上限滿足任一個就算通過,句數與步驟數都超過才要精簡。
  2. 使用專有名詞、概念或指引詞(例:WBS、TDD、decision tree、STE100)取代解釋。
  3. 必須寫清楚觸發時機(何時用、何時不用),這是各 CLI 自動載入的唯一依據。
  4. 複雜流程透過組合其他技能實現,不在單一 description 裡塞流程。

Manifest 相依版本

  1. Plugin 需要另一個 jsc plugin 的技能、工具、hooks、references 或 templates 才能完成自己的流程時,必須在三份 manifest 寫入 jsc.requires。

  2. jsc.requires 是物件。鍵是完整 plugin 名稱,格式為 jsc-{domain}。值是最低版本,格式為 >=x.y.z。

  3. 沒有跨 plugin 相依時不寫 jsc.requires。不要留下空物件。

  4. 只宣告 jsc plugin 對 jsc plugin 的相依。系統指令、語言執行環境與第三方套件寫在 README 或工具說明,不寫進這個欄位。

  5. jsc-cli/tools/check-requires.sh 是部署端相依版本回報的唯一程式來源。jsc-cli/tools/deploy.sh update 必須在更新每個 domain 前呼叫它,版本不符時照樣更新那個 domain,只在回報裡寫明缺哪一個 plugin 的哪一版,不得靜默略過這段回報。

    為什麼不跳過。 跳過更新會讓落後的 domain 永遠更新不到:它落後所以被跳過,被跳過所以永遠落後,更新指令跑幾次都一樣,只能手動拆。相依版本不符要擋的是「拿舊版去跑」,不是「把舊版換成新版」,更新本身正是解除落後的唯一路徑,擋它等於自鎖。

    阻擋改由 jsc-hooks/hooks/version-guard.sh 在技能被呼叫的當下執行,規則見「版本前置檢查」。那個時點才擋得住真正會出事的動作,也不會擋掉更新路徑。

強制力層級

  1. 規則的實現優先順序:hook > prompt。凡是可以由 hook 強制的規則(語言、計時、統計),一律下放 hook,SKILL.md 只保留 hook 無法涵蓋的指引。
  2. 有標準輸入與輸出的流程一律下放到 tools/ 腳本,SKILL.md 只描述何時呼叫與參數。
  3. 主 agent 不需要處理細節的流程,SKILL.md 必須明確要求建立 sub agent 處理(關鍵字:「必須以 sub agent 執行」)。

Hook 規則

  1. 所有 hook 專屬存放於 jsc-hooks,不可散落在其他 domain。
  2. Hook 腳本實作優先順序:shell > nodejs > python。
  3. Hook 必須適用於 claude / codex / copilot / antigravity / kiro 五種 CLI:
    • 腳本同時支援 stdin JSON(Claude 格式)與環境變數輸入,缺欄位時安靜降級(exit 0)。
    • 各 CLI 的接線方式由 jsc-hooks:hooks-install 技能處理。

技能設計

  1. 每個技能必須有單一明確目標,不可與既有技能重複;能複用就複用(呼叫其他技能或工具)。
  2. 需要操作 gitea 且輸入輸出明確的技能,一律透過 jsc-gitea/tools/gitea.sh(curl + GITEA_TOKEN)或 tea CLI,不可自行拼 API 呼叫。gitea.sh 在 token 未設定或收到 401/403 時,會自動改用 tea 的登入金鑰重試一次。
  3. 需要問使用者的技能,一律透過 jsc-ask:ask 的決策樹規則:選項式提問、每個選項標明影響範圍、問到沒有疑慮為止、已有紀錄的答案不再問。

語言

  1. 所有非程式碼輸出一律 STE100 繁體中文、UTF-8、無亂碼、無簡體字,帶擬人台灣感:短句、一句一指令、主動語態、術語一致、台灣用語、全形標點、去 AI 味、直接講重點。範圍涵蓋程式碼註解、commit 訊息、PR 描述、wiki 頁、對使用者的回報、README 與各種文件;程式碼本身(識別字、關鍵字、API 名稱)不受此規則限制。完整適用範圍表、編碼要求與替換表的唯一來源:references/ste100.md。
  2. 技能文件(SKILL.md)整份為英文:frontmatter 與內文都是。風格比照 STE100:短句、祈使句、術語一致。
  3. 技能文件裡「要原樣輸出的繁中字面內容」保留繁中:wiki 狀態字串(例:已分析、未完成)、hook 注入文字、要寫進 wiki 或 commit 的文案。技能執行時產生的 commit 訊息、PR 描述、wiki 頁內容仍依第 1 條輸出繁中。
  4. README、AGENTS.md、templates/、references/ 為 STE100 繁體中文。中文並列項用頓號「、」,不用半形「/」;英文項目的並列(CLI 名、頁名前綴)可用「/」。

撰寫規範(SKILL.md 內文)

  1. 每個步驟以可檢核的完成條件結尾(例:「成功標上工作證才可以進入下一步」),不用模糊語(「理解後」「適當地」)。
  2. 用正向敘述寫目標行為;禁止句只留給無法正向表達的硬性護欄。
  3. 每個意義只有單一真實來源:環境可查的資訊(指令、設定、目錄結構)不要抄進技能,只寫環境查不到的慣例、原因與陷阱。
  4. 漸進揭露:所有分支都需要的內容留在 SKILL.md;只有部分分支需要的參考資料下放 references/,以一行指引指過去。
  5. 善用引導詞(WBS、CPM、TDD、seam、STE100 等既有概念)取代整段解釋。

技能行為清單

每個 domain 都要有一份技能行為清單,記下每支技能實際做的事,供稽核與驗證比對。

項目 規則
位置 每個 domain 存取庫的 references/behaviors.md,UTF-8 無 BOM,內容為 STE100 繁體中文
第一行 # jsc-{domain} 技能行為清單
節 每支技能一個 ## {技能名} 節,名稱與 skills/ 底下的目錄名逐字相同,節數與技能支數一樣,排列照目錄名的字典序
表格 每節恰好一張表,表頭兩欄依序是「項目」與「內容」,五列依序為 觸發時機、關鍵步驟、外部呼叫、完成條件、可驗證跡象,每一列的「內容」欄都不得空白
寫什麼 寫技能實際的行為:什麼情況會用、什麼情況不該用、依序做了哪些事、呼叫哪些腳本與技能、做到什麼程度算跑完、跑完在環境裡留下哪些查得到的跡象。不要抄 description 的行銷語
純唯讀的技能 「可驗證跡象」欄寫「無寫入跡象,只有回報內容」,不得留白
更新時機 技能異動時在同一個 PR 內一起更新:新增技能就加一節、刪除就移除該節、改行為就改該節
檢查腳本 jsc-meta/tools/check-behaviors.sh {domain-path}

check-behaviors.sh 的結束碼分流:

結束碼 意義
0 行為清單與 skills/ 相符,五個欄位齊全且內容欄非空
1 不符:缺節、多節、順序不對、表格不對、缺欄位或欄位空白,逐項印在 stderr,照著修再重跑
2 用法錯誤:本腳本只吃一個參數
3 找不到 references/behaviors.md、找不到 skills/,或 skills/ 底下一支 SKILL.md 都沒有。什麼都沒查,不等於通過,先補齊檔案再重跑

為什麼一個 domain 一份,不集中在 jsc-meta。 技能改動與行為清單放同一個存取庫,才進得了同一個 PR;審的人在一頁 diff 上就看得出行為改了、清單也改了。集中在 meta 的話,改一支技能要開兩條 PR,一條在 domain、一條在 meta,兩條互相等待,先併的那條讓清單與技能對不上,稽核抓到的是自己造出來的漂移。跨存取庫的東西沒有原子性,同一份事實就不要拆兩邊放。

環境變數

變數 用途 未設定時
GITEA_HOST Gitea 站台(例:https://gitea.jsc.idv.tw) 詢問使用者
GITEA_TOKEN Gitea API token 改用 tea 登入金鑰(tea login list);tea 也沒有才詢問使用者
JSC_WIKI_REPO_QUESTION QUESTION_CONTENTS、QUESTION_{HASH} 所在的 {owner}/{repo} 退回 JSC_WIKI_REPO
JSC_WIKI_REPO_PLAN PLAN_CONTENTS、PLAN_{HASH} 所在的 {owner}/{repo} 退回 JSC_WIKI_REPO
JSC_WIKI_REPO_ANALYZE ANALYZE_CONTENTS、ANALYZE_{HASH} 所在的 {owner}/{repo} 退回 JSC_WIKI_REPO
JSC_WIKI_REPO_DELIVER DELIVER_CONTENTS、DELIVER_{HASH} 所在的 {owner}/{repo} 退回 JSC_WIKI_REPO
JSC_WIKI_REPO_MAINTAIN MAINTAIN_CONTENTS 所在的 {owner}/{repo}(本類型只有目錄頁) 退回 JSC_WIKI_REPO
JSC_WIKI_REPO_REPO REPO_CONTENTS、REPO_{HASH} 所在的 {owner}/{repo} 退回 JSC_WIKI_REPO
JSC_WIKI_REPO_LOG LOG_CONTENTS、LOG_{HASH} 所在的 {owner}/{repo} 退回 JSC_WIKI_REPO
JSC_WIKI_REPO_LEARN LEARN_CONTENTS、LEARN_{HASH} 所在的 {owner}/{repo} 退回 JSC_WIKI_REPO
JSC_WIKI_REPO_ERROR ERROR_CONTENTS、ERROR_{HASH} 所在的 {owner}/{repo} 退回 JSC_WIKI_REPO
JSC_WIKI_REPO_CHECK CHECK_CONTENTS、CHECK_{HASH} 所在的 {owner}/{repo} 退回 JSC_WIKI_REPO
JSC_WIKI_REPO_REPORT REPORT_CONTENTS、REPORT_{HASH} 所在的 {owner}/{repo} 退回 JSC_WIKI_REPO
JSC_WIKI_REPO_SKILLSET SKILLSET_CONTENTS、SKILLSET_{HASH} 所在的 {owner}/{repo} 退回 JSC_WIKI_REPO
JSC_WIKI_REPO_TOOLING TOOLING_CONTENTS、TOOLING_{HASH} 所在的 {owner}/{repo} 退回 JSC_WIKI_REPO
JSC_WIKI_REPO 未逐類設定時的共用 wiki {owner}/{repo} 詢問使用者
JSC_HOME Hook 資料目錄 預設 ~/.jsc
JSC_PR_WATCH_INTERVAL jsc-gitea/tools/pr-watch.sh 輪詢 PR 狀態的間隔秒數 預設 60
JSC_RESTART_GATE 部署後重啟閘門的開關,off 關閉整道閘門 閘門開啟

頁面類型只讀自己的 JSC_WIKI_REPO_{TYPE}。只有該變數未設定時,才退回 JSC_WIKI_REPO。不得跨類型代用。

版本前置檢查

技能組的每一支技能在被呼叫前都要過兩道版本檢查:本機載入版本沒有落後遠端發佈版本,以及這支技能所屬 plugin 宣告的 jsc.requires 每一項都吃得到。兩道判定都在程式層,由 jsc-hooks 的 version-guard.sh(PreToolUse,matcher Skill)執行,不靠技能內文自我約束——寫在內文的規則,模型可以無視。

兩道都只擋「確定落後」一種情況。查不到任何一項基礎資訊就安靜放行(exit 0),不要求先修好環境:五支 CLI 只有 claude 讀得到本機載入版本,fail-closed 會把另外四支整批鎖死。

項目 規則
比對對象 遠端發佈版本(存取庫預設分支的 plugin.json,經 jsc-gitea/tools/gitea.sh 讀取,不寫死分支名)對本機實際載入版本
實際載入版本 只認 installed_plugins.json 的 installPath 底下那份 plugin.json。註冊在 installed_plugins.json 的 version 欄位不當備援——註冊值可能比實際載入的版本新,拿它來比對會放過真正被載入的舊版
落後 擋下該次技能呼叫(exit 2),並印出更新指令
相等或超前 放行。開發技能組時本機本來就會超前預設分支,擋下去維護者自己動不了
查不到本機載入版本 放行(exit 0,安靜降級)。讀不到 installed_plugins.json、裡面沒有該 plugin 的條目、取不到 installPath、installPath 底下那份 plugin.json 讀不到,四種都算這一列,不退回註冊欄位
解不出 Gitea 站台 放行(exit 0,安靜降級)
查不到遠端版本 放行(exit 0,安靜降級)。缺基礎設施不等於落後,擋下去會把四支非 Claude CLI 整批鎖死
相依版本落後 這支技能所屬 plugin 的 jsc.requires 有一項落後就擋下該次呼叫(exit 2),印出缺哪一個 plugin 的哪一版與更新指令。版本比對由 version-guard.sh 自己實作,不呼叫 jsc-cli/tools/check-requires.sh:hook 專屬存放於 jsc-hooks(見「Hook 規則」第 1 條),而且 jsc-cli 已宣告相依 jsc-hooks,反過來呼叫會做出循環相依。兩支的比法要保持一致,改動任一支就回頭核對另一支
相依版本相等或超前 放行。每一項都吃得到才算過
查不到相依資訊 放行(exit 0,安靜降級)。解不出這支技能所屬 plugin 的安裝路徑、讀不到它的 manifest、manifest 沒有 jsc.requires、查不到某一項相依 plugin 的本機載入版本,四種都算這一列
逃生門 JSC_VERSION_GUARD=off(離線工作用),快取秒數 JSC_VERSION_TTL(預設 600)

豁免清單(永遠放行,改動前想清楚後果):

技能 為什麼不能擋
jsc-cli:deploy 更新整組技能的入口。擋了就沒有任何方法更新,形成死鎖
jsc-hooks:hooks-install 更新後要重新接線,擋了會讓更新做一半卡住
jsc-hooks:repair hook 壞掉時的唯一修復路徑。擋了就修不好 hook
jsc-cli:models SDLC 階段閘門依賴它產生 model-tags.tsv
jsc-meta:* 開發技能組本身的工具,擋了就修不了技能組
jsc-ask:ask 上面幾支都要問使用者
jsc-gitea:wiki 上面幾支的收尾要寫 wiki

共 7 項。兩道檢查共用這一份清單,不另立一份。 豁免的理由兩道完全一樣:這幾支是解除落後的唯一路徑,擋了就沒有東西能把版本補上來。分成兩份只會兩邊漂移,改了一份、忘了另一份,deploy 照樣被相依版本擋死。這張表的唯一真實來源是 jsc-hooks/hooks/version-guard.sh 的檔頭與豁免清單,兩邊要逐項對齊。

相依版本檢查移到這裡,是因為 deploy.sh update 原本會跳過不符的 domain,跳過就永遠更新不到,理由見「Manifest 相依版本」第 5 條。更新照跑、呼叫才擋,落後的 domain 才有路徑補上來。

沒有 pre-tool hook 的 CLI 接不上這道檢查,hooks-install 要據實回報,不得暗示每個 CLI 都有保護。

部署後重啟閘門

部署換掉的是磁碟上的技能檔,目前工作階段載入的還是舊版。這段落差期間跑技能,改動看起來沒生效,人會以為部署失敗又重跑一次。

項目 規則
狀態檔 $JSC_HOME/restart-required.d/{cli},一支 CLI 一份,由 jsc-cli:deploy 收尾寫入
清除時機 重啟 CLI 之後由 jsc-hooks 清除自己那一份,不必手動刪
該 CLI 那份存在時 擋下這支 CLI 的 jsc 技能呼叫,印出要重啟哪一支與狀態檔路徑
該 CLI 那份不存在時 放行。別支 CLI 的狀態檔不影響這一支
判定位置 程式層,由 jsc-hooks 執行,不靠技能內文自我約束
逃生門 JSC_RESTART_GATE=off

豁免清單(狀態檔存在也放行):

技能 為什麼不能擋
jsc-cli:deploy 部署本身的入口。擋了就沒有方法重跑部署,形成死鎖
jsc-hooks:hooks-install 部署後要重新接線,擋了會讓部署做一半卡住
jsc-hooks:repair hook 壞掉時的唯一修復路徑。擋了就修不好 hook
jsc-gitea:wiki 寫 SKILLSET_{HASH} 異動報告與工作日誌的唯一路徑
jsc-log:worklog 部署後還要結清工作日誌
jsc-log:learn 部署後還要記這次的教訓
jsc-meta:* 開發技能組本身的工具,擋了就修不了技能組
jsc-ask:ask 上面幾支都要問使用者。擋了 deploy 連 install 或 update 都問不出來
jsc-git:pr 報告與異動的收尾要開 PR,擋了收尾做不完
jsc-git:commit 同上,pr 的第一步就是它

豁免這幾支的理由是同一件事:jsc-meta 四支異動技能的收尾要求把驗證結果寫進 SKILLSET_{HASH},還要結清工作日誌,而這條路徑必經 jsc-gitea:wiki 與 jsc-log。全擋的話,部署一跑完就沒有路徑寫完報告,重啟閘門與報告要求互相打死。閘門不自鎖的通則見「審核檢查清單」的流程檢查第 4 項。共 10 項;這張表的唯一真實來源是 jsc-hooks/hooks/restart-gate.sh 的檔頭與豁免清單,兩邊要逐項對齊。

豁免清單不是自鎖的通解。 部署剛跑完就要在同一個工作階段叫用剛做好的技能,那支技能本來就不該靠豁免過關——豁免只擋得住這一道閘門,擋不住「行程還載著舊版」這個事實,驗證結果會是舊版的行為。正解是換一個工作階段:由 jsc-cli/tools/detect-clis.sh 開出的新 CLI 行程去叫用,新行程自己會清掉那份狀態檔,載到的也是新版。做法見 deploy-verify.md。

狀態檔為什麼一支 CLI 一份。 這道閘門管的是「這支 CLI 的行程還在跑舊版」,那是每支 CLI 各自的事實。初版用全機器單一檔案,2026-08-27 部署時實測出兩個後果:並行部署互相覆蓋,cli= 與 domains= 只留最後一支;更嚴重的是清除也是全域的,任一支 CLI 重啟就解除全部五支的閘門,其餘四支沒重啟卻不再被擋,這道閘門在多 CLI 環境等於半失效。改成 per-CLI 之後,require 寫自己那份、判定只看自己那份、clear 只刪自己那份,report 才列得出「哪幾支還沒重啟」。跨 CLI 或跨工作階段的狀態檔,設計時先問清楚那個事實屬於誰——同一類錯誤在工作包歸屬狀態檔上也踩過,解法見 jsc-sdlc/tools/wp-gate.sh 的 claim 與 owns:claim 在領包當下把歸屬登錄成「這個存取庫目前是哪一包」,owns 查驗每支 PR 是不是自己那一包的,兩層各管一件事實,狀態檔也刻意不綁工作階段。

清單認的是技能名,不是呼叫鏈。 豁免技能轉呼叫的下一層若不在清單上,那一層照樣會被擋。後三支(jsc-ask:ask、jsc-git:pr、jsc-git:commit)自己不是收尾規則的主體,是為了讓前七支走得完才補進來的。version-guard.sh 的豁免清單當年也是為同一個原因收進 jsc-ask:ask。新增豁免技能時要一併想它會呼叫誰。

Wiki 頁命名總表

所有 wiki 頁面一律採雙層命名。MAINTAIN 是唯一只有目錄頁的類型,理由見表下:

類型 目錄頁 內容頁 用途 擁有者
QUESTION QUESTION_CONTENTS QUESTION_{HASH} 問詢目錄、單一存取庫的問詢紀錄 jsc-ask
PLAN PLAN_CONTENTS PLAN_{HASH} 計畫目錄、計畫頁 jsc-sdlc
ANALYZE ANALYZE_CONTENTS ANALYZE_{HASH} 分析目錄、分析頁 jsc-sdlc
DELIVER DELIVER_CONTENTS DELIVER_{HASH} 交付目錄、工作包交付文件 jsc-sdlc
MAINTAIN MAINTAIN_CONTENTS 無 維護登記目錄:登記進維護期的專案、維護方式、起訖日期與前次維護時間 jsc-sdlc
REPO REPO_CONTENTS REPO_{HASH} 盤點目錄、存取庫盤點頁 jsc-sdlc
LOG LOG_CONTENTS LOG_{HASH} 日誌目錄、工作日誌頁 jsc-log
LEARN LEARN_CONTENTS LEARN_{HASH} 教訓目錄、技能教訓頁 jsc-log
ERROR ERROR_CONTENTS ERROR_{HASH} 異常目錄、異常頁 jsc-hooks
CHECK CHECK_CONTENTS CHECK_{HASH} 體檢目錄、執行環境體檢頁 jsc-cli
REPORT REPORT_CONTENTS REPORT_{HASH} 報表目錄、工作報表頁(年、月、週、日各一頁) jsc-log
SKILLSET SKILLSET_CONTENTS SKILLSET_{HASH} 技能組異動目錄、技能組異動報告頁(新增、更新、刪除、批次更新之後的驗證結果與改動清單) jsc-meta
TOOLING TOOLING_CONTENTS TOOLING_{HASH} 技能盤點目錄、單機單 CLI 的技能盤點頁:一台機器上某一支 CLI 的已安裝 plugin 與版本、可用技能、hook 接線狀態 jsc-meta

MAINTAIN 沒有內容頁。維護登記全部寫在 MAINTAIN_CONTENTS 的表格裡:jsc-sdlc:implement 只往那一頁附加登記,jsc-sdlc:maintain 只讀那一頁再回寫「前次維護時間」,兩支都沒有產生 MAINTAIN_{HASH} 的步驟,jsc-sdlc/templates/ 也沒有對應範本。總表以前列著這個內容頁,照著找只會找到一個不存在的頁。要補內容頁就先補技能步驟與範本,不能只在總表上寫著。

{HASH} 一律為 {owner}/{repo}(必要時加上主題字串)的 SHA-1 前 8 碼,大寫。 若第一碼是 0-9、A、B、C,就改成 H 加上原 SHA-1 前 7 碼,總長仍維持 8 碼。 同一規則套用到所有目錄頁與內容頁。

REPORT 用得到那個主題字串:雜湊來源為 {owner}/{repo}/{期間},期間是 daily、weekly、monthly、yearly 其中之一。 年、月、週、日各自一頁,每頁內依期間累積分節。

SKILLSET 的雜湊來源就是被改動的 domain 存取庫 {owner}/{repo},算法同上,由同一支 jsc-gitea/tools/hash-id 產生。 頁內累積歷次異動:每次異動附加一節,不覆蓋舊紀錄。要看一支技能改過幾次,就在同一頁上翻。

CHECK 是唯一例外:它記的是一台執行環境,不是一個存取庫,所以雜湊來源為 {主機名}/{登入帳號}。 8 碼與 H 前綴的算法完全相同,由同一支 jsc-gitea/tools/hash-id 產生。 在沒有存取庫的目錄也跑得出體檢,是這個例外存在的原因。

TOOLING 記的也是機器層事實,雜湊來源再多一段:{主機名}/{工具名稱}/{登入帳號}。 {工具名稱} 是 CLI 代號,取自 jsc-cli/tools/detect-clis.sh 輸出的第一欄,值為 claude、codex、copilot、antigravity、kiro 其中之一。 一台機器、一支 CLI、一個帳號各一頁;算法同上,由同一支 jsc-gitea/tools/hash-id 產生。

為什麼要帶工具名稱。 每支 CLI 各有自己的已安裝 plugin 集合,也各有自己的 hook 接線狀態,那是五組互相獨立的事實。 少了中間那一段,同一台機器上五支 CLI 會算出同一個雜湊,五份盤點互相覆蓋,最後只剩最後寫入的那一支,讀的人卻看不出被蓋掉。 帶上工具名稱,一支 CLI 就有一頁,換一支 CLI 重跑也不會動到別支的頁。

審核檢查清單

新增或更新技能後逐項檢查,任一不符就修正:

  • 名稱符合命名規則,且與既有技能目標不重複
  • description 為英文、≤ 5 句或 ≤ 5 步驟(滿足任一即通過)、含觸發時機(何時用、何時不用)
  • 可 hook 的規則已下放 jsc-hooks;可工具化的流程已下放 tools/;SKILL.md 沒有保留可由標準輸入輸出執行的細節流程
  • 細節流程已標示 MUST run as a sub agent
  • gitea 操作透過 gitea.sh 或 tea
  • wiki repo 與 Gitea 認證先讀目前 shell 繼承的環境變數;只有缺值或無法解析時才詢問;頁面類型不得跨用其他 JSC_WIKI_REPO_{TYPE}
  • 問詢透過 jsc-ask 決策樹規則
  • tools/ 與 hooks/ 內的 shell 腳本都通過 sh -n;技能直接呼叫的腳本都存在、可執行,且退出碼有分流
  • hook 相關變更已用 jsc-hooks/tools/wire-cli.sh smoke {cli} 實測;沒有偵測到 CLI 時,至少跑 smoke codex 並標明是預設 hook smoke。行數讀腳本自己印的 lines 那一行,技能與 README 都不得寫死數字——腳本會自我斷言,抄一份數字進文件,加減判定路徑時就漂移,稽核反而被舊數字誤導
  • 唯讀的稽核與體檢流程呼叫 wire-cli.sh 時帶 JSC_READONLY=1:打錯子命令就由程式擋下(exit 6),不靠呼叫端自我約束;status 與 smoke 不受影響
  • SKILL.md 整份為英文(要原樣輸出的繁中字面除外);README、AGENTS、templates、references 為 STE100 繁中;UTF-8 無亂碼
  • 所有非程式碼輸出(程式碼註解、commit 訊息、PR 描述、wiki 頁、回報、文件)為繁體中文、UTF-8、無亂碼、無簡體字,且 tools/ste100-lint.sh 對該 domain 全綠
  • 該 domain 的 references/behaviors.md 與 skills/ 相符,tools/check-behaviors.sh {domain-path} 對該 domain 退出 0;退出 3 是「什麼都沒查」,不算通過
  • 已同步更新該 domain 的 README「Skills 目錄」與三份 manifest 的 version
  • PR 的 base 符合「PR 分支階梯」,沒有越級

流程檢查四項,對照技能自己的流程逐項確認:

  • 技能內外引用的步驟編號、檔案路徑、節標題都真的存在,指標指得到。踩過的實例:規則搬到 references/ 後指標指向空處,照著指過去只看到空白
  • 每個步驟以可檢核的完成條件結尾,沒有「理解後」「適當地」這類模糊語
  • 每個外部呼叫(腳本、API、其他技能)的失敗情況都有明寫怎麼辦,退出碼都有分流
  • 技能自己裝的閘門不會擋掉解除那道閘門的唯一路徑(閘門不自鎖)。踩過的實例:工作包閘門若擋掉 implement,結清 PR 就沒有路徑