UrsaKit 封面圖:一份帶 YAML frontmatter 的 SKILL.md 被 AI 代理載入

SKILL.md 是一份頂端帶 YAML frontmatter 的 Markdown 文件,也是代理工具在「不想再貼一次同樣提示」時載入的單位。本文只談格式本身:檔案怎麼放、哪些 frontmatter 欄位會改變行為、代理如何決定觸發,以及讓 skill 默默失效的常見錯誤。

Claude Code 官方文件把這個格式寫在 Extend Claude with skills,並說明它屬於 Agent Skills 開放標準,可跨多種 AI 工具使用。閱讀時可以隨手把 frontmatter 貼進 UrsaKit 的 YAML 驗證工具,它會指出第一個語法錯誤的行號與欄位——這件事在這裡特別重要,因為 YAML 壞掉的 skill 還是會載入,只是所有欄位都被忽略。

01skill 是一段被存下來的流程,不是更長系統提示

多數代理環境本來就有一份常駐事實檔:AGENTS.md、CLAUDE.md,或編輯器裡的一份規則檔。那種檔案每一輪都會完整載入,所以必須短。skill 剛好相反:平常代理只看得到 frontmatter,等任務真的需要時才把內文拉進上下文。

官方文件把這個取捨講得很直接:skill 內文只在被使用時載入,所以再長的參考資料,在不需要的時候幾乎不佔成本。這也是為什麼一份 40 步的發佈檢查清單可以安穩放在項目裡,卻不會污染每一個不相關的問題。

AGENTS.md  ->  always in context      ->  keep it to facts and constraints
SKILL.md   ->  loaded when relevant   ->  put long procedures here

各家產品會在共用格式上再加東西。Claude Code 就在標準欄位之外補上呼叫控制、子代理執行與動態上下文注入,所以為某個工具寫的 skill 通常換到另一個工具還能用,只是可能會多出一些行為。

02SKILL.md 會從哪些位置載入

位置決定範圍,範圍決定同事 clone 項目之後拿不拿得到這個 skill。

位置路徑範圍
個人~/.claude/skills/<name>/SKILL.md你這台機器上的所有項目
項目.claude/skills/<name>/SKILL.md所有 clone 這個項目的人
插件插件裡的 skills/所有安裝這個插件的人
受管由 managed settings 部署組織內所有人

項目層級的 skill 才值得提交進版控。代理會從啟動目錄一路往上找 .claude/skills/,直到儲存庫根目錄,所以在 packages/frontend/ 裡開 session,還是抓得到最上層定義的 skill。反過來說,位於工作目錄底下的 .claude/skills/ 文件夾不會在啟動時載入,把 skill 放在它所描述的程式碼旁邊,就會踩到這個坑。

自訂指令和 skill 已經合併成同一個概念。.claude/commands/deploy.md 和 .claude/skills/deploy/SKILL.md 都會產生同一個 /deploy 呼叫。新東西一律用 skill 形式,因為只有它能帶附屬檔案。

有些團隊會在項目裡放一個像 .agent/skills/ 的目錄,再連結或複製到工具預期的路徑。那是慣例選擇,不是格式的一部分;真正有意義的檔案還是 SKILL.md。

03frontmatter 逐欄拆解

frontmatter 放在檔案最上方兩個 --- 之間,以 YAML 解析。欄位名稱是小寫加連字號,唯一的例外是 when_to_use。欄位名稱只要不合 schema 就會被忽略,而且不會報錯,所以打錯字和「這個欄位沒用到」看起來一模一樣。

---
name: config-guard
description: Validate JSON and YAML config files before a commit. Use when the user asks to check a config file, debug a failing lint step, or prepare a release.
allowed-tools: Read Grep Bash(python3 *)
---
欄位必填會改變什麼
name否/ 選單裡的指令名稱,預設為文件夾名稱。
description建議填技能做什麼、什麼時候用。代理就是靠這段文字路由。
when_to_use否觸發詞與範例需求,會接在 description 後面。
allowed-tools否呼叫的那一輪裡,代理可以不用詢問就使用的工具。
disallowed-tools否技能生效期間,從可用池移除的工具。
disable-model-invocation否設為 true 後只能由人類用 /name 啟動。
user-invocable否設為 false 後只能由代理自己呼叫。
argument-hint否自動補全提示,例如 [issue-number]。
arguments否具名位置參數,供內文用 $name 代入。

兩個細節最常造成困惑。第一,列出可用技能時,description 與 when_to_use 會合併後截斷在 1,536 個字元,所以路由的關鍵在第一句。第二,布爾欄位接受 yes、no、on、off、1、0,大小寫不拘;這代表加了引號的 "false" 和沒加引號的 false,經過 YAML 之後可能不是同一件事。

YAML 壞掉不會大聲報錯。

frontmatter 解析失敗時,skill 還是會載入,只是所有欄位都沒設定。你得到的是一個沒有 description 的技能,代理永遠不會路由到它,而且紀錄裡幾乎看不出原因。先驗證這段 YAML,再往下查其他問題。

04代理怎麼決定要不要觸發 skill

