【Claude Code 連載 第59回】組織向けプラグインの推奨 — 作業内容に応じて提案する

スポンサーリンク
【Claude Code 連載 第59回】組織向けプラグインの推奨 — 作業内容に応じて提案する 用語解説
【Claude Code 連載 第59回】組織向けプラグインの推奨 — 作業内容に応じて提案する
この記事は約13分で読めます。
よっしー
よっしー

こんにちは。よっしーです(^^)

スポンサーリンク

背景

この連載では、Claude Codeの公式ドキュメントを1ページずつ読み解いていきます。公式ドキュメントは情報が網羅されている分、「結局どの機能を、どんな場面で使えばいいのか」は自分で考える必要があり、読むのに意外と時間がかかります。そこで、私が実務で使うために読み込んだ内容を「使う場面→実例コード」の順に整理して残していくことにしました。専門家の解説というより、一次情報を読んだ記録です。推測や動作を確認していない部分には、その都度そう書きます。

1. 一言でいうと何か

relevance は、**「ユーザーが今やっていることに合致したら、このプラグインを提案する」**というルールを、マーケットプレイスのプラグインエントリに書き込む仕組みです。

第56回で marketplace.json のフィールドとして名前だけ挙げ、第57回では受け取る側の「suggested for this directory」ラベルとして触れました。今回はその中身です。

必要な手順は2つで、両方揃わないと動きません

  1. marketplace.json のプラグインエントリに relevance ブロックを追加する
  2. 管理設定でそのマーケットプレイスをホワイトリスト登録する

**マーケットプレイス側が宣言しただけでは提案は生成されません。**管理者が許可リストに入れるまで無効で、**これは公式 Anthropic マーケットプレイスも例外ではありません。**組織の管理下にない誰かが、勝手に全社へプラグインを推してくることがない設計です。

**シグナルのマッチングはユーザーのマシン上でローカルに行われます。ネットワークトラフィックは増えず、どのシグナルが一致したかもその値も、Anthropic にもマーケットプレイス運営者にも報告されません。**推薦機能でありながら、送信されるデータは何もない。

そして当然ながら、Claude Code はプラグインを自動インストールしません。常にユーザーが確認します。

v2.1.152 以降が必要で、古いクライアントは relevance フィールドを無視します。

2. どういう場面で役立つか

シーン1:社内規約プラグインを、必要な人にだけ届ける

Terraform を触っている人に Terraform 用プラグインを、Stripe を使っているリポジトリで Stripe 用プラグインを提案する。全社員に「これ入れてください」と一斉通知する代わりに、その作業をしている瞬間に出す——これが本来の用途です。

シーン2:新しく入った人が社内ツールを見つけられるようにする

インフラのディレクトリで作業を始めた瞬間にセッション開始通知が出るので、「そんなプラグインがあったのか」を知る機会が自然に生まれます。

シーン3:/plugin の Discover タブを文脈に合わせる

シグナルが一致したプラグインはDiscover リストの上部に固定され、「このディレクトリで推奨」「terraform コマンドで推奨」といった注釈付きで表示されます。

不要・向かないケース

  • 管理設定を配布できない環境ホワイトリスト登録が必須なので、管理設定を配れないなら提案は一切出ません。
  • セッション開始時に cwd 以外で提案したいセッション開始時にマッチできるのは cwd だけです。他はセッション履歴が必要なので、スピナーチップと Discover タブでしか出ません。
  • 確実に届けたい同じプラグインの提案は最大3セッションに1回セッション開始通知は2回表示されたらもう出ません。周知の手段としては弱い。
  • ユーザーがスピナーチップを切っているspinnerTipsEnabledfalse、または excludeDefault を使ったカスタム spinnerTipsOverride が設定されていると、スピナーチップとセッション開始通知の両方が無効になります(Discover タブのピンだけは独立して残ります)。
  • 複合コマンドで検出したいcd infra && terraform planterraform ではなく cd として記録されます(後述)。

3. 設定の実例

relevance ブロックを書く

marketplace.json のプラグインエントリに追加します。次は「Claude が .tf ファイルを読む」か「Claude が terraform を実行する」ときに関連ありと宣言する例です。

{
  "name": "acme-corp-plugins",
  "owner": { "name": "Acme Platform Team" },
  "plugins": [
    {
      "name": "terraform-helpers",
      "source": "./plugins/terraform-helpers",
      "description": "Acme conventions and helpers for Terraform",
      "relevance": {
        "topic": "Terraform",
        "signals": {
          "cli": ["terraform"],
          "filesRead": ["**/*.tf"]
        }
      }
    }
  ]
}

relevance を持っていてもシグナルが一致しないプラグインは、他のエントリと同じように振る舞います——Discover リストの通常の位置に出るだけで、スピナーチップには現れません。

relevance の2フィールド

