TL;DR
- 本文解決:自己做 Claude Code Plugin 的時候,從 marketplace.json 寫不過、cache 不更新、到跨平台跑不起來這四個坑怎麼解
- 推薦給:要做 Claude Code Plugin 給自己 / 朋友 / 團隊用的工程師
- 讀完你會知道:source欄位為什麼要./不是.、cache 為什麼 key 在版本號、python跟python3在 macOS 是兩個世界、credentials 怎麼加密分享給朋友不外洩
這篇是我做 yc-plugin 這個 Claude Code Plugin 的踩坑紀錄。Plugin 本身是「一行指令上傳 YouTube」,做完之後我順手整理了路上踩過的四個坑——剛好是新手做 Plugin 必踩的順序:marketplace 寫不過 → cache 不更新 → 別人裝下去跑不起來 → 朋友拿不到 credentials。
---
📌 目錄
---
🎯 為什麼想自己做 Plugin
Claude Code 從 2025 年底開放 Plugin 系統之後,邏輯很簡單:你已經寫過很多 .claude/commands/*.md 跟 hooks.json,這些東西只能你一個人用。把它包成 Plugin、放到 marketplace,朋友就能 /plugin install 一行裝起來。
我的場景是這樣:
- 我手上有一個自動化上傳 YouTube 的 Python 腳本
- 朋友(也是工程師、也用 Claude Code)也想用,但他不想自己摸 OAuth credential
- 想做成「他下
/youtube-upload <影片路徑>,剩下 Claude Code 自己問流程」
但動手做才發現:官方文件雖然清楚,有四個坑文件不會跟你說。
---
💥 坑 1:marketplace.json 的 source 一個斜線之差
錯誤訊息
Plugin Details
Failed to install: This plugin uses a source type your Claude Code version does not support.
第一次看到這個錯誤我以為是版本問題,跑去升級 Claude Code——沒用。再去看官方 marketplace 文件寫得很清楚:
Thesourcefield accepts a relative path like"./"for plugins inline in the marketplace repo.
我寫的是 "."(一個點)。官方接受的是 "./"(點加斜線)。
錯的版本
{
"name": "yc-plugin",
"owner": { "name": "Bob Chen" },
"plugins": [
{
"name": "yc-plugin",
"source": ".",
"description": "Upload YouTube videos via Claude"
}
]
}
對的版本
{
"name": "yc-plugin",
"owner": { "name": "Bob Chen", "email": "bobchen184@gmail.com" },
"plugins": [
{
"name": "yc-plugin",
"source": "./",
"description": "Upload YouTube videos via Claude"
}
]
}
差兩個字元而已,解析器把 "." 視為「未知 source 類型」直接拒絕。
為什麼坑
文件範例都用 "./",但人寫程式時直覺寫 "."(Unix 慣例都這樣)。Claude Code 內部判斷邏輯只認字面值,沒有 normalize。
順便提另一個 owner 的坑
第一次寫的時候 owner 我直接寫字串:
"owner": "Bob Chen"
噴:
Invalid schema: owner: Invalid input: expected object
owner 必須是 object,至少有 name,建議帶 email。一行字串不行。
---
🔄 坑 2:cache 用版本號當 key,同版本不會更新
場景
第一坑修好之後我推上去,自己用 /plugin marketplace update 拉最新版——沒反應。文件還停在舊內容。/plugin uninstall 再 /plugin install 也沒用。
我以為是 marketplace 沒推到,去 GitHub 看:明明是最新的 commit。
真相
Claude Code 的 plugin cache 是 {plugin-name}-{version} 為 key。我 plugin.json 寫的版本是 0.4.1,已經被快取住——同版本拉下來都是舊的。
唯一解法:bump 版本號。
修法
{
"name": "yc-plugin",
- "version": "0.4.1",
+ "version": "0.4.2",
...
}
同步在 marketplace.json 也要 bump:
{
"plugins": [
{
"name": "yc-plugin",
"source": "./",
- "version": "0.4.1"
+ "version": "0.4.2"
}
]
}
然後打 git tag 對齊:
git commit -am "chore: bump to 0.4.2"
git tag v0.4.2
git push origin master --tags
朋友端跑 /plugin marketplace update → /plugin install yc-plugin@yc-plugin 就會吃到新版。
為什麼這樣設計
從快取效能角度看其實合理——Claude Code 不可能每次啟動都重新 fetch 一次每個 plugin。版本號當 key、commit 才更新是正確的優化。
但對開發者來說痛點明顯:每次小修都得 bump 版本。我自己後來的工作流變成:
~/.claude/plugins/marketplaces/yc-plugin/ 直接改(symlink 到本機 working copy)如果只是測試自己的 plugin,用 claude --plugin-dir ./yc-plugin 載本機目錄完全跳過 cache,這個比 bump 版本快。
---
🐍 坑 3:python 跟 python3 在 macOS 是兩個世界
場景
第二坑修完,朋友裝下去,跑 /yc-plugin:youtube-setup:
zsh: command not found: python
我自己機器上明明跑得好好的——Bug 從 reproducer 開始。
真相
我本機 zsh 有 alias python=python3,朋友沒有。現代 macOS 預設只有 python3,沒有 python alias(從 Catalina 之後就把 Python 2 移除了)。
我的 plugin 裡所有指令都寫:
python bin/youtube_upload.py
在我這台跑得通,給其他 Mac 使用者一裝就死。
修法(comprehensive)
不能只改一個地方,全部改:
#### 3.1 所有 commands 改 python3
commands/youtube-setup.md、commands/youtube-upload.md 裡 10 個 python 全改 python3。
#### 3.2 hook 也改
hooks/hooks.json:
{
"hooks": {
"SessionStart": [
{
"hooks": [
{
"type": "command",
"command": "\"${CLAUDE_PLUGIN_ROOT}/bin/check_runtime.sh\" && python3 \"${CLAUDE_PLUGIN_ROOT}/bin/install_deps.py\""
}
]
}
]
}
}
#### 3.3 所有 Python 腳本加 shebang
bin/setup.py、bin/install_deps.py、bin/youtube_upload.py、bin/youtube_auth.py 第一行都加:
#!/usr/bin/env python3
然後 chmod +x 給執行權限。
#### 3.4 加一個前置檢查腳本
最關鍵的:寫一個 bin/check_runtime.sh,在任何 Python 腳本跑之前先確認 python3 存在。沒有就印跨平台安裝指令然後 exit 1:
#!/usr/bin/env bash
set -e
if command -v python3 >/dev/null 2>&1; then
exit 0
fi
cat >&2 <<'EOF'
[yc-plugin] python3 not found on PATH.
This plugin needs Python 3.10+ to run. Install it first:
macOS: brew install python@3.12
Ubuntu: sudo apt install python3 python3-pip
Fedora: sudo dnf install python3 python3-pip
Windows: https://www.python.org/downloads/
EOF
exit 1
掛在 SessionStart hook 上,朋友一裝 plugin 就會立刻知道環境少什麼——不會等到下指令時才噴錯。
為什麼這樣設計值得
教訓不是「python 還是 python3」這個技術細節,是心態:
- ❌ 我以為「能用就好」 → 在我機器上能用而已
- ✅ Plugin 要當「公共財」寫,不能假設別人環境跟你一樣
.claude/ 的根本差別。.claude/ 是你自己用、你環境是什麼樣它就是什麼樣;Plugin 是給其他人用、必須做 prerequisite check。
---
🔐 坑 4:credentials 怎麼加密分享給朋友
痛點
YouTube Data API v3 要 OAuth credential(從 Google Cloud Console 的 client_secret.json)。這個檔案不能進 GitHub——任何看到的人都能假冒你的應用。
但朋友也是工程師,要他自己去 Google Cloud Console 開 project、開 OAuth、申 API、下 client secret——大概要花 10 分鐘,過程中還會被「驗證需要審查」這類 dialog 嚇到。
我希望的流程是:我傳一個檔案給朋友,他指令一下就能用。
不行的做法
- ❌ 直接貼到 Discord / LINE:純文字會被截、檔案會被掃
- ❌ Email:附件可能被 Gmail 擋(Google 對 OAuth secret 特別敏感)
- ❌ 上傳 GitHub Gist 設 private:朋友下載要登 GitHub,不順
- ❌ 走 GCP IAM 加他帳號:他得有 GCP project 才行,太重
我的解法:加密 zip
# 我這邊
cd ~/Downloads
zip -e wb_creds.zip client_secret.json
# 系統會問密碼,輸入兩次
-e 是 ZIP 標準的 PKZIP 加密,AES-256 不算強但夠擋掉「不小心被別人看到」這個威脅模型——朋友都還沒拿到的時候,路徑上沒有人解得開。
然後密碼用另一條通道傳:zip 走 LINE,密碼走 Signal,或乾脆口頭講。這樣破解需要同時破兩個通道,門檻夠高。
朋友拿到後跑:
/yc-plugin:youtube-setup import ~/Downloads/wb_creds.zip
Plugin 裡面的 setup.py 處理:
client_secret.json 搬到 ~/.config/yc-plugin/chmod 600(只有 owner 能讀)這個流程完全自動化——朋友不需要懂 OAuth 也不需要碰 Google Cloud Console。
還是有限制
ZIP 加密是 convenience,不是真正的密鑰交換。如果你的威脅模型是「全國級對手」,要走 age / gpg / Vaultwarden 那些。我的場景是「不要不小心被路人看到」,AES-256 zip 完全夠。
---
⚖️ Plugin vs 純 .claude 配置 該選哪個
踩完這四個坑之後,回頭看官方文件給的判斷準則其實對:
| 情境 | 用 .claude 配置 | 包成 Plugin |
|---|---|---|
| 自己一個人用 | ✓ | △ |
| 給朋友 / 團隊用 | ✗ | ✓ |
| 多專案共用 | ✗ | ✓ |
| 要版本管理 | ✗ | ✓ |
| 要快速試一個想法 | ✓ | △ |
| 跨平台分發 | ✗ | ✓ |
- 想法剛冒出來 →
.claude/commands/xxx.md寫一個就用 - 用了兩週覺得真的有用 → bump 成 plugin
- 用了一個月朋友也想用 → 上 marketplace
.claude/ 沒這些坑,是你動手嘗試的最佳場域。
---
❓ 常見問題
Plugin 跟 Skill 是不一樣的東西嗎?
不一樣。Skill 是 Plugin 的一個組成元件。一個 Plugin 可以包多個 Skill / Agent / Hook / MCP server。最小可運行 Plugin 只要一個 .claude-plugin/plugin.json,連 Skill 都不一定要有。
我做的 Plugin 一定要上 marketplace 嗎?
不用。本機開發直接 claude --plugin-dir ./my-plugin 載目錄就能跑。要分享給朋友才需要 marketplace(其實就是一個 GitHub repo)。
Plugin cache 在哪?怎麼清?
macOS 上在 ~/.claude/plugins/cache/。手動清整個 cache 目錄通常不需要,bump 版本是更乾淨的解法。
marketplace 一定要在 GitHub 嗎?
不一定。文件支援 GitHub / GitLab / 任何 git host,甚至是 raw URL(用 --plugin-url 載 zip 也行)。但 GitHub 最方便,因為 marketplace 會自動跟 commit SHA 對齊。
朋友裝完每次開都會跑 SessionStart hook 嗎?
是的。SessionStart 是 Claude Code 一啟動就跑的 hook,所以是放「環境檢查」的好位置。但不要放會花超過 1-2 秒的事情——使用者的啟動時間會被你拖慢。
我推了 v0.4.2 但朋友還是看到 v0.4.1?
99% 是他沒跑 /plugin marketplace update。Plugin 本身的更新是手動拉的,不會自動。請他開 Claude Code → 下 /plugin marketplace update yc-plugin → 再 /plugin install yc-plugin@yc-plugin。
---
🔗 延伸資源
- Claude Code Plugin 官方文件
- yc-plugin GitHub repo(包含本文提到的四個踩坑修法)
- Plugin Marketplaces 完整 schema 參考
- 本站相關文章:如何馴服 Claude Code(CLAUDE.md / Auto memory / Agent)
- 本站相關文章:用 yc-plugin 一行指令上傳 YouTube
不怕死,只怕不過癮。