Claude Media
Claude Codeプラグイン依存関係 — バージョン制約とタグでリリースを固定する

Claude Codeプラグイン依存関係 — バージョン制約とタグでリリースを固定する

Claude Codeのプラグインは他のプラグインに依存でき、plugin.jsonでバージョン範囲を固定できます。宣言・タグ付け・クロスマーケットプレイス許可・無効化とpruneの挙動を実行結果つきで扱います。

Claude Codeプラグイン依存関係 — バージョン制約とタグでリリースを固定する

Claude Codeのプラグインはplugin.jsonのdependencies配列に他のプラグイン名を書くだけで、インストール時に依存先まで自動で入ります。バージョンを書かなければ、依存先はマーケットプレイスの最新リリースを追い続けます。上流の破壊的変更にも、そのまま巻き込まれます。

~2.1.0のようなバージョン範囲の書き方と自動更新の細部はプラグインの依存バージョンを固定するに、チーム全員へ配るバンドルの運用はプラグインをチームバンドルとして配布するにあります。ここでは宣言からタグ付け、無効化、pruneまでを、v2.1.287で実行した出力と並べて見ていきます。

範囲を書くと、依存先の更新は誰が決めるようになるか

シークレット管理のMCPサーバーを持つsecrets-vaultを、デプロイ支援のdeploy-kitが呼び出す構成で考えます。

くらべる

依存先の更新を、誰が決めるか

上流が決める

バージョン指定なし

"audit-logger"のように名前だけを書く形です。マーケットプレイスが次のリリースを出すと、ユーザーが更新した時点で依存先も移ります。リリースがMCPツール名を変えれば、依存元は更新した全員の環境で壊れます。

依存元が決める

~2.1.0 のような範囲

git系のソースにある依存先なら、2.1.xのパッチだけを受け取り、2.2には進みません。上げるときは、新しいリリースで動作を試したうえで、範囲を広げた新バージョンのdeploy-kitを公開します。

plugin.jsonで依存と範囲を宣言する

依存は.claude-plugin/plugin.jsonのdependencies配列に書きます。

{
  "name": "deploy-kit",
  "version": "3.1.0",
  "dependencies": [
    "audit-logger",
    { "name": "secrets-vault", "version": "~2.1.0" }
  ]
}

要素は文字列でもオブジェクトでも書けます。文字列は"audit-logger"のように名前だけ、または"name@marketplace"で別のマーケットプレイスを指す形です。範囲を付けるときはオブジェクトにし、フィールドはすべて文字列です。

フィールド説明
name説明依存先のプラグイン名。marketplaceを付けない限り、宣言元と同じマーケットプレイスで探す(必須)
version説明~2.1.0 ^2.0 >=1.4 =2.1.0のようなセマンティックバージョニング範囲。条件を満たす最も高いgitタグで入る
marketplace説明依存先を別のマーケットプレイスで探すときの名前

2.0.0-beta.1のようなプレリリース版は、^2.0.0-0のようにプレリリースを許す接尾辞を範囲に付けない限り選ばれません。

範囲の書き損じは、書いた時点では気づきにくい形をしています。versionを"~2.x.y"にしたplugin.jsonをclaude plugin validate .にかけると、descriptionとauthorが無いという警告だけが出て、結果は✔ Validation passed with warningsです(v2.1.287)。不正な範囲は、インストールか読み込みの段階でhas an invalid version requirementとして表に出ます。

依存先の公開側はタグでリリースを区切る

範囲は、依存先をホストするリポジトリのgitタグと突き合わせて解決されます。タグが無い依存先に範囲を掛けても、解決できません。タグを打つ担当は、依存先のソースで分かれます。

  • github / url / git-subdirソース: プラグイン自身のリポジトリなので、プラグインの作者が打つ
  • ./plugins/secrets-vaultのような相対パス: マーケットプレイスのリポジトリなので、マーケットプレイスの管理者が打つ
手順

依存される側のリリース手順

  1. 1

    versionを上げる

    plugin.jsonのversionを更新します。マーケットプレイスにエントリがあれば、同じ値にそろえます。

  2. 2

    タグ名を先に見る

    claude plugin tag --dry-runで、作られるタグと実行されるgitコマンドを表示させます。

  3. 3

    タグを作ってpushする

    claude plugin tag --pushを実行します。成功するとCreated tag secrets-vault--v2.1.0とPushed to originが出ます。--pushなしなら、代わりにpushコマンドが表示されます。

タグ名は<プラグイン名>--v<バージョン>で固定です。名前を接頭辞にするため、1つのマーケットプレイスのリポジトリで複数のプラグインが別々の版数を持てます。

secrets-vaultのplugin.jsonが"version": "2.1.0"のgitリポジトリで--dry-runを実行すると、次の出力でした。

