マーケットプレイスのstrict modeとvalidateの使い方
定義の権威を決めるstrict modeと、配布前に実行するclaude plugin validateの使い方を扱います。
このTipsでできること
マーケットプレイスを配る前の確認を2点に絞ります。マーケットプレイスエントリの strict フィールドの使い分けと、claude plugin validate の使いどころです。
困りごとから逆引きすると、入口は2つです。プラグインが「failed to load」になるなら strict の組み合わせを、marketplace.json の誤りを配布前に拾いたいなら validate を見ます。手元のClaude Code v2.1.287で両方を動かした出力も載せています。
プラグインが「conflicting manifests」で読み込めないとき
strict は、plugin.json を持つプラグインに対して、マーケットプレイスエントリがコンポーネントを書いたときの扱いを決める設定です。ここでいうコンポーネントは、エントリの6フィールドです。commands / agents / skills / hooks / outputStyles / themes が該当します。
競合の条件は、plugin.json がコンポーネントを宣言していることではありません。plugin.json が存在し、かつエントリ側がコンポーネントを書いていることです。plugin.json が name や description だけの場合でも同じで、エントリにコンポーネントがあれば strict: false は失敗します。逆に plugin.json が無いプラグインなら、strict の値に関係なくエントリがマニフェストそのものになります。
strict | plugin.json | エントリのコンポーネント | 結果 |
|---|---|---|---|
| 任意 | plugin.jsonなし | エントリのコンポーネント任意 | 結果エントリがマニフェストになる |
true | plugin.jsonあり | エントリのコンポーネント任意 | 結果plugin.json が主で、エントリの内容が追記される。ただし hooks は、イベントごとにエントリ側のマッチャーが plugin.json のものを置き換える |
false | plugin.jsonあり | エントリのコンポーネントなし | 結果plugin.json がマニフェストになる |
false | plugin.jsonあり | エントリのコンポーネント1つ以上 | 結果競合。プラグインは読み込まれない |
実際の失敗を再現する
plugin.json がスキルを宣言しているプラグインに対し、エントリ側でも skills を指定し、strict を false にしました。
{"name":"b","source":"./plugins/b","strict":false,"skills":["./skills/x"]}この状態で claude plugin validate を走らせると、v2.1.287では ✔ Validation passed で終わり、終了コードも0でした。ところがマーケットプレイスを追加してインストールし、claude plugin list を見るとこうなります。
❯ b@demo-market
Version: 1.0.0
Scope: user
Status: ✘ failed to load
Error: Plugin b has conflicting manifests: both plugin.json and marketplace entry specify components. Set strict: true in marketplace entry or remove component specs from one location.インストール自体は Successfully installed と表示されるので、失敗はインストール直後ではなく一覧で初めて見えます。strict を true に直して更新と再インストールをすると、同じプラグインが Status: ✔ enabled になりました。つまり、strictの競合は validate では拾えず、実際にインストールして claude plugin list を見る工程が要ります。
エラー文の対処は2通りです。エントリ側のコンポーネント指定を消すか、strict: true に戻すかです。
どちらを選ぶか
strict: true は、プラグインが自分の plugin.json でコンポーネントを管理している場合の既定です。ほとんどのプラグインはこのままで足ります。
strict: false にすると、plugin.json が唯一の権威になります。エントリ側でコンポーネントを足す書き方は、追記されずに読み込みエラーで止まります。エントリ側の指定が紛れ込まないことを保証したいプラグインに向く設定です。
必須になる場面もあります。headersHelper を使うarchive形式のエントリは "strict": false が必須です。外すと Plugin "x" sets headersHelper but is not "strict": false のエラーになります。
strictKnownMarketplacesとは別の設定
名前が似た設定に strictKnownMarketplaces があります。こちらは組織のmanaged settingsに書き、ユーザーが追加できるマーケットプレイスを許可リストで絞ります。strict は .claude-plugin/marketplace.json のプラグインエントリに書く設定で、置き場所も役割も別です。managed settingsの仕組みはClaude Code組織管理ガイドにあります。
配布前にclaude plugin validateで拾えるもの
マーケットプレイスのディレクトリで次を実行します。Claude Codeのセッション内なら /plugin validate . でも同じ検証が走ります。
claude plugin validate .マーケットプレイスを対象にすると、marketplace.json のスキーマエラー、プラグイン名の重複、source の .. を検査します。source がローカルパスのエントリは、そのプラグイン自身の plugin.json も検証され、エントリの version と食い違えば警告が出ます。plugin.json 側の問題は plugins[2] plugin.json → のようにエントリ番号付きで出るので、どのプラグインか特定できます。
実際に壊れた marketplace.json(同名のエントリが2つ、片方の source に .. を含む)へ実行した出力です。
✘ Found 3 errors:
❯ plugins[2].source: Path contains "..": ./plugins/../a. Plugin source paths are resolved relative to the marketplace root (the directory containing .claude-plugin/), not relative to marketplace.json. Use "./plugins/my-plugin" instead of "./plugins/../a".
❯ plugins[0].name: Duplicate plugin name "a" found in marketplace
❯ plugins[2].name: Duplicate plugin name "a" found in marketplace
✘ Validation failed終了コードは失敗で1でした。エラーが複数あっても1回の実行でまとめて出ます。v2.1.196以降は source が . のプラグインも対象に入り、エラーの種類が1つ見つかった時点で止まることもありません。
警告も終了コードに反映する
CIで警告も落とすなら --strict(v2.1.145以降)を付けます。plugin.json に author が無いだけのプラグインで試すと、既定は ✔ Validation passed with warnings で終了コード0でした。--strict を付けると ✘ Validation failed (--strict treats warnings as errors) が出て、終了コードは1です。CIで結果を機械的に読むなら --json(v2.1.259以降)を使います。出力は success / strict / target / manifest / contents を持つJSONです。
validateの終了コード
0
Validation passedまたはpassed with warnings。--strictの場合は警告も無いときだけです。1
エラーがあるとき、または
--strictで警告があったとき。2
読めないパスなど、検証そのものが失敗したとき。標準出力には何も出ません。
検証対象はパスの渡し方で変わる
claude plugin validate は、渡したディレクトリの中身で検証内容を選びます。.claude-plugin/marketplace.json があればそれを、無ければ .claude-plugin/plugin.json を見ます。どちらも無ければ、スキル・エージェント・コマンドのファイルが対象です。
| 確認したいもの | 実行コマンド |
|---|---|
| マーケットプレイス全体 | 実行コマンドclaude plugin validate . |
plugin.json を持つプラグイン1つ | 実行コマンドclaude plugin validate ./plugins/my-plugin |
| スキル・エージェント・コマンドのディレクトリ単体 | 実行コマンドclaude plugin validate .claude/skills のように、skills / agents / commands の名前のディレクトリを指定 |
| プロジェクトの3ディレクトリをまとめて | 実行コマンドclaude plugin validate .claude |
| ユーザーレベルの設定 | 実行コマンドclaude plugin validate ~/.claude |
マニフェストを使わずスキルなどのファイルだけを見る実行は、v2.1.233以降が必要です。1行目と2行目は、それより古いバージョンでも動きます。
マーケットプレイスのディレクトリを対象にした実行では、各プラグインのスキル・エージェント・コマンド・フックのファイルや、同梱するMCPサーバーのファイルは開きません。それらの誤りは、プラグインのディレクトリを指定して実行し直したときに見つかります。プラグインルート直下の SKILL.md はプラグイン実行でも検査されず、同じ場所の CLAUDE.md には警告が出ます。
空のディレクトリを渡すと、終了コード1になりました。エラーは次のとおりです。
directory: No manifest found in directory. Expected .claude-plugin/marketplace.json or .claude-plugin/plugin.jsonよく出るエラーと対処
重複した名前と .. を含む source は、上の出力例のとおりです。そのほか、対処に迷いやすいものを挙げます。
| エラー | 原因 | 対処 |
|---|---|---|
Plugin name cannot contain spaces. Use kebab-case | 原因プラグイン名に空白がある | 対処ハイフン区切りの名前にする |
Marketplace name cannot contain control or bidirectional-formatting characters | 原因名前に制御文字や文字の表示順を操作するUnicode文字が混ざっている | 対処該当文字を取り除く |
プラグインのディレクトリを指定した実行では、YAML frontmatter failed to parse: ... が出ることがあります。SKILL.md などのfrontmatterが壊れているときです。hooks/hooks.json が壊れていれば Invalid JSON syntax: ... が出ます。どちらも対象ファイルの修正で消えます。
名前の警告はClaude Desktopに響く
非致命的な警告には、説明文が無い、プラグインが1つも無い、名前がkebab-caseでない、といったものがあります。この中で名前の警告は無視しないほうが安全です。org / org-provisioned / unknown はClaude Desktopの予約語で、マーケットプレイスの同期ごと拒否されます。Claude Desktopが受け付ける名前は128文字までの英数字と . _ - で、先頭は英数字です。
マーケットプレイス名を org、プラグイン名を My Plugin にして試しました。出力のうち警告部分を抜粋すると、次の2件が出ました。
⚠ Found 2 warnings:
❯ name: Marketplace name "org" is reserved in Claude Desktop. Claude Code accepts it, but the Claude Desktop managed marketplace sync (allowedPluginMarketplaces) will reject the whole marketplace.
❯ plugins[0].name: Plugin name "My Plugin" is not accepted by Claude Desktop (letters, digits, ".", "_", "-"; must start alphanumeric; max 128 chars). The Claude Desktop managed marketplace sync (allowedPluginMarketplaces) will drop this entry.この実行では、空白入りのプラグイン名がエラーとしても出ています。ここでは警告部分だけを載せました。org のほうはエラーにならず、警告のまま通ります。v2.1.283以降は、インストールできない名前が marketplace.json にあると警告でなくエラーで落ちます。Claude Codeでは使える名前でも、Desktopで配るなら警告の段階で直す必要があります。これらのDesktop向け警告はv2.1.221以降の claude plugin validate で出ます。それより古いCLIで検証しても出ないので、Desktop向けに配る場合は検証に使うバージョンも揃えます。
symlinkを使っている場合
検証はディレクトリ内のsymlinkをたどりません。症状は場所で変わります。
skills/agents/commandsディレクトリ自体がリンクなら、「何も読んでいない」という警告になる- ディレクトリ内の1エントリだけがリンクなら、そのエントリだけがスキップされ、ディレクトリごとにスキップ数が警告で出る
- 指定した
skillsなどのディレクトリや、その親の.claudeがリンクなら、エラーになって中身は一切チェックされない
複数のプラグインが同じ skills/ をリンクで共有している場合は、リンク先の実ディレクトリを直接指定して再実行すると、中身も検証できます。
公開前の作業順
公開前に通す5ステップ
- 1
strictを決める
自分の
plugin.jsonでコンポーネントを管理するプラグインは、既定のtrueのままにします。plugin.jsonだけを唯一の定義にしたいときと、headersHelperを使うarchive形式のエントリはfalseにします。 - 2
marketplace.jsonを書く
エントリごとに一意の
name、..を含まないsourceを書きます。 - 3
マーケットプレイスをvalidateする
claude plugin validate .で、スキーマ・名前の重複・パストラバーサルを潰します。CIに置くなら--strictを付けるか判断します。 - 4
プラグインごとにvalidateする
スキルやエージェントの中身は、各プラグインのディレクトリを指定して検証します。
- 5
ローカルで追加してインストールする
/plugin marketplace add ./path/to/marketplaceで追加し、テスト用プラグインを実際にインストールします。claude plugin listで全プラグインがenabledかを確認します。
マーケットプレイスの作り方全体はClaude Codeプラグイン完全ガイドにあります。コンテナへの事前展開はプラグインをコンテナへ事前展開する手順です。
よくある質問
strict: falseにしたらplugin.jsonは消すべきですか
plugin.json を消す必要はありません。エントリにコンポーネントを書かないなら、strict: false でも plugin.json がマニフェストとして使われます。エントリ側でコンポーネントを持ちたいときは、strict: true に戻して追記方式にするか、plugin.json を置かずエントリをマニフェストにします。strict: false のまま plugin.json を残すと、エントリのコンポーネントは競合になります。
まとめ
エントリにコンポーネントを書く運用なら strict は true のままにします。plugin.json を唯一の正にしたいときだけ false にし、その場合はCIの validate に加えて、インストール後の claude plugin list を工程に入れます。