Claude Media
Claude Codeプラグインのキャッシュとファイル解決の仕組み

Claude Codeプラグインのキャッシュとファイル解決の仕組み

マーケットプレイス経由のプラグインはバージョンごとにキャッシュへコピーされ、npm依存は自動インストール・古いパスの参照はパストラバーサル制限で拒否されます。symlinkの扱いも3パターンに分かれます。

Claude Codeプラグインのキャッシュとファイル解決の仕組み

マーケットプレイス経由でインストールしたプラグインは、実体のあるディレクトリではなく~/.claude/plugins/cacheにコピーされたバージョンごとのディレクトリから読み込まれます。更新やアンインストールをしても古いバージョンはすぐには消えず、Node.js依存関係の自動インストールやパストラバーサル制限、symlinkの扱いもこのキャッシュ機構を前提に設計されています。仕組みを知らないと「更新したのに古い挙動のまま」「なぜかスクリプトがパッケージを見つけられない」といったつまずきの原因がつかめません。

プラグインはどこにキャッシュされるか

プラグインの指定方法は2種類あります。claude --plugin-dirまたはclaude --plugin-urlでセッション限定で読み込む方法と、マーケットプレイス経由でインストールして以後のセッションでも使う方法です。

セキュリティと検証のため、マーケットプレイス経由のプラグインは元の場所のまま使われるのではなく、ユーザーのローカルプラグインキャッシュ(~/.claude/plugins/cache)にコピーされます。唯一の例外はコマンドソースをリンクモードで使う場合で、この場合はキャッシュ内のエントリからリンクを通じて元の場所をそのまま使います。

コピーされたプラグインは、インストールしたバージョンごとに別々のディレクトリとしてキャッシュに保存されます。マーケットプレイスとプラグイン名でグループ化され、解決済みバージョン名でディレクトリ名が付き、そのプラグイン自身のファイルとNode.jsパッケージ依存関係のコピーを持ちます。リリースタグから解決した依存関係の場合は、ディレクトリ名にコミットSHAのサフィックスが付きます。

バージョンごとにディレクトリが分かれる仕組み

プラグインを更新またはアンインストールすると、Claude Codeは旧バージョンのディレクトリを「孤立(orphaned)」としてマークし、およそ14日後のバックグラウンドの掃除処理で削除します。この猶予期間があるおかげで、旧バージョンを既に読み込んでいる別セッションが動いていても、エラーを起こさず動作を続けられます。

この掃除処理は少なくとも1つプラグインがインストールされている間だけ実行されます。最後の1つをアンインストールしてしまうと、孤立したディレクトリはその後プラグインを再インストールするまでディスクに残り続けます。

Claude Codeがプラグインやマーケットプレイスのフォルダをキャッシュから削除するのは、そのフォルダがどのディレクトリもsymlinkも含まなくなったときだけです。開発中のチェックアウトをシンボリックリンク(symlink)としてキャッシュ内のバージョンエントリにリンクしている場合、Claude Codeはそのリンクを孤立とマークしません。リンクやそれを保持するフォルダを削除することもなく、バージョン追跡用のファイルをリンク先のチェックアウト内に書き込むこともありません。

GlobツールとGrepツールは検索時に孤立したバージョンディレクトリをスキップするため、検索結果に古いプラグインコードが紛れ込むことはありません。

Node.jsパッケージ依存は自動インストールされる

プラグインをキャッシュにコピーするとき、Claude Codeはそのプラグインが自分のpackage.jsonで宣言しているNode.js依存関係もキャッシュ内にインストールします。これによりプラグインのhookやMCPサーバーがその依存関係を読み込めるようになります。ここで扱うのはあくまでプラグイン自身のpackage.jsonが指すnpm・Bunパッケージで、プラグイン同士の依存関係はバージョン制約付きで宣言でき、これとは別の仕組みで解決されます。

この自動インストールが走るのは、プラグインのルートディレクトリにpackage.jsonと対応するlockfileが両方存在するときだけです。

lockfile実行されるコマンド
bun.lockまたはbun.lockb実行されるコマンドbun install --frozen-lockfile --ignore-scripts
npm-shrinkwrap.jsonまたはpackage-lock.json実行されるコマンドnpm ci --ignore-scripts