claude plugin tag --dry-run
Plugin:  secrets-vault
Version: 2.1.0 (from plugin.json)
Tag:     secrets-vault--v2.1.0
 
✔ Dry run — would create tag secrets-vault--v2.1.0 at HEAD in /path/to/secrets-vault
  git -C /path/to/secrets-vault tag -a secrets-vault--v2.1.0 -m "secrets-vault 2.1.0"
  git -C /path/to/secrets-vault push origin refs/tags/secrets-vault--v2.1.0

作られるのは注釈付きタグ(-a)で、メッセージの既定は<名前> <バージョン>です。-mで変えられ、%sがバージョンに置き換わります。リモートを設定していない作業ディレクトリでも、--dry-runはpush用のコマンドまで表示して終わりました。

タグを作る前に、コマンドは次の4点を検査します。

  • プラグインの検証
  • plugin.jsonとマーケットプレイスのエントリで、バージョンが一致していること(プラグインがマーケットプレイスのチェックアウト内にあるとき)
  • プラグインのディレクトリ配下の作業ツリーがクリーンであること
  • 同名のタグが無いこと

-f / --forceを付けると、作業ツリーの検査と同名タグの検査は飛ばせます。--pushが失敗してもタグはローカルに残り、コマンドはエラー終了します。セッション中は/plugin tag [path] [--push] [--dry-run] [--force]でも同じタグを作れます。git tag secrets-vault--v2.1.0を直接打っても等価ですが、2つのバージョンを自分でそろえる責任が付きます。

範囲を満たすタグが見つからないとき

{ "name": "secrets-vault", "version": "~2.1.0" }を持つプラグインを入れると、secrets-vault--vで始まるタグのうち~2.1.0を満たす最も高いものが取得されます。満たすタグが無いときの行き先は、依存先のソースで3通りに分かれます。

3パターン

タグで解決できないときの行き先

  • 自前のリポジトリを持つプラグイン

    インストールが失敗し、Dependency "secrets-vault@your-marketplace" has no git tag satisfyingで始まるメッセージが出ます。

  • 相対パスで参照されるプラグイン

    マーケットプレイスの現行コピーが入り、範囲は読み込み時に検査されます。範囲外なら依存元は無効のままで、claude plugin listにRequires "secrets-vault@your-marketplace" ~2.1.0, installed 3.0.0と出ます。

  • npm / archive / commandソース

    タグでは解決されません。依存先のplugin.jsonにあるversionが読み込み時に照合され、範囲外なら依存元が無効になります。versionを書いていない依存先は、どの範囲も満たせません。

commandソースの依存先は、Claude Code自身がインストールしません。headersHelperを持つマーケットプレイスエントリの依存先も同様で、どちらも利用者が先に自分で入れます。

claude plugin listには、タグから解決した依存先のバージョンが12文字のコミット接尾辞付き(2.1.0-8713c5b11005の形)で出ます。範囲の検査に使われるのはplugin.jsonのversionではなくタグ側のバージョンなので、そのコミットのplugin.jsonが古い値のままでも検査は通ります。タグを別のコミットへ強制的に動かした場合、次のインストールは古いキャッシュを使い回さず、移動先の内容を取得します。

別のマーケットプレイスにある依存先を許可する

依存先が宣言元と別のマーケットプレイスにあると、既定では自動インストールされません。レビューしていない配布元のプラグインを、別のマーケットプレイスが黙って引き込む事態を防ぐためです。例外は、同じスコープで依存先をユーザーが既に有効にしている場合です。

許可するには、ユーザーがインストールするプラグインを直接ホストしているマーケットプレイス(ルート)のmarketplace.jsonに、allowCrossMarketplaceDependenciesOnで相手の名前を書きます。許可が効くのはルートの一覧だけで、中間のマーケットプレイスを経由して信頼は連鎖しません。

{
  "name": "acme-tools",
  "owner": { "name": "Acme" },
  "allowCrossMarketplaceDependenciesOn": ["acme-shared"],
  "plugins": [
    {
      "name": "deploy-kit",
      "source": "./deploy-kit",
      "dependencies": [
        { "name": "audit-logger", "marketplace": "acme-shared" }
      ]
    }
  ]
}

許可が無いときの失敗の形は、依存を書いた場所で変わります。

依存を書いた場所許可が無いときの結果
marketplace.jsonのエントリ許可が無いときの結果インストール自体が拒否される。メッセージはDependency "audit-logger@acme-shared" (required by deploy-kit@acme-tools) is in marketplace "acme-shared", which is not in the allowlistで始まり、設定すべきフィールド名も示す
plugin.json許可が無いときの結果インストールは依存先なしで完了し、そのあとdeploy-kitが読み込みに失敗する