フィールド説明
topicstringオプション。スピナーチップの「〜で作業していますか?」を埋める句。多くは製品名Stripe など)。プラグイン名がトピックとして自然に読めないなら design のようなドメイン名を使う。デフォルトは各ハイフンセグメントを大文字化したプラグイン名。**セッション開始通知はこの値を使わない。**最大64文字
signalsobject関連性を判定するマッチャー。提案可能にするには最低1つのシグナルが必要

5種類のシグナル

ここが本体です。それぞれに癖があります。

cwd(作業ディレクトリのグロブ)セッション開始時にマッチできる唯一のシグナルです。絶対パスとしてマッチされ、git リポジトリ内ならリポジトリルートからの相対パスとしてもマッチされます。フォワードスラッシュで正規化、大文字小文字を区別しません。そして便利な仕様——すべてのパターンがディレクトリ自体とその配下すべてにマッチするので、infrainfra/infra/** はすべて同じ動作です。最大10パターン、各256文字。

cli(実行されたコマンド名)。全プラットフォームで有効で、Windows の PowerShell や Git Bash 経由でも同じように記録されます。ここに一番の落とし穴があります。Claude Code はシェルツール呼び出しごとに1つのコマンド名しか記録しません——先頭の環境変数割り当てと sudo の後の最初のトークンです。したがって複合コマンドは先頭のコマンドしか提供せず、cd infra && terraform planterraform ではなく cd を記録します。完全一致。最大10エントリ、各64文字。

hosts(Bash コマンドに現れたホスト名)。セッション中の Bash コマンドの http:// / https:// URL から拾います。スキーム・ポート・パスを含まない裸のホスト名のみapi.stripe.com など)。完全一致・大文字小文字非依存。最大20エントリ、各128文字。

filesRead(読まれたファイルパスのグロブ)**/*.tf のように書きます。フォワードスラッシュで正規化、大文字小文字非依存。最大10パターン、各256文字。

manifestDeps(マニフェストで宣言された依存関係)最も複雑で、最も強力です。各エントリは { "file": "...", "pattern": "..." } の形で、file はマニフェストファイルのパスにマッチする正規表現、pattern はその内容にマッチする正規表現です。両方とも JavaScript の RegExp ソース文字列で最大256文字file は大文字小文字非依存、pattern は区別するという非対称があります。512KB を超えるマニフェストファイルはスキップ。最大10エントリ。

manifestDeps の書き方には明確な指示があります。file は末尾にアンカーしてください。理由はパスが通常は絶対パスとしてセッション状態に記録されるため、開始アンカー付きのパターンは決してマッチしないからです。またこのシグナルではパスが区切り文字で正規化されないので、Windows パスはバックスラッシュのままになります。

公式の例がその作法を示しています。

{
  "name": "stripe-helpers",
  "source": "./plugins/stripe-helpers",
  "relevance": {
    "topic": "Stripe",
    "signals": {
      "manifestDeps": [
        {
          "file": "[/\\\\]package\\.json$",
          "pattern": "\"stripe\"\\s*:"
        }
      ]
    }
  }
}

読み解きます。[/\\\\] はフォワードスラッシュとバックスラッシュの両方の区切り文字にマッチさせるため、\\. はドットがリテラルであることを示すため。そしてJSON では正規表現のバックスラッシュを2回書く——だから元の正規表現 [/\\]package\.json$ が JSON 上では [/\\\\]package\\.json$ になります。ここは間違えやすいので、書いたら必ず検証してください。

シグナルのマッチ可能なタイミングをもう一度整理します。cli / hosts / filesRead / manifestDeps はセッション履歴が必要なので、スピナーチップと Discover タブでのみマッチします。セッション開始時にマッチできるのは cwd だけ。

そして filesReadmanifestDeps の対象範囲が広い点は覚えておく価値があります。セッションの記録されたファイル状態をテストするので、Claude が書き込み・編集したファイルと、自動読み込みされた CLAUDE.md メモリファイルも含まれます。

なお**relevancerelevance.signals 配下の未知のフィールドは読み込み時に無視される**ので、古いクライアントでもマーケットプレイスは読み込まれ続けます。claude plugin validate を実行すれば警告として表示されます。

管理設定でホワイトリストに登録する

繰り返しますが、宣言だけでは不十分です。管理者は pluginSuggestionMarketplaces にマーケットプレイス名を追加します。

公式 Anthropic 以外のマーケットプレイスは、同じ管理設定でソースも宣言する必要があります——extraKnownMarketplaces のエントリとして、あるいは strictKnownMarketplaces のエントリとして。

{
  "extraKnownMarketplaces": {
    "acme-corp-plugins": {
      "source": {
        "source": "github",
        "repo": "acme-corp/claude-plugins"
      }
    }
  },
  "pluginSuggestionMarketplaces": ["acme-corp-plugins"]
}

