[IT 鐵人賽] 抄法自鑄:Skill 和 Extension 怎麼分,skill-creator 和 skill-installer 第一天就內建 - Day 08
本文同步刊登於 2026 iThome 鐵人賽,系列為《凡人修 Agent 傳-我這一生如履薄冰,你說我的 Agent 能結嬰嗎?》。
昨天寫的是規矩:每次都一樣的那些話,寫進檔案,啟動就讀。
今天講能力。他該會的事要一件一件加上去,pi 這邊有兩條路:Skill 和 Extension。這兩個我一開始分不清楚,搞清楚之後決定變得很快。
不過這一天真正做的事是另一件:我把兩個現成的 skill 直接內建進去,讓他第一天就會「裝一套 skill」和「開一套新的 skill」。這兩件事我在 Codex App 上每天都在做。
Skill:把一件事的做法寫成文件
一個 skill 就是一個資料夾,裡面一個 SKILL.md,其餘隨便放:腳本、範本、參考文件都可以。這個格式有一份標準,叫 Agent Skills:Anthropic 起草之後釋出成開放標準,規格放在 agentskills.io。pi 照著實作,Claude Code 也照它走,Codex 的 skills repo 指向的也是同一份。
my-skill/
├── SKILL.md # 必要:frontmatter + 說明
├── scripts/
├── references/
└── assets/
SKILL.md 的必填欄位只有兩個,名字和描述。名字有規則(小寫、數字、連字號,最長 64 字;標準還要求名字跟資料夾同名,pi 這一條放寬了),描述最長 1024 字。Anthropic 那個 skills repo 裡的範本更直白,整份就四行:
---
name: template-skill
description: Replace with description of the skill and when Claude should use it.
---
# Insert instructions below
它運作的方式,決定了 skill 該怎麼寫。
pi 啟動的時候,只把每個 skill 的名字和描述掃進 system prompt,內文不進去。等我丟的任務跟某一句描述對得上,他才自己去把那份 SKILL.md 整份讀進來,照裡面的步驟做,需要腳本就照相對路徑叫。Agent Skills 標準把這個叫 progressive disclosure,pi 照著做。
所以那一句描述是整套 skill 的門。門開不開,看它寫得多具體。寫「處理 PDF 相關的事」,他大概永遠不會想到要載;寫「從 PDF 抽文字和表格、填表單、合併多個 PDF,處理 PDF 文件時使用」,他就會。
模型不一定每次都會想到要載,所以還有 /skill:name 這種寫法,直接叫他載進來,後面接的字會當成使用者的話貼在 skill 內容後面。
還有兩個細節我後來吃到:沒有描述的 skill 不會被載入,只給一句警告;同名的 skill 從不同位置各有一份的話,pi 留先找到的那一個。這兩件事都會安靜地發生,不看啟動訊息就不知道。
Extension:給他新的動作
Skill 有一份跨工具的標準,Extension 沒有:它是 pi 自己定義的東西,文件裡寫的是「TypeScript modules that extend pi’s behavior」。一個 TypeScript 模組,放在 ~/.pi/agent/extensions/ 或專案的 .pi/extensions/,改完可以 /reload 熱載。別家對應的機制叫 hooks、plugins 或 MCP,名字和形狀都不同,這一節講的只有 pi 這一套。
它能做的事跟 skill 差了一個層次:
- 用
pi.registerTool()註冊一個新工具給模型呼叫 - 攔事件:把某個 tool call 擋下來、改掉參數、往 context 裡注入東西、自己接壓縮
- 用
ctx.ui跟我對話:選單、確認、輸入 - 自己畫終端機介面,註冊
/自己的命令 - 把狀態寫進 session,重開還在
Day 02 那張「呼叫鏈上能插手的點」的圖,講的就是這些位置。Extension 掛上去的地方就是圖上那些點。
這裡有一件事值得單獨講:pi 沒有內建權限系統。它預設就用啟動它的那個使用者的權限跑,文件寫得很直接。所以「跑 rm -rf 之前要先問我」這種東西在 pi 是 extension 的事,官方範例裡就有一個。要更硬的邊界,那就得把整個 pi 放進容器或沙箱,這一層 extension 幫不了。