どちらの場合も、claude plugin install audit-logger@acme-sharedを、deploy-kitと同じ--scopeで先に実行しておけば通ります。

複数のプラグインが同じ依存先に範囲を掛けたとき

同じ依存先に複数のプラグインが範囲を掛けていると、すべての範囲を満たす最も高いバージョンに解決されます。

プラグインAの範囲プラグインBの範囲結果
^2.0プラグインBの範囲>=2.1結果2.1.0以上で最も高い2.xのタグに1つだけ入る。両方が読み込まれる
~2.1プラグインBの範囲~3.0結果Bのインストールがhas conflicting version requirementsで失敗する。Aと依存先は元のまま
=2.1.0プラグインBの範囲なし結果依存先は2.1.0のまま。Aが入っている間、自動更新は新しいバージョンを飛ばす

自動更新も、マーケットプレイスの最新ではなく、全プラグインの範囲を満たす最高のタグを取りにいきます。範囲が重ならないと、依存先は今のバージョンのまま残り、/pluginのErrorsタブに制約元のプラグインを名指しした項目が出ます。範囲は重なるのに該当するタグが無いときは、マーケットプレイスの現行コピーを取得します。そのコピーのversionがどれかの範囲の外なら、更新は見送られます。範囲を掛けていたプラグインを最後の1本までアンインストールすると、依存先は固定を外れ、次の更新からマーケットプレイスのエントリに追従します。

インストールからpruneまで、実行結果で追う

ローカルのacme-toolsマーケットプレイスから、deploy-kit(audit-loggerとsecrets-vault ~2.1.0に依存)を入れた場合の出力です(空のHOME、v2.1.287)。audit-loggerのplugin.jsonにだけ"defaultEnabled": falseを書いています。

claude plugin install deploy-kit@acme-tools
✔ Successfully installed plugin: deploy-kit@acme-tools (scope: user) (+ 2 dependencies: audit-logger, secrets-vault)

依存先の2つは、同じ操作の中で入ります。ここで目を引くのがsettings.jsonです。

{
  "enabledPlugins": {
    "deploy-kit@acme-tools": true,
    "audit-logger@acme-tools": true,
    "secrets-vault@acme-tools": true
  }
}

依存先として引き込まれたプラグインには、defaultEnabled: falseでも明示的なtrueが書かれました。依存元が呼び出す前提のプラグインが、既定の無効のまま残って動かない事態は起きません。claude plugin listも3つともStatus: ✔ enabledでした。

依存されているプラグインは単独で無効にできない

secrets-vaultだけを無効にしようとすると、次の結果になります(終了コードは1、v2.1.287)。

✘ Failed to disable plugin "secrets-vault@acme-tools": secrets-vault is still required by deploy-kit. Disable that plugin first, or disable everything together: claude plugin disable deploy-kit@acme-tools && claude plugin disable secrets-vault@acme-tools

有効な依存元が残っている限り、依存先は無効にできません。末尾の連結コマンドをそのまま実行すれば、正しい順序で両方が止まります。

反対向きのclaude plugin enableは、依存先も有効にします。次のいずれかのときは失敗します。

条件表示される内容
依存先が未インストール表示される内容不足している依存先ごとのclaude plugin installコマンド
依存先が組織のプラグインポリシーでブロックされている表示される内容ブロックされている依存先の名前
依存先が、対象より優先順位の高いスコープでfalseになっている表示される内容失敗する。そのスコープで有効にするか、--scopeで書き込み先を指す

アンインストールしても依存先は残る

deploy-kitをアンインストールした直後の表示です。

✔ Successfully uninstalled plugin: deploy-kit (scope: user)
2 auto-installed dependencies no longer needed: audit-logger, secrets-vault. Run `claude plugin prune` to remove.

自動で入った依存先は、依存元を消しても残ります。片付けはclaude plugin pruneの役目で、まず--dry-runで対象を見られます。

claude plugin prune --dry-run
2 auto-installed plugins no longer needed at user scope:
  audit-logger@acme-tools (1.0.0)
  secrets-vault@acme-tools (2.1.0)
(dry run — nothing removed)

claude plugin prune -yを実行するとRemoved 2 auto-installed plugins: audit-logger, secrets-vaultと表示され、claude plugin listはNo plugins installed.に戻りました。対象が無いときは、Nothing to prune (no auto-installed plugins at user scope).と出て終了し、これはエラーではありません。

pruneの既定のスコープはuserで、--scope projectか--scope localで変えられます。標準入力か標準出力が端末でないときは、-yを付けない限り一覧とNot a TTYの案内を出すだけで、何も消しません。自分で明示的にインストールしたプラグインは、他のプラグインの依存先と同名でも対象になりません。アンインストールと同時に済ませるならclaude plugin uninstall deploy-kit --pruneです(非対話の環境では-yが必要)。

