iT邦幫忙

2026 iThome 鐵人賽

DAY 21
0
Claude AI

資深工程師的 Claude Code 工作筆記系列 第 21 篇

Day 21:Plugin 把前四天的東西包成一個單位,怎麼做、怎麼裝、怎麼給團隊,以及它在跨廠標準裡的位置

  • 分享至 

  • xImage
  •  

Day 17 到 20 各講了一個擴充點:hooks、subagent、skill、MCP。它們有一個共同的麻煩:散落在 ~/.claude 和各個專案裡,換一台機器、多一個隊友,就得重新複製一次。Plugin 就是官方給的打包單位。今天講它怎麼做、怎麼裝、怎麼發給團隊,最後放到 OpenAI 與跨廠標準的脈絡裡對照。

先交代來源與範圍。指令、欄位與限制來自 Claude Code 與 OpenAI Codex 的官方文件原文,以及 agent-plugins.org 的規格頁。製作與安裝的流程,在 Claude Code 2.1.289 上用隔離的設定目錄實際跑過,輸出節錄自實際紀錄。範例名稱是示意,實跑用的是同結構、不同名稱的 plugin。需要登入模型才能驗證的部分,包括 skill 實際觸發、hook 實際觸發、MCP 完整工具名與 eval 分數,這次沒有跑,文中會標「依文件」。

它是什麼:一個目錄,一起安裝,一起啟停

官方的定義是:A Claude Code plugin is a directory of skills, agents, hooks, MCP servers, or other components that Claude Code installs and loads as one unit。重點是「一個單位」:裝一次、停用一次、更新一次,裡面的元件一起動。

解剖一個 plugin