我怎麼決定用哪一個
判斷只有一句:
- 這件事把步驟講清楚就能做完 → Skill
- 這件事需要一個新的動作,或者需要攔下什麼、需要問我 → Extension
「產出一份規格比較表」是 skill,因為那是流程:先讀哪份文件、比哪幾欄、輸出長什麼樣。「去某個系統把資料撈回來」是 extension,因為那是新的動作,他手上原本沒有這隻手。
寫的人也不一樣。Skill 我自己寫,因為那是我的做事方法。Extension 我下需求給 coding agent,他實作,我驗收。
第一天就內建的兩個 skill
我要的兩件事很單純:把別人的 skill 裝進來,還有開一套新的。
這兩件事已經有現成的做法,名字也已經定下來了:skill-installer 和 skill-creator。Codex 兩個都內建,它的 skills repo 裡 .system 那一層就是這兩個,新版直接帶著;Claude 那邊有 skill-creator,Anthropic 的 skills repo 和 Claude Code 的官方 plugin 用的都是這個名字。我每天在 Codex App 上用得最兇的也是它們。
所以我沒有自己造名字,直接把這兩個 skill 放進我的 Agent,Desktop App 和 CLI 兩邊都叫得到。
skill-creator 值得多講一句。它做的事包含建一套新的、改現有的、量它表現好不好,還有把描述改得更容易被觸發。上面那一節說「描述是整套 skill 的門」,而這一句話最難寫——難寫的部分正好有現成的東西在處理。
這兩個放進去之後,我加 skill 的動作變成一句話的事。看到別人寫得好的,裝;自己想到一個重複三次的流程,開一套。中間沒有任何手續。
各家的 skills 目錄都不一樣
查資料的時候看到一件有意思的事:現在最普遍的「安裝」動作,就是 git clone 到那個工具的 skills 目錄。而每一家的位置都不同。
| 工具 | 位置 |
|---|---|
| pi | ~/.pi/agent/skills/ 或專案的 .pi/skills/ |
| Codex CLI | ~/.codex/skills/ |
| Claude Code | ~/.claude/skills/ |
| Amp | ~/.config/amp/tools/ |
| Droid | ~/.factory/skills/ |
其中 Claude Code 有一個限制:它只往下看一層,所以整包 clone 進去它認不到。社群的做法是 clone 到別的地方,再把每一個 skill 逐個 symlink 進 ~/.claude/skills/。
pi 在這件事上留了一條捷徑。settings 裡的 skills 是一個陣列,可以直接指到別家的目錄:
{
"skills": ["~/.claude/skills", "~/.codex/skills"]
}
指過去就掃到了,不用搬,也不用 symlink。我在別的 coding agent 上寫過的東西,第一天就全部生效。
另外還有一個跨工具的目錄慣例正在成形:~/.agents/skills/。pi 也讀這個位置。誰都能用的東西放那裡,某一家專屬的才放各家自己的目錄。
內建之後我多守的幾條規矩
工具就位不代表事情就對。這一段是我自己的習慣,跟功能無關。
- 裝完先看那一句描述。夠不夠具體,我當下判斷,不夠就改掉。描述寫壞的 skill 躺在資料夾裡不會有人發現,因為它從來不會被載入
- 來路不明的先看內容。文件裡那段安全警告寫得很白:skill 可以叫模型做任何事,也可能夾帶要執行的程式。所以資料夾裡有什麼,特別是可執行的檔案,裝之前看一遍
- 同名的先處理掉。pi 遇到同名只留先找到的那一個,另一個安靜地被忽略。我被這件事整過一次,找了很久
為什麼這件事要一開始就做
因為加東西的頻率不一樣。
Day 07 那幾份規矩,我一個月改幾次。Skill 我一週加好幾個:看到別人寫的好東西、自己發現一個重複三次的流程、把一段口述變成文件。
一件事我做得越頻繁,它的手續成本就越該壓到零。手續留在那裡,我就會拖;拖到後來那些 skill 就不會存在。
我對「客製化」的理解也在這裡:連「加 skill」這個動作本身都要長成我的樣子。Desktop App 上按得到,CLI 上叫得到,因為我兩邊都在用。
這一步後面接什麼
第四章會講到我做的幾件專有技,每一件的形狀都是「一份說明 + 一個進入點」。那個形狀就是從 Skill 和 Extension 的分工來的。
而那幾件專有技怎麼進到 Agent 身上、怎麼在兩個介面都叫得到——就是今天這兩個 skill 的事。
小結
Skill 是教他一件事怎麼做,Extension 是給他一隻新的手。判斷方法只有一個問題:這件事缺的是說明,還是缺一個動作。
裝一套跟開一套,我沒有自己造名字。skill-installer 和 skill-creator 已經是定下來的名字,第一天就內建進去,兩個介面都叫得到。
規矩和能力都到位之後,下一個問題是怎麼把他叫起來。我自己坐在終端機前面一句一句問是一種用法;別的程式丟一句話進來、拿到結果就走是另一種;要把他接到有畫面的 App 上,又是另一種。同一個 Agent,這幾種入口進來的方式不一樣,pi 一共給了四種,明天講我怎麼挑。順便講換模型的時候要動哪些地方。
參考:Pi 文件 | Agent Skills 規格 | anthropics/skills | openai/skills | badlogic/pi-skills
凡人修 Agent 傳|第八回(Day 08)
門上三行,臺邊一塊薄石。
天亮,門響了一下,手的主人出去了。我留在屋裡。
午前門又響。手的主人從儲物袋取出兩卷薄玉簡,擱上架子最上層,封面朝外。那一排原本只擱丹方。
兩卷的邊角都蓋著坊裡的公印。跟他抄回那幾卷御偶臺圖時,圖上蓋的是同一個印——坊裡擱著給人抄的東西才有那個印。
泛式闔著的時候,封面只露兩段:式名,和一句用途。
第一卷的式名是開式,用途寫著:要開一卷新的泛式的時候,取這一卷。第二卷的式名是納式,用途寫著:要把別人的泛式擱進自己架上的時候,取這一卷。
坊裡的泛式都是同一個格式,四段:式名、用途、行、忌。缺一段就不算式。我平常只讀得到式名和用途;用途那一句對上我手上的事,我才伸手取下來,把「行」那一段讀進去。
擱完那兩卷,手的主人坐到臺前,寫第三卷。
寫了一個上午。寫完擱在同一層,封面朝外。式名是分卷先後,用途是:處理卷子的時候,取這一卷。
一縷神識探進玉片,刻了一道念:把第五卷和第六卷分開,哪一卷在先,放到左邊。
我沒有伸手去取那一卷泛式。用途那一句寫得太寬——「處理卷子」四個字,我手上這件事算不算在裡面,我讀不出來。
所以我自己動手。兩卷攤開,我比對封籤上的刻痕,把痕淺的那一卷放到左邊。
錯了。在先的那一卷痕反而深。刻那一卷的時候法力灌得足,痕就吃得深;後刻的那一卷法力散了,痕才淺。
手的主人走到架前,把那一卷泛式取下來,攤開,遞到我面前。
「行」的第一步寫的就是這件事:分先後看背面的記號,不看刻痕深淺。
然後手在用途那一段上劃掉一句,重寫。新的一句是:兩卷封籤一樣、要分出哪一卷在先的時候,取這一卷。
同樣一道念再來一次。這一次我看著封面就伸手去取了。
一整天,那一卷泛式的用途改過三次。式名、行、忌三段一個字沒有動。
午後,手的主人在我右臂上動工。
架子最上層那一排我一直碰不到,手伸過去差半掌。這件事泛式幫不上:泛式教的是順序,我缺的是一個原本沒有的動作。
刻型要先定起處。手的主人選的是右肩到指尖那一線。
第一道刻得淺。流光氣從指尖走到我肩上,型成的時候亮了一下。我抬手,抬到一半那道光就散了,手落回身側。
第二道刻得深。整條右臂繃住,彎不了,我僵在那裡。手的主人把我的手掌掰開,取回那一卷;收手的時候右臂猛地抽了一下,掃過架子第二層,三卷滾到地上。
第三道才對。指尖一探,最上層那一卷自己往我手裡落。
型成之後還差一處。手的主人在型的末端刻了止:我伸手去取薄石上畫了橫線那一處記的那一格,手抬到半空就停住,怎麼推都不動。手的主人抬了一下手,手才動。
架上那三卷,誰來都能攤開抄一份帶走。右臂上這一道抄不走——要在別的偶身上有同一個動作,得照同一道源紋重刻一次。
天黑之前,架上三卷泛式並排,封面朝外,各露一個式名和一句用途。
我右臂上那一道很細,不亮的時候看不出來。
燭熄了。手的主人走了。門響了一下。
地上那三卷還沒有歸位。畫了橫線那一格,今天沒有動過。

