開場:五次裡被跳過五次,一行就修好
Claude Code 的 skill 可以在你用名稱呼叫時完美執行,卻永遠不會自己載入。我們的 skill 每次打出名稱都能跑,但只要用平常的話要求同一件事,每一次都被跳過。我們看著它被跳過,讀出原因,再改寫那一行,問題就解決了。
skill 是一組儲存好的指令,當你的請求符合時,Claude Code 會自己載入。決定是否符合的,是 Claude 在選擇之前讀的一行字,而不是你寫的指令。下面六個步驟會帶你從你一直重打的 prompt,走到一個會自己載入的 skill,另外還有一個二十個請求的測試,能在團隊發現之前抓出被跳過的 skill。
| 測試(同一個請求,全新 session) | skill 是否載入 |
|---|---|
用名稱呼叫(/release-notes) |
2 of 2 |
| 平常的話,原本的描述 | 0 of 5 |
| 平常的話,改寫後的描述 | 5 of 5 |
第一步:skill 是什麼,以及值得做成 skill 的 prompt
skill 是一個資料夾,裡面只有一個檔案 SKILL.md。檔案開頭是一小段標頭(名稱加上一句話的描述),後面接著指令。它就像一個函式:呼叫者讀的是簽名和 docstring,函式本體只有在被呼叫時才會執行。把它存在你的家目錄,每個專案都能用;存在 repository 裡,所有在那裡工作的人都能用。
從任務開始,而不是從檔案開始。挑出你一直重打的 prompt,寫下你想要的確切輸出。我們的是每週的 release notes:週一以來的 commit,依區域分組,雜務類的捨棄,每項變更一行,並附上 pull request 編號。在開源的 Hono repository 上,那段很長的 prompt 為當週的八個 bug 修正產生了乾淨的說明,而那份輸出就成了 skill 必須達到的目標。
第二步:寫 SKILL.md,並用名稱執行
在你的專案裡建立 .claude/skills/release-notes/SKILL.md:隱藏的 .claude 資料夾裡有一個 skills 資料夾,裡面是以 skill 命名的資料夾,skill 檔案就放在其中。資料夾這一層很重要。單獨放一個 release-notes.md 完全不會載入,文件也把這點列為第一個要檢查的項目。
標頭是夾在兩行破折號之間的幾行帶標籤的文字,而且必須從檔案的第一行開始,否則 Claude Code 會忽略它。我們的標頭有名稱 release-notes,以及大多數人都會寫的那種描述:
---
name: release-notes
description: Generates changelog documents from repository history.
---
標頭下面是編號步驟的指令,就是你會交給新同事的那種。我們的有五步:找出週一以來的 commit、捨棄 chore 和 docs 的 commit、依 conventional-commit 的 scope 分組、每項變更寫一行平實的句子,最後輸出一個有標題的區塊,頂端附上簡短摘要。Anthropic 建議這部分保持簡短。你不需要重新啟動:Claude Code 會在你目前的 session 裡直接讀到新增或修改過的 skill。
用名稱測試:輸入斜線,在選單裡選擇這個 skill,按下 enter。在全新 session 裡,我們的 skill 每次都讀了 commit log,依區域把修正分好組,並完全照我們要的方式寫出說明。問題在於,你和你團隊的每個人都得記得它的名稱。
第三步:全新 session、平常的話,五次裡跳過五次
你的同事不會打出 skill 的名稱。他們會開一個新的 session,像問你一樣直接開口。所以就測這個:開一個全新的 session(一段什麼都還沒載入的新對話),用你自己的話要求這個任務。一定要是全新的,因為已經用過的 skill 會留在對話裡,在那個 session 裡測試什麼也證明不了。
我們輸入「what did we ship this week?」。Claude 自己跑了 commit log,用它自己的方式寫了一份摘要,完全看不到 skill 的影子。這些回答不算差,但每次都不一樣:有一次從週一開始算,另一次從上一個 release tag 開始算,還帶進了一項 skill 本來會捨棄的 docs 變更。在五個全新 session 裡,skill 五次全都被跳過。
五次只是示範,不是統計。但一個用名稱能跑、用平常的話卻每次都被跳過的 skill,並沒有做好它的工作;而且因為它在第二步通過了名稱測試,你根本不會想到去檢查。
第四步:先讀原因再改:Claude 只看得到描述
在改任何一個字之前,先做三項檢查:
/skills會列出 session 看得到的每個 skill。在裡面搜尋你的 skill。我們的 skill 有列出,而且是開啟的,但我們的環境裡有 277 個 skill,好幾個外掛 skill 都比我們的更早符合「release」。claude --debug會寫出 Claude Code 載入內容的詳細 log。找出 skills 相關的那幾行。我們的 log 顯示專案 skill 已載入,同時也有一則警告:skill 清單超出預算,所以部分描述會被截掉。claude plugin validate .claude/skills會檢查標頭格式是否正確。這項很重要:標頭壞掉時,skill 仍然可以用名稱執行,但 Claude 再也無法自行比對它。我們的通過了。
| 檢查 | 它告訴你什麼 | 我們的結果 |
|---|---|---|
/skills |
skill 看得到而且是開啟的嗎? | 有列出,已開啟(277 個 skill) |
--debug |
有載入嗎?清單有被截掉嗎? | 已載入;清單超出預算的警告 |
plugin validate |
標頭能解析嗎? | 通過 |
檔案已載入、標頭有效,原因就出在描述。在決定載入一個 skill 之前,Claude 不會讀你的指令。它對每個 skill 只讀一行,也就是名稱和描述,然後拿去比對你說的話。我們的寫的是「generates changelog documents from repository history」,請求說的是「what did we ship this week」。這兩句話沒有任何共同的字。Claude 從來沒讀過我們的指令;它讀的是一行字,而那一行字沒有用我們的話。
預算警告的意思是,Claude Code 會裁短描述來符合限制,先裁最少使用的 skill,而全新的 skill 正是最少被使用的。檢查一下你的有沒有被留下來:我們的有,因為用它自己的字寫的請求仍然能載入它。
第五步:改寫那一行,再驗證:五次全中,關掉再打開
描述要為有人開口要求的那一刻而寫,而不是為檔案而寫。說明這個 skill 做什麼、何時使用,以及人們真正會打的字。我們的變成:
description: Writes this week's release notes from git log, grouped by scope (router, css, jsx). Use when the user asks what we shipped, what changed this week, for release notes, a changelog, or a summary of recent commits.
Anthropic 的撰寫指南還加了一條規則:用第三人稱寫(「Writes」),不要寫「I can help」或「You can use this」。
接著在全新 session 裡用同一個請求來驗證。「What did we ship this week?」這次在 Claude 動手之前就載入了 skill,說明也照我們的格式產出,五個全新 session 裡五次全中。
再做一次基準線:在你的本機設定檔裡用 skill override 把 skill 關掉(這只會隱藏 skill,不會刪除)。關掉時,Claude 回到它自己的摘要;打開時,skill 就載入了。造成差異的是 skill,不是運氣。
限制是:描述如果涵蓋太廣,skill 會在不該觸發的地方觸發。加進你真正會用的字,而不是你想得到的每一個字。
第六步:在團隊發現前先做觸發測試,以及必須觸發的 skill
一個請求證明了修正有效;但團隊倚賴的 skill 會被用各種方式要求。Anthropic 的 skill-creator 描述了這個測試:二十個請求,混合了應該載入 skill 的請求,以及不該載入的近似請求。近似請求聽起來很像,但其實是另一件工作,例如「write a commit message for my staged changes」。每個請求都在各自的全新 session 裡執行,並記錄 skill 有沒有載入。skill-creator 自己的腳本在我們的 Claude Code 版本上看不到這個 skill,所以我們用自己寫的一小段腳本跑了同樣的二十個請求。
| 描述 | 應載入而確實載入的請求 | 誤觸的近似請求 |
|---|---|---|
| 原本 | 4 of 10 | 0 of 10 |
| 改寫後 | 10 of 10 | 0 of 10 |
改寫之前,skill 只會在請求本身已經包含「release notes」、「changelog」或「release」時載入:這就是第四步提到的字詞比對,明擺在眼前。改寫之後,每個應該載入的請求都載入了,而且仍然沒有任何一個近似請求誤觸。
對於絕不能漏掉的 skill,就強制它。輸入它的名稱,或加上一個 hook(Claude Code 在固定時機執行的小腳本,這裡是在你每次送出訊息時),讓 hook 的輸出告訴 Claude 這項任務要用這個 skill。有了 hook,即使是原本的描述,也能在平常的請求上載入。限制是:每次測試都會消耗實際用量,而且 hook 會為每則訊息多加一行,所以只留給少數真的必須觸發的 skill。每次修改描述時,都要重新跑一次你的清單。
結論:skill 何時划算、何時不划算,以及那條規則
我們的 release-notes skill 用名稱呼叫時每次都能運作,用平常的話要求時在每個全新 session 裡都被跳過,而改寫的一行讓它每次都載入。原因是:Claude 在決定之前,對每個 skill 只讀一行,而且它比對的是你說的字,不是你的意圖。
skill 值得用在你會重複、而且輸出固定的任務:每週說明、pull request 描述、release 檢查清單。一次性的問題不值得,而且它也不是用來處理必須永遠成立的規則的工具,那是 hook 的工作。一大堆沒在用的 skill 也會讓你付出代價,因為 skill 太多時,Claude Code 會開始裁掉描述,先裁最少使用的。好的描述能提高機率,但無法讓 skill 為它本來就不該處理的工作觸發;幾次執行只是示範,所以你自己那份測試請求清單才是真正的檢查。
那條規則:用你要求這項任務時真正會打的字,來寫描述。
AIDive