複数のlockfileが同居している場合は、bun.lockbun.lockbnpm-shrinkwrap.jsonpackage-lock.jsonの順で最初に一致したものが使われます。一致したlockfileに対応するパッケージマネージャーはユーザーのPATHから実行され、それが見つからなくても別のlockfileにフォールバックすることはありません。bunが入っていない環境でbun.lockを同梱すると、そこでインストールが失敗します。npm経由で配布するプラグインではnpm-shrinkwrap.jsonが適します。npmは公開パッケージからpackage-lock.jsonを除外するためです。yarn.lockpnpm-lock.yamlはスキップされます。Yarnとpnpmは依存解決時の設定フックに対応しており、それが--ignore-scriptsをすり抜けてしまうためです。

この依存関係インストールには3つの制約がかかっています。1つはロックファイルが固定するバージョンだけを厳密に入れる点で、package.jsonとロックファイルが食い違えば再解決せずに失敗します。2つ目はpreinstallinstallpostinstallのライフサイクルスクリプトを実行しないことです。3つ目は60秒でタイムアウトすることです。ネイティブモジュールをこれらのスクリプトでビルドする依存関係は、この時点ではダウンロードだけされてコンパイルはされません。

インストールが失敗またはスキップされてもプラグイン自体はブロックされません。失敗時やYarn・pnpmのlockfileをスキップした場合は、デバッグ出力に警告として理由が記録されます。package.jsonがあってlockfileが無いプラグインは、ログにも残らずそのままスキップされます。タイムアウトした場合、キャッシュ内のコピーにnode_modulesが中途半端な状態で残ることがあります。

この自動インストールを無効化する設定や環境変数はありません。ライフサイクルスクリプトの実行が必要なパッケージ、Python依存関係、Yarn・pnpmでロックされた依存関係のように自動インストールが対応できないものは、プラグインの環境変数とパスの解決ルールで扱うSessionStartフックの型を使い、永続データディレクトリへインストールする形を取ります。

パストラバーサル制限 — ../参照はなぜ弾かれるか

Claude Codeはプラグインが自分のディレクトリの外にあるファイルを参照することを許しません。plugin.jsonやマーケットプレイスエントリのどちらで宣言されたパスであっても、プラグインルートの外に解決される../shared-utilsのようなパスは拒否されます。このときClaude Codeはpath escapes plugin directoryというエラーを報告し、そのコンポーネントを除いた残りの部分でプラグインを読み込みます。

commands path escapes plugin directory: ./../shared.md

claude pluginコマンドの出力では同じエラーがPath escapes plugin directory: ./../shared.md (commands)という形で表示されます。マーケットプレイスエントリのcommandsパスについては、v2.1.251より前はプラグインディレクトリの外を指していても読み込まれてしまう例外がありました。plugin.jsonで宣言されたパスや、マーケットプレイスエントリの他のコンポーネントパスはそれ以前から一貫して拒否されています。

Claude Codeはプラグインをインストールする際にも、プラグインディレクトリの外にあるファイルをキャッシュにコピーしません。そのため、コピーされたプラグイン内のスクリプトがプラグインルートより上のパスを読もうとしても、そこにファイルを見つけることはできません。

symlinkの3つの扱い方

同じマーケットプレイス内で他のプラグインとファイルを共有したい場合、プラグインディレクトリの中にシンボリックリンクを作れます。ただしリンク先がどこに解決されるかによって、キャッシュへコピーされるときの扱いが3通りに分かれます。

リンク先キャッシュでの扱い
プラグイン自身のディレクトリ内キャッシュでの扱い相対symlinkとして保存され、実行時もコピー先のターゲットを指し続ける
同じマーケットプレイス内の他の場所キャッシュでの扱いsymlinkは実体化(dereference)され、ターゲットの内容がコピーされる。メタプラグインのskills/が他プラグインのスキルをリンクする用途に使える
マーケットプレイスの外キャッシュでの扱いセキュリティ上の理由でスキップされる。システムパスなど任意のホストファイルをキャッシュに引き込むことを防ぐ

次のコマンドは、マーケットプレイス内のプラグインから、兄弟プラグインが定義する共有スキルへのリンクを作る例です。Windowsでは管理者権限のコマンドプロンプトからmklink /Dを使うか、開発者モードを有効にします。

ln -s ../../shared-plugin/skills/foo ./skills/foo

--plugin-dirでのインストール、ローカルパスからのインストール、コピーモードのコマンドソースからのインストールでは、プラグイン自身のディレクトリ内に解決されるsymlinkだけが保持されます。それ以外はすべてスキップされます。