なぜソース宣言まで要るのかが明記されています。**ホワイトリスト登録された名前は、マーケットプレイスが別のソースから登録されていた場合は無視されます。**これにより、無関係なソースが、ホワイトリスト登録済みの名前で登録して組織全体にプラグインを提案するのを防ぐ——名前だけの許可では、名前の乗っ取りが成立してしまうからです。

公式マーケットプレイスはこの要件から除外されます。その名前は公式 Anthropic ソースからしか登録できないため、名前だけで十分です。

{
  "pluginSuggestionMarketplaces": ["claude-plugins-official"]
}

ユーザーに何が見えるか

3か所に出ます。

スピナーチップ——Claude が応答している間、スピナーの下に表示されます。

Working with Terraform? Install the terraform-helpers plugin:
/plugin install terraform-helpers@acme-corp-plugins

セッション開始通知——cwd シグナルが作業ディレクトリと一致した場合、最初のターンの前に1行出ます(v2.1.153 以降)。

plugin suggestion: terraform-helpers@acme-corp-plugins · /plugin

/plugin Discover タブのピン——「このディレクトリで推奨」「terraform コマンドで推奨」のように一致したシグナルを示す注釈付きで、リスト上部に固定されます(v2.1.154 以降)。

表示頻度の制限が細かく決まっています。特定のプラグインの提案は、スピナーチップとセッション開始通知を合わせて最大3セッションに1回。そしてセッション開始通知は2回表示されたら以後表示されません。さらにプラグインがインストールされれば、どちらも繰り返されません。Discover タブのピンも特定のプラグインを1回だけ固定し、それ以降は通常の順序に戻ります。

うるさくならないよう相当抑制されている、と言えます。裏を返せば確実な周知手段としては使えないということでもあります。

バージョンによる差も整理しておきます。v2.1.152 ではスピナーチップのみ、v2.1.153 でセッション開始通知が追加、v2.1.154 で Discover タブのピンが追加。

無効化の条件は前述のとおりで、spinnerTipsEnabled: false またはカスタム spinnerTipsOverrideexcludeDefault で、スピナーチップとセッション開始通知が両方止まります。Discover タブのピンはチップ設定とは無関係です。

なお公式ドキュメントには、Claude Code にはこのホワイトリストとは無関係の組み込み提案が1つあるという記述もあります。それも spinnerTipsEnabled: false で無効になります。

公開前に検証する

claude plugin validate ./my-marketplace

このバリデータが relevance について見るのは3点です。relevancerelevance.signals 配下の未知のキーを警告として報告relevance の値がオブジェクトでないことをフラグ、そしてスキーム・ポート・パスを含む signals.hosts エントリを拒否

3つ目は実際に間違えやすい箇所(https://api.stripe.com と書いてしまう)なので、検証で弾いてくれるのは助かります。

4. まとめ + 次回予告

  • relevance は、セッションの状況に合致したときにプラグインを提案する仕組み。マーケットプレイス側の宣言と、管理設定でのホワイトリスト登録の両方が必要。
  • **マッチングは完全にローカル。**どのシグナルが一致したかも値も、Anthropic にもマーケットプレイス運営者にも送られない。
  • **自動インストールはしない。**必ずユーザーが確認する。
  • シグナルは5種——cwd / cli / hosts / filesRead / manifestDepsセッション開始時にマッチできるのは cwd だけ。
  • cli は1ツール呼び出しにつき1コマンド名しか記録しない。cd infra && terraform plancd になる。
  • manifestDepsfile は末尾アンカー必須(パスが絶対パスで記録されるため)。JSON ではバックスラッシュを2回書く。file は大文字小文字非依存、pattern は区別する。
  • filesRead / manifestDeps は、Claude が書き込み・編集したファイルと自動読み込みの CLAUDE.md も対象に含む。
  • ホワイトリストは名前だけでなくソースの宣言も要る(公式マーケットプレイスを除く)。名前の乗っ取りを防ぐため。
  • 表示は3か所(スピナーチップ/セッション開始通知/Discover タブのピン)で、最大3セッションに1回、セッション開始通知は2回まで
  • spinnerTipsEnabled: false で前2つが止まる。Discover タブのピンは独立。
  • 公開前に claude plugin validatehosts にスキームやパスを書くと拒否される。

第54回から続いたプラグイン系はこれで6本目。マーケットプレイス運営者向けの機能はひととおり揃いました。

次回予告(暫定)CLI からプラグインを推奨する(plugin-hints)を取り上げ、Claude Code のセッションシグナルではなく自分の CLI ツール側からユーザーにプラグインを提案する仕組みを扱う予定です。


よっしー
よっしー

何か質問や相談があれば、コメントをお願いします。また、エンジニア案件の相談にも随時対応していますので、お気軽にお問い合わせください。

それでは、また明日お会いしましょう(^^)

コメント

タイトルとURLをコピーしました