[AI 工具] · · 20min read

自製 Claude Code Plugin 必踩的四個坑:marketplace、cache、跨平台與 credentials 分享

做 yc-plugin 路上踩過的四個坑:marketplace.json 的 source 寫法、plugin cache 為什麼不更新、python vs python3 跨平台問題、credentials 加密 zip 分享給朋友。

章節目錄 · 9
TL;DR
- 本文解決:自己做 Claude Code Plugin 的時候,從 marketplace.json 寫不過、cache 不更新、到跨平台跑不起來這四個坑怎麼解
- 推薦給:要做 Claude Code Plugin 給自己 / 朋友 / 團隊用的工程師
- 讀完你會知道:source 欄位為什麼要 ./ 不是 .、cache 為什麼 key 在版本號、pythonpython3 在 macOS 是兩個世界、credentials 怎麼加密分享給朋友不外洩

這篇是我做 yc-plugin 這個 Claude Code Plugin 的踩坑紀錄。Plugin 本身是「一行指令上傳 YouTube」,做完之後我順手整理了路上踩過的四個坑——剛好是新手做 Plugin 必踩的順序:marketplace 寫不過 → cache 不更新 → 別人裝下去跑不起來 → 朋友拿不到 credentials。

yc-plugin Claude Code 自製插件 GitHub repo 預覽

---

📌 目錄

  • 為什麼想自己做 Plugin

  • 坑 1:marketplace.json 的 source 一個斜線之差

  • 坑 2:cache 用版本號當 key,同版本不會更新

  • 坑 3:python 跟 python3 在 macOS 是兩個世界

  • 坑 4:credentials 怎麼加密分享給朋友

  • Plugin vs 純 .claude 配置 該選哪個

  • 常見問題

  • 延伸資源
  • ---

    🎯 為什麼想自己做 Plugin

    Claude Code 從 2025 年底開放 Plugin 系統之後,邏輯很簡單:你已經寫過很多 .claude/commands/*.mdhooks.json,這些東西只能你一個人用。把它包成 Plugin、放到 marketplace,朋友就能 /plugin install 一行裝起來。

    我的場景是這樣:

    • 我手上有一個自動化上傳 YouTube 的 Python 腳本
    • 朋友(也是工程師、也用 Claude Code)也想用,但他不想自己摸 OAuth credential
    • 想做成「他下 /youtube-upload <影片路徑>,剩下 Claude Code 自己問流程」
    把這個流程包成 Plugin,就可以從 GitHub 直接安裝、版本化更新、credentials 用加密 zip 傳一次就好

    但動手做才發現:官方文件雖然清楚,有四個坑文件不會跟你說

    ---

    Claude Code Plugin 系統官方 GitHub repo

    💥 坑 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 文件寫得很清楚:

    The source field 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)

  • 改到滿意再 bump 版本 + push

  • 朋友那邊才會看到更新
  • 如果只是測試自己的 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.mdcommands/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.pybin/install_deps.pybin/youtube_upload.pybin/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 要當「公共財」寫,不能假設別人環境跟你一樣
    這就是 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 處理:

  • 提示輸入密碼

  • 解開 zip

  • client_secret.json 搬到 ~/.config/yc-plugin/

  • 立刻 chmod 600(只有 owner 能讀)

  • 刪掉解開的暫存檔
  • 這個流程完全自動化——朋友不需要懂 OAuth 也不需要碰 Google Cloud Console。

    還是有限制

    ZIP 加密是 convenience,不是真正的密鑰交換。如果你的威脅模型是「全國級對手」,要走 age / gpg / Vaultwarden 那些。我的場景是「不要不小心被路人看到」,AES-256 zip 完全夠。

    ---

    Anthropic 官方 Cookbook 作為 Claude Code Plugin 開發參考

    ⚖️ Plugin vs 純 .claude 配置 該選哪個

    踩完這四個坑之後,回頭看官方文件給的判斷準則其實對:

    情境用 .claude 配置包成 Plugin
    自己一個人用
    給朋友 / 團隊用
    多專案共用
    要版本管理
    要快速試一個想法
    跨平台分發
    判斷規則我自己用得舒服的版本:
    • 想法剛冒出來 → .claude/commands/xxx.md 寫一個就用
    • 用了兩週覺得真的有用 → bump 成 plugin
    • 用了一個月朋友也想用 → 上 marketplace
    不要一開始就上 Plugin——前面四個坑會把熱情磨光。.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

    ---

    🔗 延伸資源

    不怕死,只怕不過癮。
    author
    陳彥彤

    AI 工程師 · AI 顧問。Java 後端 8 年、AI 工程師 2 年。AI 內訓 · AI 導入顧問 · 前後端與雲端培訓。

    support

    覺得文章有用可以到 GitHub 給個 star,或是透過信箱聊聊 AI 內訓、AI 導入顧問或前後端 / 雲端培訓。