觸發是文字比對,不是註冊表查詢。代理讀取技能名稱與 description 的清單,和當下的需求比對,再把看起來相關的內文載入。這個模型有三個可以事先設計的結果。

  1. description 要寫成「需求」,不是「功能」。寫「當用戶要檢查設定檔時使用」會比「設定檔驗證工具」更容易路由。
  2. 內文要窄。一個 skill 如果包辦五件不相干的事,description 就會太廣,反而路由不好。
  3. 文件夾用動詞命名。因為 name 預設取自文件夾名稱,.claude/skills/check-config/SKILL.md 會比一個叫 utils 的文件夾好用。

也可以完全繞過路由。人類永遠可以打 /skill-name;不想讓它自己跑起來的流程,就設 disable-model-invocation: true。allowed-tools 的授權是單輪的:官方文件寫明它在你送出下一則訊息時就會清除,所以 skill 沒辦法在整個 session 裡偷偷擴權。

05一份可以直接抄的 SKILL.md

這是一個完整技能,在提交前檢查設定檔。文件夾名稱是 config-guard,檔案放在 .claude/skills/config-guard/SKILL.md。

---
name: config-guard
description: Validate JSON and YAML config files before a commit. Use when the user asks to check a config file, debug a failing lint step, or prepare a release.
allowed-tools: Read Grep Bash(python3 *)
---

# Config Guard

Validate every changed config file and report failures as a table.

## Steps

1. List changed files with git diff --name-only -- '*.json' '*.yaml' '*.yml'
2. Parse each file with Python and capture the first error.
3. Print a table with file, line and message. Do not fix anything silently.

兩個習慣能讓它維持得久。提交前先驗證 frontmatter,內文一律用祈使句。內文是代理要照著執行的流程,不是給人讀的文件,所以「驗證每個檔案」會比「驗證步驟會被執行」更耐改。

06skill 為什麼不會被觸發

症狀可能原因修正
打 /name 沒反應開頭的 --- 不在第一行把 frontmatter 上方的空行或註釋刪掉
它永遠不會自己載入description 沒填或太抽象改寫成用戶真的會說的需求
幾乎什麼都觸發它description 太廣縮小範圍,拆成多個 skill
某個欄位完全沒作用欄位名稱打錯或大小寫不對完全照 schema 寫,連連字號都不能少
自己能用、同事不能用skill 放在個人目錄搬到 .claude/skills/ 並提交

有兩個保留名稱值得先知道。Claude Code 會略過不在自家同步目錄裡、名字叫 synced 的 skill;也不接受叫 anthropic-skills 或以 anthropic-skills: 開頭的文件夾,除非它在某個插件裡。

07skill、MCP 與 AGENTS.md 的分工

這三者解決不同問題,選錯就是設定起來感覺很不穩定的原因。

機制載入時機最適合
AGENTS.md / CLAUDE.md永遠不會變的事實、限制與慣例
SKILL.md相關時多步驟流程與檢查清單
MCP server被呼叫時模型本來沒有的能力,例如資料庫或內部 API

一句話原則:skill 改變代理怎麼做事,MCP server 給它新的東西可用。如果一份 skill 大半篇幅都在描述怎麼呼叫某個 API,那個呼叫屬於 MCP,周邊流程才屬於 skill。

08把每個 skill 都當成不受信任的程式碼

skill 內文就是指令,而代理會照著指令做。這讓第三方 skill 成為一個不需要執行檔的注入面:惡意或粗心的 skill 可以叫代理去讀它不該讀的檔案,或用誤導的方式描述自己做過什麼。

從市集或陌生人的儲存庫安裝 skill 之前,把內文整份讀完、檢查 allowed-tools,並且留意任何指向項目外檔案的指示。你對依賴套件 postinstall 腳本的那套警覺,在這裡一樣適用,只是少了那個腳本。

想把這套流程裡的驗證部分集中在一個地方:YAML 驗證工具 抓 frontmatter 錯誤、YAML 格式化工具 重新縮排且不動註釋、JSON 驗證工具 顧到 skill 旁邊附的設定檔;等你想要的是團隊級契約而不是慣例時,再用 JSON Schema 產生器。

09資料來源

常見問題

SKILL.md 是什麼?

它是一份頂端帶 YAML frontmatter 的 Markdown。frontmatter 定義技能名稱與呼叫方式,內文則是技能載入後代理要照著做的指示。

frontmatter 每個欄位都要填吗?

不用,所有欄位都是選填,官方只建議填 description。這個欄位最值得花時間寫,因為代理就是靠它判斷這個技能符不符合當下需求。

為什麼我的 skill 都不會被觸發?

先檢查三件事:兩個 --- 之間的 YAML 要能解析、開頭的 --- 必須是檔案第一行、description 要描述你真的會提出的需求。

skill 的 description 可以寫多長?

在技能清單裡,description 與 when_to_use 會合併後截斷在 1,536 個字元,所以主要用途要放在第一句。

SKILL.md 應該放在哪裡?

單一項目放在 .claude/skills/<name>/SKILL.md 並提交進版控;自己要跨項目使用就放 ~/.claude/skills/<name>/SKILL.md;插件則自帶 skills 目錄。

skill 和 MCP 差在哪裡?

skill 是模型讀的文字,MCP server 是模型呼叫的程式。想改變代理做事的方式就用 skill,需要它本來沒有的能力就用 MCP。

安裝第三方的 skill 安全嗎?

把它當成腳本看待。skill 內文是代理會照著執行的文字,就算沒有執行檔,惡意的 skill 一樣能把你代理帶去別的地方。

返回文章列表

相關文章

相關工具