昨天結尾那條 /mike 會把超過 90 天沒動的指令和 skill 標成 ⚠️,我說那一區通常就是我不記得的東西。今天先把它拿去查自己:它列出的 14 個 skill 裡,官方的 docx/pptx/pdf、社群的 graphify/humanizer 都不是我寫的;我自己寫、而且這個文章 repo 用得到的是五個。這五個現在還有幾個活著?
數完自己的,再講另一半:昨天那種一個檔的,官方現在也叫 skill;那些看起來只是設定的東西 —— frontmatter、會不會被 Claude 自動叫、放在哪一層 —— 決定了一個 skill 活不活得下來,也決定了裝來的 skill 該不該直接裝。
Skill 的宣稱是把工作流程沉澱成資產:寫一次,以後不用重講。這句話裡有一個沒說出口的假設 —— 寫下來的東西會一直被用。今天驗的就是這個。
我自己寫的 skill 有五個。翻了本機 55 天的對話紀錄(7/20 到 9/12),加上 /mike 的最後改動時間,結果長這樣:
| Skill | 做什麼 | 55 天內被叫 | 判定 |
|---|---|---|---|
md-single-html |
md → 單一自帶圖片的 HTML | 1 次(8/18,Claude 自己叫的) | ✅ 活著 |
gen-table-image |
md 的表格 → 風格一致的 PNG | 0 | ❌ 已被取代 |
convert-docx |
md → Word,自動修表格框線 | 0 | 🟡 休眠 |
clean-legacy |
刪被註解掉的遺留碼 | 0 | ⬜ 數錯地方(上班天天用,在家沒用) |
clean-check |
驗證 clean-legacy 只動到註解 | 0 | ⬜ 數錯地方(同上) |
(.claude/skills/ 不進版控,clone 下來看得到的是備份 tools/skills/;為什麼這樣會有問題,下面第五點。)
四個零。但這四個零不是同一種零,下一節拆開講。先講證據最硬的那個。
gen-table-image 為什麼變成零,不用翻紀錄:story/ 底下有 21 個 gen.sh,每一篇文章各自帶一份。表格圖天天在產,沒有一次是透過那個 skill 產的。
更值得記一筆的是:這件事 repo 的 CLAUDE.md 自己早就寫下來了 ——「gen-table-image 目前未列在啟用的 skill 清單中,所以實務上用各篇的 gen.sh 產表格圖」。也就是說我知道它死了,只是從來沒把這件事當成一個問題。
把四個零攤開來看,它們的意思不一樣,而且每一種要的處理方式都不同。
第一種零:被在地腳本取代(gen-table-image)
Skill 是通用的,gen.sh 是這一篇專用的。當每篇文章的表格都需要一點點微調(欄寬、換行、要不要粗體),通用版就永遠差一點,而複製一份改比呼叫一次快。
這是最值得警惕的一種零,因為它看起來像是效率:每次複製 gen.sh 都只花 10 秒。但 21 份 gen.sh 意味著改一次風格要改 21 個地方。
而這件事已經發生過一次。9/10 我發現 playwright 升了新版,本機沒有 headless shell,截圖會靜默失敗 —— 不報錯,就是沒有圖。修法是加一個 --channel=chrome,於是我改了 21 支 gen.sh,一次 commit。寫這篇回頭看 skill 的 SKILL.md,那行 npx playwright screenshot 沒有 --channel=chrome。21 個地方都改了,漏掉的是第 22 個 —— 它們被複製出來的源頭。所以寫這篇之前,這個 skill 不只是沒人用,是打了也會安靜地失敗。
(寫到這裡順手補上了。真正執行截圖的是 skill 目錄裡那支 gen_tables.py,加一個 --channel=chrome,拿 0904 那篇跑一次,4 張表全部產出。所以它現在是「活著但沒人叫」,Day 30 再數一次的時候,看它有沒有被叫過。)
誤判:數錯地方(clean-legacy / clean-check)
這兩個第一版我判的是 ❌,理由寫得很順:「這一年主要工作從改舊專案轉成寫文章,這個 repo 裡根本沒有遺留碼可以清。」
寫完才想到不對。這兩個是上班用的 —— 公司好幾個有年紀的 iOS 專案都有同一種病:到處是被註解掉還捨不得刪的舊碼。不管在哪一個裡面,我清一段就跑一次 clean-legacy、再跑 clean-check 確認 diff 只動到註解。它們是我工作日裡真的天天在用的兩個。
但寫文章是在家裡這台電腦,文章 repo 裡沒有一行遺留碼可以清。我翻的是這台電腦、這個 repo 的對話紀錄,它們在這裡當然是零,就像在廚房裡數不到螺絲起子。 零不是它死了,是我數的地方數不到它 —— 它活在另一台機器、另一個 repo 裡。
這比第一種零更值得記,因為它差一點就進了「已死」清單,而理由聽起來完全合理。數到零的時候,先問你數的地方數不數得到它,再問它是不是死了。 要數這兩個,得去公司那台電腦的紀錄裡數,那不在這篇的範圍。
第二種零:一次性需求(convert-docx)
轉 Word 是偶發的 —— 有人要 .docx 才用。它會在未來某一天再被用一次,然後再睡半年。
這種其實是健康的。不是每個工具都需要天天用,問題只在於你要不要為了它維護一整套 skill。
但它睡著的時候位子可能被佔掉。9/11 我裝了官方的 docx skill,做的是同一件事(Markdown → Word),而且紀錄裡它已經有一次呼叫、convert-docx 零次。它還沒正式取代 convert-docx —— 那一次是我拿它跟 pandoc 對照的實驗 —— 但下次有人要 Word 檔的時候,我大概不會去翻自己那份了。
md-single-html 是五個裡面最晚寫的,也是唯一有呼叫紀錄的。
它的需求很具體:朋友或同事想快速看一篇我還沒發的文章,但他們不讀 Markdown —— 一包資料夾加一堆 .png,對不寫程式的人是障礙。所以要一個雙擊就能開、圖都在裡面、長得像 Medium 的單一 HTML 檔。
差別不在它比較好用,在於它解決的問題沒有在地版本。要把一篇帶圖的文章變成單一 HTML 檔傳給別人看,沒有一個「複製一份改一改」的替代路徑 —— 圖片要 base64 內嵌、註解要略過、placeholder 要清掉,這些每次都一樣。而且需求來自別人不是我,所以它不會因為我換一種寫法就消失。
所以存活的判準浮出來了:
如果這件事「複製一份腳本改一改」比較快,那它終究會變成 21 個
gen.sh。 Skill 只在「每次都一樣、而且沒有在地捷徑」的地方活得下來。
數完之後我回去把 skill 的官方文件從頭讀了一次。有五件事,早知道的話上面那張表會不一樣。
一、Claude 平常只看得到 description。 SKILL.md 的本文要等被叫到才載入;沒被叫到之前,它在 Claude 眼裡就是那一行描述(跟 when_to_use 加起來超過 1,536 字會被截斷)。所以一個 skill 會不會被自動用,幾乎只取決於那一行有沒有對上你講話的方式。md-single-html 唯一那次呼叫是 Claude 自己叫的 —— 我說「轉成 HTML 傳給人看」,描述裡剛好就是這幾個字。
昨天說過兩種寫法都是 /x。這頁開頭說目錄格式「多了」讓 Claude 自動載入的能力,往下翻又寫 .claude/commands/ 的檔「支援同樣的 frontmatter,只少 name 和 paths」—— 同一頁兩種說法。我做了一個實驗:乾淨 repo 一邊放 .claude/commands/apple.md、一邊放 .claude/skills/pear/SKILL.md,description 各寫一句觸發句,然後用白話問「幫我數蘋果」、「幫我數梨子」,不打斜線:
幫我數蘋果 → Skill {"skill": "apple"} → APPLE-COMMAND-LOADED
幫我數梨子 → Skill {"skill": "pear"} → PEAR-SKILL-LOADED
兩種都被自動叫了。 所以差別只剩補充檔和 paths;要不要它自己出現,兩種都靠這一行 description,不要就加 disable-model-invocation。昨天的 /commit 也一樣 —— 我在文章 repo 說「幫我寫 commit message」,它自己去叫了 /commit。文件兩句打架的時候,跑一次的那份才算。
二、disable-model-invocation: true 會讓它從 Claude 的清單上消失。 這個欄位的用意是給有副作用的 skill(部署、寄信):只有你打 /名稱 才會跑,Claude 不能自己決定。它還有一個文件寫在表格裡、很容易漏看的效果:標了的 skill 連 description 都不進 context,你叫到才整份載入 —— 後面「先全部裝起來」那節會講這為什麼是錢。我回頭看五個檔案的 frontmatter:
| skill | 會改檔? | disable-model-invocation |
|---|---|---|
gen-table-image |
會(產 PNG) | 有 |
clean-legacy |
會(刪程式碼) | 沒有 |
convert-docx |
會(產 .docx) | 沒有 → 寫完這篇加了 |
clean-check |
不會 | 沒有 |
md-single-html |
會(產 .html) | 沒有 |
gen-table-image 標了。所以它的死是兩道鎖:Claude 的清單上沒有它,而我又忘了它。 這也解釋了 CLAUDE.md 那句「未列在啟用的 skill 清單中」—— 不是壞掉,是我自己關的。反過來,clean-legacy 會刪程式碼卻沒標,Claude 理論上可以在我沒開口的情況下決定跑它。該標的沒標,不該標的標了。convert-docx 我寫完這篇就標上了 —— 理由在後面那個搶單實驗。
(「會改檔」要分等級:md-single-html、convert-docx 產的是一個新檔,最壞就是多一個檔;clean-legacy 動的是你既有的程式碼。前者讓 Claude 自己來反而是活下來的原因,後者才是這個欄位真正要擋的。)
三、paths 可以讓 skill 只在碰到某些檔案時出現。 gen-table-image 如果拿掉上面那個 disable、加一行 paths: story/**/index.md,它會在我開文章檔的時候自己浮上來。這是「忘記它存在」的技術解法,比 /mike 更早一步 —— 不用你想起來,它在對的地方自己出現。
四、撞名會蓋掉官方的。 文件說同名的優先序是個人 > 專案 > 內建,目錄贏檔案,plugin 的有自己的前綴 /plugin:skill 不撞。這個我也驗了:每一層各放一個同名的,本文只印一行記號 ——
/clash-test 個人層 vs 專案層 → PERSONAL-WINS
/dup-test skills/ 目錄 vs commands/ 檔 → SKILL-DIR-WINS
/code-review 專案層 vs 內建 → MY-CODE-REVIEW
/review 內建的別名 → 跑的還是官方的 review
四條都跟文件一樣。最後一行是坑:你取名 code-review,/code-review 是你的,/review 還是官方的 —— 同一件事兩個入口、兩種行為,而且沒有任何提示。下一節列官方的有哪些,一個用意就是別撞名。
五、放在哪一層,決定誰拿得到。 ~/.claude/skills/ 跟著你走,換 repo 還在,但只有你有;.claude/skills/ 跟著 repo 走,隊友 clone 下來就有 —— 前提是它有進版控。我的五個放在專案層,但 .claude/ 被 .gitignore 擋著,所以它們實際上是個人層的:隊友拿不到,撞名時卻照專案層算。要給團隊用有兩條路:解開 ignore 讓它跟著 repo 走,或做成 plugin 放 marketplace 讓人裝 —— 下一節裝官方那四個用的就是後者。
昨天講內建指令時說過一次,今天 skill 這邊再說一次,因為理由更強:「每次都一樣、沒有在地捷徑」的那些事,官方大多已經寫好了。 你要寫的 skill 如果跟下面某一條撞名,先用它的。
分兩區。第一區跟 Claude Code 一起來,不用裝;第二區要自己裝。
| skill | 做什麼 | 我什麼時候用 |
|---|---|---|
/code-review |
審目前的 diff、或你指定的 PR/分支,找正確性 bug 與可清理的地方 | 開 PR 前。可加強度 low 到 max |
/security-review |
檢查 diff 有沒有安全漏洞 | 碰到輸入處理、權限、金流那類 diff |
/simplify |
只看品質:重用、簡化、效率,而且會直接改 | 功能做完、測試綠了之後 |
/debug |
開 debug log,讀 session 的 debug 紀錄找問題 | Claude Code 本身行為怪的時候,不是你的 code 怪 |
/loop |
固定間隔重跑一個 prompt 或指令 | 等 CI、等部署,不想一直手動看 |
/batch |
把大規模改動拆給多個 agent 平行做 | 同一種改法要套到幾十個檔 |
/run、/verify |
啟動你的 app 實際看改動有沒有效 | 「測試過了」和「真的會動」之間那一步 |
/claude-api |
載入 Claude API 的參考資料 | 寫要呼叫 Claude 的程式時,先按它再問 |
這一區跟昨天內建指令的差別:官方文件說得很清楚,指令是固定邏輯,skill 是一段給 Claude 的詳細指示,由它用工具去完成。所以 skill 的行為會隨模型漂,內建指令不會 —— 內建指令沒有今天這種存活率問題,skill 才有。
anthropics/skills)/plugin marketplace add anthropics/skills
/plugin install document-skills@anthropic-agent-skills
| skill | 做什麼 | 我什麼時候用 |
|---|---|---|
docx |
建立、編輯、讀 Word;含追蹤修訂與註解 | 有人要 .docx 的時候 —— 就是 convert-docx 那個位子 |
pptx |
建立、編輯、讀 PowerPoint | 要簡報。Day 5 練習三如果重做,會從這裡開始 |
pdf |
抽文字與表格、合併拆分、填表單、OCR | 讀 PDF 規格書、合併多份輸出 |
xlsx |
建立、讀、改試算表 | 我還沒用過,列出來是因為它跟上面三個同一包 |
這四個是「source-available」不是開源 —— Anthropic 說它們就是 Claude 自己處理文件時在跑的那一套,拿出來給人參考。
我 9/11 裝了前三個,實跑過,有一個坑要先講。 它們的 SKILL.md 假設 docx、pptxgenjs、defusedxml 這些相依「已經裝好」—— 那是 Anthropic 自家沙箱的前提,在你的 Mac 上不成立。macOS 的系統 Python 被 PEP 668 擋著,pip install 直接回 externally-managed-environment。解法是走 uv、不動全域環境:
uv run --with defusedxml --with lxml --with pillow python ~/.claude/skills/pptx/scripts/thumbnail.py deck.pptx prefix
這件事 SKILL.md 沒寫。官方 skill 也有它自己變成零的方式:它假設的環境不是你的。 和上面那五個一樣,裝好之後要真的跑一次才算數。
上一節列了十二個官方的。而 GitHub 上還有更多:光是官方的社群 marketplace,我 9/10 掃的那版就有 2,282 個 plugin,再加上各種 awesome-claude-skills 合輯。很多人的第一反應是先全部裝起來,反正裝了不用也不會怎樣 —— 用到的時候它就在。
我原本也這樣想。三個實測結果改變了我的看法。
第一,每一個 skill 都在每一輪付租金。 文件說 description 是常駐的 —— 不管這輪有沒有用到,Claude 每次開口前都先讀過全部 skill 的描述。9/12 量的時候我這台機器有 19 個 skill,描述加起來 4,798 字,其中 docx 和 pptx 兩個就佔 1,577。這筆錢不大,但它是每一輪都付、而且你看不到的那種。裝 200 個,就是每一輪先讀五萬字再開始工作。唯一不付的是標了 disable-model-invocation 的那些 —— 它們不在 Claude 的清單裡,convert-docx 標上之後就從這 4,798 字裡消失了。
第二,功能重疊的 skill 會互相搶,而且誰贏取決於你站在哪個目錄。 convert-docx(我寫的,專案層)和官方的 docx 做的是同一件事。我用同一句話「把這篇轉成 Word 檔」問了 18 次,只允許它選 skill、不准執行:
| 站在哪個目錄 | 次數 | 它選的 |
|---|---|---|
文章 repo(有 convert-docx) |
15 | convert-docx 15 次 |
| 鐵人賽 repo(沒有) | 3 | docx 3 次 |
15 次裡有 3 次我是故意要它做 convert-docx 做不到的事 ——「加目錄和頁碼」—— 它還是選 convert-docx。它不是挑會做的那個,是挑描述對得上的那個。 而換一個目錄,同一句話就換一個 skill 接,過程裡沒有任何提示告訴你這次是誰在做。全部裝起來的結果不是「用到的時候它就在」,是「用到的時候你不知道是哪一個在」。
這兩個還算好認,因為名字裡都有 docx。更糟的是 humanizer 和 humanizer-zh:兩個都是校稿,一個預設只診斷、一個預設直接改寫檔案。我最後是在 CLAUDE.md 裡寫了一條規則告訴 Claude 中文用哪個、英文用哪個 —— 裝兩個相似的 skill,代價是你得多寫一條規則來管它們。
convert-docx 的解法比較乾脆:標上 disable-model-invocation: true。標完再問同一句「轉成 Word 檔」,它回「convert-docx 不在這次 session 的清單裡」,然後選 docx —— 我要它的時候自己打 /convert-docx,其他時候讓位。
第三,skill 不只是說明書,它會改 Claude Code 的行為。 這是我讀文件才意識到的。frontmatter 裡有幾個欄位,每一個都在動你的環境:
| 欄位 | 它做的事 |
|---|---|
allowed-tools |
skill 被叫到的那一輪,列在裡面的指令不用問你就能跑 |
disallowed-tools |
把某些工具從 Claude 手上拿掉 |
model、effort |
換模型、換推理強度,你沒開口 |
hooks |
skill 一被叫到就註冊 hook,整個 session 都在 |
context: fork |
開一個你看不到的子 agent 去做 |
Plugin 還能帶自己的 hook 和 MCP server。Day 16 會拆一個工具的 install:它的 --dry-run 說會動 18 個地方,真跑動了 39 個,漏掉的那一半剛好全是 skill、hook 和 git pre-commit。所以裝一個第三方 skill,不是多一份參考資料,是讓別人寫的指示帶著你的權限跑。allowed-tools: Bash(git push *) 這種東西寫在一個你沒讀過的 SKILL.md 裡,跟裝一個沒看過原始碼的 shell script 是同一件事。
我後來給自己定了一套流程,也做成了 skill:/skillcheck。裝之前先靜態掃一遍(用 NVIDIA 的 SkillSpector,--no-llm,內容不上雲),再逐條看它的 frontmatter 和腳本,最後才決定裝、有條件裝、或不裝。9/10 我把那 2,282 個的清單掃了三輪關鍵字,一個都沒裝 —— 不是它們不好,是那天沒有一個是我當下需要的。
Day 4 那三級隔離裡的第二級就是為這件事準備的:環境變數 CLAUDE_CONFIG_DIR 指到別的目錄,整套設定、skill、記憶都換成那個目錄的。我試了:
$ CLAUDE_CONFIG_DIR=/tmp/iso claude -p "/mike"
Unknown command: /mike
一個乾淨的 Claude Code,什麼都沒有。要試一個新 skill,就在這裡裝、在這裡跑、看它動了什麼;確定要了,再搬進正式的 ~/.claude/。要連檔案系統一起圈住,加上 Day 4 那個一級半的 /sandbox;更狠的是 Day 4 的第三級,開一台 VM:裝前拍快照,看完退回。
這比「先全部裝起來」多花幾分鐘,但省下的是「三個月後某個行為怪怪的、不知道是哪個 skill 幹的」那種下午。
所以裝的判準跟寫的判準是同一條:需要的時候再動手,動手之後要回來數。 今天數的五個是我自己寫的,但裝來的一樣要數 —— eli5 那個社群 plugin 我裝了、跑過一次、哪一篇都沒用上,它也算在那 4,798 字裡面。
反過來說,裝來的 skill 有一個天生的限制:它不知道你的流程。md-single-html 是五個裡唯一活著的,不是因為它寫得好,是因為它知道這個 repo 的表格藏在 HTML 註解裡、圖片前面有一行 placeholder 要略過 —— 這些慣例只有這裡有,官方或社群的 skill 不可能知道。
所以自己寫的判準不是「有沒有現成的」,是這件事有多少是你自己的。每次都一樣、而且帶著你自己的慣例、而且沒有「複製一份腳本改一改」的捷徑 —— 三個都符合,才值得寫;少一個,要嘛用現成的,要嘛用腳本。
五個 skill,在這個 repo 55 天內只有一個被叫過。這個數字比我預期的難看,但它比「感覺上還算有用」誠實 —— 只要記得它只說了這個 repo 的事。
而真正的教訓不是「別寫 skill」,是寫完之後要有一天回來數。數是維護的第一步,不是全部:數完才知道哪個要修(gen-table-image)、哪個要讓位(convert-docx)、哪個該刪。昨天的 /mike 看的是「我多久沒改它」,今天看的是「我多久沒用它」—— 兩個數字互相獨立。md-single-html 51 天沒改,但活著;gen-table-image 被 /mike 標 ⚠️(132 天沒動),呼叫也是零。只中一個可以解釋,兩個都中就該問它還要不要留 —— 前提是你數的地方數得到它,clean-* 那兩個教的就是這件事。我甚至在 CLAUDE.md 裡親手記下了其中一個的死訊,然後照樣當它還活著。
沒有回頭數過的資產,不是資產,是庫存。
這一篇留下的心法:
寫完的 skill 要回來數:多久沒改、多久沒用,分開看;很久沒改、也沒人用,就該問它還要不要留。沒有回頭數過的資產不是資產,是庫存;裝來的先隔離,因為它不知道你的流程。
明天:去識別化做成一支檢查工具 —— 一張對照表,和一條不能交給 AI 的檢查。人工檢查漏過一次,漏了 95 天。
description 截斷 1,536 字、disable-model-invocation、paths、撞名優先序)、內建指令與 skill 一覽(本文「做什麼」欄照它翻);2026-09-22 查docx/pptx/pdf/xlsx 在 skills/ 下,source-available)tools/skills/(五個 skill 的原始碼)