CLAUDE_CODE_PLUGIN_DIRSで複数プラグインをセッション単位で読み込む
環境変数CLAUDE_CODE_PLUGIN_DIRSに複数のパスを並べると、--plugin-dirと同じ読み込み方で複数プラグインをそのセッションだけ有効にできます。区切り文字・パスの書き方・優先順位・管理者による無効化を解説します。
CLAUDE_CODE_PLUGIN_DIRSは、そのセッションだけ読み込むプラグインのディレクトリを環境変数で列挙するための変数です。--plugin-dirフラグと同じ読み込み方をするので、コマンドラインに引数を足せない起動経路でも、複数のプラグインを開発中のまま試せます。Claude Code v2.1.280以降で使えます。マーケットプレイスから入れる第三者プラグインの例はsuperpowersの導入手順にあります。プラグインの設定項目が埋まっているかは、claude plugin configureで確かめられます。
CLAUDE_CODE_PLUGIN_DIRSは何をする変数か
公式のenv-varsリファレンスは、この変数を「セッション中に読み込むプラグインディレクトリの一覧。各パスは--plugin-dirフラグと同じ方法で読み込まれる」と説明しています。読み込んだプラグインは、そのセッションだけ有効です。
仕様は次の5点に収まります。
| 項目 | 内容 |
|---|---|
| 区切り文字 | 内容Unixは:、Windowsは; |
| パスの書き方 | 内容絶対パス、または~で始まるパス |
| 相対パス | 内容Claude Codeが読み飛ばす |
| 他の読み込み経路との関係 | 内容--plugin-dirで渡したプラグインに加えて読み込まれる |
| 必要なバージョン | 内容v2.1.280以降 |
「読み飛ばす」は文字どおりの挙動です。v2.1.289で../plugins/alphaのような相対パスだけを渡してclaude plugin listを実行すると、エラーは出ず、No plugins installed.と返りました。書き間違えても起動は通るので、プラグインが出てこない原因として真っ先に疑う箇所です。
複数のパスを並べる書き方
Unix系(macOSとLinux)では、:でパスをつなぎます。
export CLAUDE_CODE_PLUGIN_DIRS="$HOME/dev/review-plugin:$HOME/dev/deploy-plugin"
claude~始まりでも書けます。許可されているのは絶対パスか~始まりの2形式だけなので、./my-pluginのような相対指定は使えません。
Windowsのpowershellでは区切りが;になります。次は書き方の一例です。
$env:CLAUDE_CODE_PLUGIN_DIRS = "C:\dev\review-plugin;C:\dev\deploy-plugin"
claude1回だけ有効にしたいなら、変数を前置きして起動する形が手軽です。
CLAUDE_CODE_PLUGIN_DIRS="$HOME/dev/review-plugin:$HOME/dev/deploy-plugin" claude指すのは、プラグインのルートディレクトリ(.claude-plugin/plugin.jsonとskills/などが入ったフォルダ)です。配布形式ごとの違いはClaude Codeプラグインソースの使い分けに、zipでの一時ロードはプラグインのzip配布にあります。
--plugin-dirとの違いと使い分け
環境変数と--plugin-dirは同じ読み込み方ですが、渡し方が違います。
| 比較点 | --plugin-dir | CLAUDE_CODE_PLUGIN_DIRS |
|---|---|---|
| 渡し方 | --plugin-dir起動時のフラグ | CLAUDE_CODE_PLUGIN_DIRS環境変数 |
| 複数指定 | --plugin-dirフラグを繰り返す(1フラグ1パス) | CLAUDE_CODE_PLUGIN_DIRS区切り文字でつなぐ |
| 併用 | --plugin-dir可 | CLAUDE_CODE_PLUGIN_DIRS可(フラグ分に追加して読み込まれる) |
| 設定ファイルのenvブロック | --plugin-dir該当なし | CLAUDE_CODE_PLUGIN_DIRSproject / localの設定では指定できない |
| 管理者による無効化 | --plugin-dir可 | CLAUDE_CODE_PLUGIN_DIRS可 |
向き不向きは、起動経路で決まります。マーケットプレイス経由のプラグインを-pの初回ターンから使う方法は、CLAUDE_CODE_SYNC_PLUGIN_INSTALLの解説にあります。
どちらで渡すか
環境変数
ラッパースクリプト、コンテナのエントリポイント、CIのジョブ定義のように、環境変数は渡せてもコマンドラインを組み立てにくい場面で扱いやすくなります。
--plugin-dir
端末でclaudeを直接叩く場面では、フラグのほうが短く済みます。
プラグインの作成ページは、変数の用途を「フラグを足せないセッションで読み込むとき」としています。フラグと変数を同時に使っても衝突せず、両方のプラグインが有効になります。v2.1.289でCLAUDE_CODE_PLUGIN_DIRSにbeta、--plugin-dirにalphaを渡すと、claude plugin listには2つとも✔ loadedで並びました。
環境変数を渡す場所と、渡せない場所
プラグインの作成ページに「プロジェクト設定とローカル設定ではこの変数を設定できない」と書かれています。リポジトリにコミットされる.claude/settings.jsonや.claude/settings.local.jsonのenvブロックに書いても、プラグインの読み込み元にはなりません。置き場所の選択肢は次のとおりです。
- シェルの起動ファイル(bashなら
~/.bashrc、zshなら~/.zshrc)にexportを書く。全セッションに効かせる方法としてenv-varsページが案内している形です - 起動用のラッパースクリプト
- コンテナのenv指定やCIジョブの環境変数
その場でexportした場合は、その端末のセッションの間だけ有効です。端末を閉じれば読み込みも終わります。
設定ファイルのenvブロックとシェルのexportが同じ変数を持つ場合、ほとんどのセッションでは設定ファイル側の値がシェル由来の値を置き換えます。Claude Desktopアプリやself-hostedの環境ランナーがセッションを起動したときは、逆に起動環境の値が優先されます。シェルで渡したのに反映されないときは、ユーザー設定やmanaged settingsのenvに別の値が入っていないかを疑います。
たとえば、チームで共有するプラグイン群を開発用ラッパーから読み込む構成は、次のような形になります(例示であり、推奨構成ではありません)。
#!/usr/bin/env bash
# dev-claude.sh: 開発中のプラグインを2つ読み込んで起動する
PLUGINS_ROOT="$HOME/dev/plugins"
export CLAUDE_CODE_PLUGIN_DIRS="$PLUGINS_ROOT/review:$PLUGINS_ROOT/deploy"
exec claude "$@""$@"を渡しているので、--modelなど他のフラグはそのまま使えます。
同名のプラグインが入っているとどうなるか
インストール済みのプラグインと、環境変数で読み込んだプラグインの名前(manifestのname)が同じ場合は、公式のプラグイン読み込みリファレンスの優先順位で決まります。要点は次のとおりです。
- managed settingsの
enabledPluginsに載っているプラグインが最優先。ここに載った名前は、--plugin-dir側の同名コピーが読み込まれません - その次が、有効な
--plugin-dir・--plugin-url・CLAUDE_CODE_PLUGIN_DIRSのプラグイン。同名のインストール済みマーケットプレイスプラグインとスキルディレクトリのプラグインを置き換えます - その次が、インストール済みのマーケットプレイスプラグイン
マーケットプレイスからインストール済みのプラグインを置き換える場合、claude plugin listのマーケットプレイス側の行は有効のままです。表示は設定を反映しているだけで、実際に読み込まれるのは環境変数側のコピーです。切り替わったことを確かめるには、--debug付きで起動して~/.claude/debug/のログを見ます。ログにはPlugin "<name>" from --plugin-dir overrides installed versionという形の記録が出ると公式に書かれています。
自作プラグインを直しながら、配布済みの同名版と入れ替えて試せるのが、この仕組みの実用面です。アンインストールは要りません。
逆に、親プロセスが変数を設定していて同名の配布版を使いたいときは、設定ファイルで"enabledPlugins": {"<name>@inline": false}を指定します。無効にしたセッション限りのプラグインは上書きに加わらず、マーケットプレイス側のコピーが読み込まれます。claude plugin disable <name>@inlineでも同じキーが保存されます。v2.1.289では、空の設定ディレクトリでalpha@inlineを無効にするとenabledPluginsに"alpha@inline": falseが書き込まれ、claude plugin listの表示は✘ disabledになりました。
管理者がセッション単位の読み込みを止める設定
組織のmanaged settingsでdisableSideloadFlagsをtrueにすると(v2.1.193以降)、--plugin-dir・--plugin-url・--agents・--mcp-configが起動時に拒否されます。strictKnownMarketplacesで許可リストを作っても、これらのフラグで1回限りの読み込みを許してしまうと迂回できるためです。
{
"disableSideloadFlags": true
}この検査は、CLAUDE_CODE_PLUGIN_DIRSにも及びます。変数がプラグインのフォルダを指していると、フラグのときと同じエラーで終了し、エラー文には変数を外すよう案内が出ます。「変数なら通る」という抜け道にはなりません。
社内配布のプラグインしか使わせない環境では、この設定が入っている可能性があります。起動できないときは、まずエラー文に変数名が出ていないかを見てください。disableSideloadFlagsは、プラグインの中身ではなく読み込み経路そのものを閉じるスイッチです。プラグイン同士の依存を扱う話はプラグインの依存関係にあります。
読み込みを確認する手順と、つまずきやすい点
読み込みを確かめる3段階
- 1
変数の中身を出す
起動前に同じシェルで
echo "$CLAUDE_CODE_PLUGIN_DIRS"を実行し、区切りとパスを目で確かめます。代入の行は成功しても何も表示しません。 - 2
plugin listで状態を見る
変数を付けたシェルから
claude plugin listを実行すると、Session-only pluginsの見出しの下に<name>@inlineが並びます。 - 3
セッション内で読み直す
起動後は
/pluginのErrorsタブと--debugのログが手がかりです。プラグインのファイルを編集したら/reload-pluginsで読み直します。手順は/reload-pluginsで再起動なしにプラグインを反映するにあります。
v2.1.289で、alphaとbetaという2つの最小プラグインを環境変数だけで渡して確かめた出力です(パスは置き換えています)。
CLAUDE_CODE_PLUGIN_DIRS="/path/to/alpha:/path/to/beta" claude plugin listSession-only plugins (--plugin-dir / --plugin-url):
❯ alpha@inline
Version: 1.0.0
Path: /path/to/alpha
Status: ✔ loaded
❯ beta@inline
Version: 1.0.0
Path: /path/to/beta
Status: ✔ loadedフラグ経由のplugin listは、フラグをサブコマンドの前に置かないと表示されません(claude --plugin-dir ./my-plugin plugin list)。環境変数はこの順序を気にせず、変数を付ければそのまま一覧に出ます。
本文で触れていないつまずきは、次の3つです。
プラグインが出てこないときの3つの原因
相対パス
~/dev/alphaは、HOMEを差し替えた環境で$HOME/dev/alphaに展開されて読み込めました。区切り文字
Unixで
;を使うと、;でつないだ全体が1本のパスとして扱われ、Path not foundのエラーがplugin listに出ました。WindowsのパスはC:\のようにドライブ文字にコロンを含むため、:区切りは使えず、;でつなぎます。マーケットプレイスのルート
フォルダを渡したとき、読み込まれるのは直下のサブフォルダだけです。
plugins/alphaのように1段深いプラグインは対象外で、マーケットプレイス形式のフォルダ(.claude-plugin/marketplace.jsonとplugins/を持つ)を渡すと、plugin listはNo plugins installed.でした。
フォルダ単位の読み込みは、--plugin-dirの仕様として説明されているものですが、環境変数でも動きます。.claude-plugin/も最上位のコンポーネントも持たないフォルダは「プラグインのフォルダ」として扱われ、直下の各サブフォルダのうち.claude-plugin/plugin.jsonを持つものが別々のプラグインになります(v2.1.265以降)。alphaとbetaを並べたフォルダ1つを変数に渡したところ、2つとも読み込まれました。marketplace.jsonを併置したフォルダも、.claude-plugin/にplugin.jsonが無ければ読み込める仕様が、v2.1.281以降で追加されています。複数の:区切りを並べる代わりに、束ねたフォルダを1つ渡す形も選べます。
まとめ
起動のコマンドラインを書き換えられるなら--plugin-dir、ラッパーやコンテナ、CIのように環境変数しか渡せないならCLAUDE_CODE_PLUGIN_DIRS、という分け方になります。組織でセッション単位の読み込みが閉じられている環境では、どちらを使っても同じエラーで止まります。
参照した一次ソース
この記事の記述は、次の一次ソースと照合しています。更新時に参照先が変わった場合は一覧も更新します。