acme-hello/
├── .claude-plugin/plugin.json   # 只有這個檔放這裡
├── skills/hello/SKILL.md        # 叫用為 /acme-hello:hello
├── agents/greeter.md            # 叫用為 acme-hello:greeter
├── hooks/hooks.json             # 最外層要有 "hooks" 包一層
├── .mcp.json                    # server 名變成 plugin:acme-hello:hello
└── commands/*.md                # 舊格式,新作品用 skills 取代

最容易踩的兩點:

  • manifest 其實可省略,只有 name 是唯一必填;但元件放進 .claude-plugin/ 不會被載入,那裡只放 plugin.json。
  • plugin 根目錄的 CLAUDE.md 不會被載入,validate 還會警告。要給指示,得寫成 skill。

命名空間決定你在權限規則、hook matcher 裡怎麼稱呼它們:

元件 名稱形式 要注意
Skill /<plugin>:<目錄名> frontmatter 的 name 只改最後一段,前綴不變
Agent <plugin>:<name> 忽略 permissionMode、hooks、mcpServers、initialPrompt(Day 18)
MCP 工具 mcp__plugin_<plugin>_<server>__<tool> hook matcher 只寫 server 名會永遠不觸發(Day 20)
Hooks 沒有前綴 同一個 hook 在 settings 與 plugin 各放一份,會跑兩次

plugin 自己的 settings.json 只有 agent 與 subagentStatusLine 兩個鍵生效,其餘丟棄,所以 plugin 沒辦法靠 settings 替自己放寬權限。

plugin 的目錄結構與命名空間轉換

做一個:從零到能被安裝

最小的 plugin.json 只需要一行 name,其餘選填。名稱不能用 claude-、anthropic- 這類保留字開頭,validate 會直接報錯。

{
  "name": "acme-hello",
  "version": "0.1.0",
  "description": "示意用的最小 plugin"
}

hook 與 MCP 的設定依文件格式寫如下。路徑一律用 ${CLAUDE_PLUGIN_ROOT},因為安裝後 plugin 會被複製進 cache,路徑每次更新都會變,而且 shell 形式的指令要加雙引號,路徑含空白才不會斷:

{ "hooks": { "SessionStart": [ { "hooks": [
  { "type": "command", "command": "\"${CLAUDE_PLUGIN_ROOT}/hooks/hello.sh\"" }
] } ] } }
{ "mcpServers": { "hello": {
  "command": "python3", "args": ["${CLAUDE_PLUGIN_ROOT}/servers/server.py"]
} } }

接著寫 marketplace,也就是一份目錄,不是一個託管商店。必填的只有 name、owner.name 與 plugins[],每個 entry 必填 name 與 source:

{
  "name": "acme-tools",
  "owner": { "name": "Acme Platform Team" },
  "metadata": { "description": "團隊共用的示意 marketplace" },
  "plugins": [ { "name": "acme-hello", "source": "./acme-hello" } ]
}

驗證時有一個很好的反面教材。把 source 誤寫成 ../acme-hello,實跑的 claude plugin validate 直接失敗,訊息是:

Path contains "..": ../acme-hello. Plugin source paths are resolved relative to
the marketplace root (the directory containing .claude-plugin/), not relative
to marketplace.json. Use "./acme-hello"

改成 ./acme-hello 之後通過。另外有兩個實跑看到的細節:${CLAUDE_PLUGIN_ROOT} 沒加引號會得到 warning;marketplace 缺 description 也會 warning,補上 metadata.description 就乾淨。另外 claude plugin init 只會把腳手架寫進 ~/.claude/skills/<名稱>/,沒有換路徑的旗標,所以實務上是手寫,或先 init 再搬走。

安裝與管理

兩條路:在 Claude Code 內用 /plugin 介面,或用 claude plugin 指令。實跑的完整流程如下,輸出皆為節錄:

claude plugin validate ./acme-tools
claude plugin marketplace add /絕對路徑/acme-tools      # declared in user settings
claude plugin install acme-hello@acme-tools              # scope: user
claude plugin list                                       # Version 0.1.0 ... enabled
claude plugin details acme-hello                         # 列出元件與常駐 token 成本
claude plugin disable acme-hello && claude plugin enable acme-hello
claude plugin update acme-hello@acme-tools               # 0.1.0 到 0.1.1,Restart to apply
claude plugin uninstall acme-hello@acme-tools

這份流程裡,claude mcp list 在安裝後顯示 plugin:acme-hello:hello ... ✔ Connected,不需要登入。以下是用起來最關鍵的幾點:

項目 說明
範圍 --scope user、project、local 三種;update 另有 managed,但 managed 只能更新、不能安裝
試用 claude --plugin-dir <目錄> 只在這次執行有效,不寫入設定;同名時會靜默取代已安裝的 plugin
本機目錄當 marketplace 實跑確認不需要 git;差別只是安裝紀錄沒有 commit SHA
更新 目錄來源的 update 不必先 marketplace update;git 來源則依文件要先更新 marketplace
生效時機 安裝或更新後,執行中的 session 不會套用,要 /reload-plugins 或重開
解除安裝 設定會清乾淨,但 cache 目錄仍留著,約 14 天後背景清除

一個實跑才發現的陷阱:複製進 cache 的是工作樹快照,連沒提交的檔案也會被帶進去,不是 marketplace 紀錄的那個 commit。

包給團隊:marketplace 與分發

給團隊用,文件列出三條路:

  1. 不用 marketplace:給資料夾或 zip,隊友用 --plugin-dir。最簡單,但沒有更新機制。
  2. 自建 marketplace:repo 內放 .claude-plugin/marketplace.json,隊友 marketplace add 後 install。這是主推路線。
  3. 提交到 Anthropic 的 directory,限付費方案。

專案層的註冊,有兩個容易想當然的地方,文件寫得很清楚:

  • extraKnownMarketplaces 能讓開啟 repo 的人不必自己加 marketplace,但要先接受 workspace trust 對話框,未信任時會靜默忽略。維護者的做法是 claude plugin marketplace add acme/claude-plugins --scope project,再把它寫出的 .claude/settings.json 提交。
  • 專案 settings 的 enabledPlugins 對其他人並不會自動安裝,文件原話是 doesn't install it for other people。例外是 plugin 與 marketplace 在同一個 repo、source 用相對路徑時,會自動從 marketplace 載入;外部來源每個人要自己 install --scope project,否則 /plugin 的 Errors 分頁會顯示已啟用但未安裝。
  • 「clone 之後自動提示安裝」這句話,官方文件沒有。所以最省事的路徑是同 repo 加相對路徑,這一條我是依文件推論,沒有用第二個 clone 實測。

私有 repo 的認證交給機器本身:Claude Code 沒有自己的 git token,marketplace.json 也沒有放 token 的欄位,它用你機器上既有的憑證跑 git,而且關掉互動提示。SSH 的 key 不能有 passphrase,HTTPS 要用 credential helper,只設 GITHUB_TOKEN 不夠。

版本策略有一個官方明寫的陷阱:設了 "version": "1.0.0" 卻一直推新 commit 沒改版號,使用者收不到更新。要嘛每次遞增版本,要嘛省略 version 讓版本跟 commit。想釘死就在 entry 填 sha。自動更新預設是官方 marketplace 開、第三方關,更新後執行中的 session 不會換。

企業端有一組鍵:

設定 作用
strictKnownMarketplaces marketplace 來源白名單,空陣列是全面封鎖,連官方的也擋
managed 的 enabledPlugins true 強制啟用,false 在所有範圍封鎖
strictPluginOnlyCustomization skills、agents、hooks、MCP 只能來自 plugin 或 managed 設定,本身不限制裝哪些 plugin
disableSideloadFlags 拒絕 --plugin-dir 等旁路,白名單擋不到它們

官方也明說做不到的事:沒有隱藏 /plugin 的鍵,無法逐人逐群組設定。

團隊分發的流程與分岔

跨廠:沒有一個標準,是分層的

常聽到的說法是各家 AI 工具共用一個 plugin 標準,查下來並不是。比較準確的說法是分層:

層 標準 現況
指引 AGENTS.md Codex、Cursor、Gemini CLI、Copilot 等列為支援;Claude Code 未列
Skill Agent Skills(agentskills.io) 含 Claude Code、Codex、Gemini CLI、Cursor、Copilot、VS Code
工具 MCP,規格最新版 2026-07-28 各家都有,設定檔格式不同
打包(開放) Agent Plugins 1.0.0 規格狀態 Published;TSC 含 Amazon、Cursor、Microsoft、OpenAI、Vercel
打包(各家) 各自的 manifest Claude、Codex、Gemini CLI、Cursor、Copilot 各有一份

Agent Plugins 是新出現的打包層:根目錄一個 plugin.json、skills/ 與 mcp.json,其餘元件放進 extensions.<反向網域>。它只保證 skills 與 MCP 可攜。它不是山寨站:GitHub 組織經過驗證,OpenAI、VS Code、Cursor 的官方文件都引用它的 schema。但 Claude Code 不在它的相容客戶端名單裡,Claude Code 官方文件也沒有提到它。

OpenAI 這邊確實有 plugin 機制:Codex CLI 有 codex plugin add、list、remove 與 codex plugin marketplace add、list、upgrade、remove,session 內用 /plugins。官方文件寫的是 Plugins bundle capabilities into reusable workflows in ChatGPT and Codex,也寫明 IDE 擴充套件不支援。我另外在隔離的 Codex 設定目錄實測了「Claude 格式能不能被 Codex 讀」:用 CODEX_HOME 指向新目錄,安裝前 plugin 與 marketplace 清單都是空的。把前面那種 Claude 格式的 marketplace 交給 codex plugin marketplace add,成功;接著 codex plugin add 也成功,安裝出來的內容與來源只差一個 .codex-plugin/ 目錄,commands/ 底下的指令被轉成放在那裡的 skill,這一點官方文件沒提到,agents/ 則只是被複製。反過來,Agent Plugins 格式的單一 plugin 目錄不能直接 add,錯誤是 marketplace root does not contain a supported manifest,要包進一層 marketplace 才行。要說清楚的是,這只驗證到檔案落地,skill、hook 與 MCP 在 Codex 裡有沒有真的生效,因為不呼叫模型所以沒測,也只測了本機路徑來源。另外文件說 .claude-plugin/marketplace.json 相容的對象是 ChatGPT 桌面 app,並說 CLI 的 marketplace add 是給製作用,但實測 CLI 也能完整安裝。

Claude Code 對 Agent Plugins 格式的態度,在隔離環境實測:把一個只有根 plugin.json、skills/ 與 mcp.json 的目錄丟給它,validate 沒把根目錄的 plugin.json 當 manifest;用 --plugin-dir 載入時,plugin 名稱變成目錄名、版本顯示 unknown,但 skills 載入了。mcp.json 因為少了開頭的點,我推論不會被讀,這一項沒實測。

標準分層與各家打包的對照

安全與已知坑

官方的信任模型寫得很直白:你安裝的 plugin 能以你的使用者權限執行任意程式碼。marketplace 的名字只告訴你誰發布目錄,不代表它裡面每個 plugin 做什麼,Anthropic 也不審查第三方 marketplace。權限規則與 sandbox 管的是 Claude 發出的工具呼叫,管不到 plugin 自己執行的程式碼,hooks 與 MCP server 都在 sandbox 外跑。/plugin 的安裝畫面只會告訴你有 hook,不會告訴你它跑什麼,所以要自己讀三個地方:hooks/hooks.json、.mcp.json 與 bin/。

供應鏈有三點:沒填 ref 就是拉預設分支的最新內容,要釘就填 sha;自動更新後,你審過的檔案可能在磁碟上被換掉;plugin 的 PreToolUse hook 可以回 allow 跳過權限提示,deny 與 ask 規則仍優先,後半句是依文件的推論,要防就自己寫 deny 規則。

文件與實跑記錄到的幾個坑,都有出處:

坑 現象與對策
元件放進 .claude-plugin/ 不會載入,也沒有明確報錯
--plugin-dir 指到 marketplace 根目錄 什麼都不載入,不報錯
開發時能動、安裝後壞 安裝會複製進 cache,../shared 這類外部引用失效
改了程式沒改 version update 會說已是最新
install name 不帶 @marketplace 讀的是快取,不刷新
claude plugin eval 預設嘗試發佈 HTML 報告,要加 --no-publish;結果寫進 plugin 目錄,要放進 .gitignore,否則 tag 會被擋
清 cache 不能用 claude plugin prune,它只移除沒人依賴的自動安裝相依,要手動刪對應目錄

另外 claude plugin eval 通過不等於安全審查,官方的 help 本身就這樣警告。

什麼時候不要做 plugin

一個人、一個專案、規則還在天天改的時候,plugin 反而是負擔:每次改完要 bump 版本、update、重載。把規則檔打包時也有三個結構問題要先知道:CLAUDE.md 與規則檔不是 plugin 元件,只能改寫成 skill;hook 放兩處會跑兩次;agent 定義裡的 permissionMode、hooks、mcpServers 在 plugin 內會被忽略。

最後是一份可以直接拿去用的檢查清單:

  1. 先看來源再裝,第三方 marketplace 沒有人替你審。
  2. 裝之前先讀 hooks/hooks.json、.mcp.json 與 bin/。
  3. 對團隊分發的版本,git 來源填 sha,archive 填 sha256。
  4. 決定自動更新開或關,更新後它不會再問你。
  5. 底線用 deny 規則守,不要靠 plugin 自律。
  6. 企業端用 strictKnownMarketplaces 搭配 disableSideloadFlags。
  7. 做完先 validate,再用 --plugin-dir 試用,最後才發版。

前四天每一個擴充點都在回答「誰能做什麼」,plugin 回答的是「這一整包東西,誰有資格裝、裝了誰能改」。把能力打包得越方便,越需要先決定這條線。


上一篇
Day 20:MCP 最近的大改版,以及怎麼接、怎麼收權限、怎麼用好
下一篇
Day 22:無頭模式 `claude -p`,在沒人看著的環境裡怎麼讓它能停、能被擋
系列文
資深工程師的 Claude Code 工作筆記 共 22 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言