# 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-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`](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`](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 就沒有路徑