キャッシュの仕組みが実務にどう効くか

このキャッシュ機構が意味するのは、プラグインの実体がユーザーの意識しないところで多重化されているということです。更新のたびに新しいバージョンディレクトリが増え、旧バージョンは14日残ります。開発中のプラグインを頻繁に更新しながら動作確認していると、この猶予期間中はディスク上に複数バージョンが同居することになります。ふだんは意識する必要がありませんが、ディスク容量やデバッグ時に「どのバージョンが読み込まれているか」を切り分けたい場面では、この仕組みを知っているかどうかで調査のスピードが変わります。

自動インストールが--ignore-scriptsとFrozen resolutionを徹底しているのも、プラグインをインストールするだけで任意コードが実行される事態を避けるためです。ネイティブモジュールのビルドが必要な依存関係を使うプラグインを配布するなら、自動インストールに頼らずhookで永続データディレクトリへ導入する設計を最初から選んでおくほうが安全です。

よくあるつまずき

  • ネイティブモジュールが動かない: 自動インストールは--ignore-scripts付きで走るため、ビルドスクリプトが必要な依存関係はダウンロードされてもコンパイルされません。hookからの手動インストールに切り替えます。
  • package.jsonを書いたのにインストールされない: lockfileが無い、またはYarn・pnpmのlockfileしか無いプラグインは自動インストールの対象外です。npm・Bunの対応lockfileを同梱します。
  • 共有ファイルへのシンボリックリンクがキャッシュで消える: マーケットプレイスの外を指すsymlinkはセキュリティ上スキップされます。共有したいファイルは同じマーケットプレイス内に置きます。
  • 開発中のプラグインが更新しても古いまま動く: symlinkでキャッシュにリンクした開発チェックアウトは孤立判定されず残り続けます。バージョン管理ファイルもリンク先には書き込まれないため、更新の反映状況を別途確認する必要があります。

よくある質問

プラグインを更新すると旧バージョンのファイルはすぐ消えますか

すぐには消えません。孤立とマークされてからおよそ14日後のバックグラウンドの掃除処理で削除されます。この猶予期間は、旧バージョンを既に読み込んでいる別セッションを壊さないための仕組みです。

プラグインを最後の1つまでアンインストールするとキャッシュはどうなりますか

孤立したディレクトリの掃除処理は少なくとも1つプラグインがインストールされている間だけ動くため、最後の1つをアンインストールした後は、次にプラグインを再インストールするまで孤立ディレクトリがディスクに残り続けます。

npmソースのプラグイン自体を取得するときもライフサイクルスクリプトは無効化されますか

いいえ。npmソースのプラグイン自体を取得するnpm installはライフサイクルスクリプトを有効にしたまま実行されます。--ignore-scriptsが適用されるのは、そのプラグインが自分のpackage.jsonで宣言する依存関係をキャッシュにインストールする、後段の処理だけです。

パストラバーサル制限に引っかかったコンポーネントがあると、プラグイン全体が読み込めなくなりますか

なりません。該当するコンポーネントのパスだけが除外され、Claude Codeは残りのコンポーネントでプラグインを読み込みます。エラーメッセージにはどのフィールド(commandsなど)が原因かが表示されます。

制限されたネットワーク環境で自動インストールが失敗する場合はどうすればよいですか

自動インストールを無効化する設定や環境変数はありません。ネットワークアクセスの要件を確認し、必要なホストへの通信を許可する必要があります。それでも導入できない依存関係は、hookから永続データディレクトリへインストールする形に切り替えます。

まとめ

マーケットプレイス経由のプラグインは~/.claude/plugins/cacheにバージョンごとコピーされ、更新・アンインストール後も孤立ディレクトリとして14日残ります。Node.js依存関係はpackage.jsonと対応lockfileがある場合のみ、ライフサイクルスクリプト無効・タイムアウト60秒という制約付きで自動インストールされます。プラグインディレクトリの外を指すパスはパストラバーサル制限で拒否され、symlinkはリンク先がプラグイン内かマーケットプレイス内か外かで扱いが3通りに分かれます。プラグインの基本構造や自作の手順はClaude Codeプラグイン完全ガイド、環境変数とパスの参照ルールはプラグインの環境変数とパスの解決ルールで扱っています。

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