依存のエラーメッセージから原因を探す

エラーが出る場面は2つあります。インストール時の拒否はそのコマンドのエラーとして返り、読み込み時の問題はclaude plugin listと/pluginのErrorsタブに出て、該当プラグインは解決まで無効のままです。

メッセージ原因直し方
Dependency "<dep>" is not installed原因宣言された依存先が未インストール直し方claude plugin install <dep>@<marketplace>を実行する。マーケットプレイスが未登録なら追加して/reload-pluginsを実行すると、解決できる依存先が入る
Dependency "<dep>" is disabled原因依存先は入っているが無効直し方依存先を有効にするか、依存元をアンインストールする
Requires "<dep>" <range>, installed <version>原因インストール済みの依存先が、宣言された範囲の外直し方範囲に入るバージョンへ更新するか、依存元をアンインストールする
... has conflicting version requirements原因全範囲を満たすバージョンが無い。範囲の一覧が付く直し方競合するプラグインのどちらかを更新・削除するか、上流に範囲を広げてもらう
... has version requirements too complex to intersect / has an invalid version requirement原因範囲がsemverとして不正、または重ね合わせられない直し方不正な範囲を直す。長い||の連鎖を単純にする
... has no git tag satisfying <range>原因依存先のリポジトリに、範囲を満たす<name>--v*タグが無い直し方上流がこの命名でタグを打っているか調べるか、自分の範囲を緩める
... is in marketplace "<m>", which is not in the allowlist原因別マーケットプレイスの依存先で、許可が無い直し方依存先を同じスコープで先に自分でインストールする

プログラムから読むならclaude plugin list --jsonです。問題のあるプラグインにはerrorsと、各エラーのtypeを持つerrorDetailsが付きます。typeは、最初の2行がdependency-unsatisfied、3行目がdependency-version-unsatisfiedです。

依存元と依存先を同時に開発する

両方を--plugin-dirで読み込むと、依存先をマーケットプレイスから入れ直さずに試せます。

claude --plugin-dir ./my-dependency --plugin-dir ./my-plugin

ローカルコピーが依存エントリを満たします。範囲の検査はローカルコピーには行われないので、plugin.jsonにversionが無くても動きます。2つのプラグインが同じ親フォルダに並んでいるなら、親フォルダを1回渡す形でも読み込めます。フォルダ自体がプラグインでなければ、.claude-plugin/plugin.jsonを持つ子フォルダが1つずつ読み込まれ、v2.1.265以降で使えます。

依存先をマーケットプレイスからインストールしていない間は、ローカルコピーが無効または不在になると、依存元の読み込みが止まります。

  • ローカルコピーを自分で無効にした: 次のプラグイン読み込みで、依存元がis disabled — enable it or remove the dependencyで終わるエラーとともに無効になる。依存先は<name>@inlineと呼ばれ、--plugin-dirで読み込んだコピーを指す
  • 依存先の--plugin-dirを付けずに起動した: 依存先が未インストールとして報告される。フラグを付け直すか、マーケットプレイスからインストールする

チーム向けに依存だけのプラグインをバンドルにする

nameとdependenciesだけを持つプラグインは、それ自体が有効なプラグインで、インストールすると依存先がすべて入ります。役割別のセットを1コマンドで配る形です。

{
  "name": "backend-standard",
  "version": "1.0.0",
  "description": "Standard plugin set for backend engineers",
  "dependencies": [
    "secrets-vault",
    "deploy-kit",
    { "name": "db-migrate", "version": "^3.0" },
    "oncall-runbook"
  ]
}

セットにプラグインを足すときは、依存を増やした新しいbackend-standardを公開します。マーケットプレイスの自動更新が既定で無効なら、利用者側の反映は2通りです。マーケットプレイスの自動更新を有効にするか、手動でclaude plugin update backend-standardを実行します。手動のときは、開いているセッションで/reload-pluginsも実行すると、増えた依存先が入ります。組織全員に配るなら、管理者がmanaged settingsのenabledPluginsにバンドルを加えます。

まとめ

作る側は、範囲を書く前に依存先のタグがあるかを確かめます。タグが無い依存先に範囲を掛けても、解決も固定も働きません。使う側は、依存元を外したあとにclaude plugin prune --dry-runで残りを見る習慣があれば、使われなくなった依存先を溜めずに済みます。

Claude Codeのプラグイン配布全体はClaude Codeプラグイン完全ガイドに、信頼できないソースを弾く仕組みは「untrusted source」エラーの対処にあります。

この記事を共有:XはてブLinkedIn