【Claude Code 連載 第60回】CLI からプラグインを推奨する — 1行のマーカーで案内を出す

スポンサーリンク
【Claude Code 連載 第60回】CLI からプラグインを推奨する — 1行のマーカーで案内を出す 用語解説
【Claude Code 連載 第60回】CLI からプラグインを推奨する — 1行のマーカーで案内を出す
この記事は約12分で読めます。
よっしー
よっしー

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

スポンサーリンク

背景

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

1. 一言でいうと何か

自分が保守している CLI や SDK に公式 Anthropic マーケットプレイスのプラグインがあるなら、その CLI 自身が「このプラグイン入れませんか」と Claude Code のユーザーに促せます

前回(第59回)はマーケットプレイス側が relevance で提案する仕組みでした。今回はCLI 側から提案する——同じ「プラグインを勧める」でも、主導権が逆です。

仕組みは驚くほど単純です。**CLI は自分が Claude Code の中で動いていることを検出したら、stderr に1行のマーカーを書く。Claude Code はそれを読み、出力から削除し、ユーザーに1回限りのインストールプロンプトを出す。**それだけ。

マーカーはこれです。

<claude-code-hint v="1" type="plugin" value="example-cli@claude-plugins-official" />

この設計の良いところが2つ明記されています。

Claude Code はヒント行をモデルに送る前に出力から削除します。したがってマーカーは会話に現れず、トークン使用量にもカウントされません。「プラグインを勧めるためにコンテキストを消費する」ことがない。

そして**このプロトコルは追加のコマンドを必要とせず、Claude Code の外でユーザーが実行する場合の CLI の出力を変えません。**環境変数でゲートするだけなので、人間が直接叩いたときには何も起きない。

もちろんClaude Code はプラグインを自動インストールしません。常にユーザーが確認します。

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

シーン1:自社 CLI と Claude Code の統合を知ってもらう

**プラグインを作って公式マーケットプレイスに載せても、存在を知られなければ使われません。**CLI を Claude Code 経由で叩いた瞬間に案内が出るなら、知る側の探索コストがゼロです。

シーン2:Claude が CLI の使い方を探っている瞬間を捉える

推奨される出力場所の筆頭が --help 出力です。理由が的確で——Claude は不慣れな CLI を探索するときにヘルプを実行することが多いから。

シーン3:Claude が困っている瞬間に助け舟を出す

不明なサブコマンドのエラーも推奨されています。Claude がインターフェースについて混乱している、まさにその瞬間に到達するからです。

シーン4:セットアップの流れに乗せる

ログイン/認証の成功時(ユーザーは既にセットアップの心構えができている)と、初回実行のウェルカムメッセージ(自然なオンボーディングの瞬間)。

不要・向かないケース

  • 公式マーケットプレイス以外にプラグインがある場合このプロトコルは claude-plugins-official にリストされたプラグインでのみ有効です。他のマーケットプレイスを指すヒントは静かに削除されます。
  • 確実に届けたい場合プラグインごとに1回、かつセッションごとに1回しか出ません。しかもユーザーが30秒以内に応答しなければ「いいえ」として却下されます。
  • hook コマンドから出したい場合hook のヒントタグは削除され、無視されます。インストールプロンプトをトリガーするのはBash と PowerShell ツールの出力だけです。
  • ログ行の途中に埋め込みたい場合。**タグは独立した行を占める必要があります。**行の途中に埋め込まれたものは無視されます(前後の空白は可)。
  • ユーザーがヒントを切っている場合。プロンプトの選択肢に「再度表示しない」があり、選ばれるとそのユーザーの将来のヒントプロンプトがすべて無効になります。

3. 実装の実例

何が起きているか(4ステップ)

まず Claude Code 側の動作です。Claude Code はBash・PowerShell ツール経由で実行するすべてのコマンド、および hook コマンドに対して CLAUDECODE 環境変数を 1 に設定します。v2.1.172 以降は同じサブプロセスで CLAUDE_CODE_CHILD_SESSION1 に設定します。

CLI がそれを見てタグを出すと、Claude Code はコマンド出力を受け取ってから4つのことをします。

  1. ヒント行をスキャンし、出力がモデルに到達する前に削除する
  2. ヒントが公式 Anthropic マーケットプレイスのプラグインを対象にしていることを確認する
  3. プラグインがまだインストールされておらず、以前にプロンプトを出していないことを確認する
  4. ヒントを出力したコマンドの名前を表示するインストールプロンプトをユーザーに見せる

どちらの環境変数でゲートするか

ここが実装上いちばん判断の要る箇所です。2つの変数は到達範囲と誤爆リスクのトレードオフになっています。

CLAUDECODEClaude Code のすべてのバージョンで設定されるので、最も多くのセッションに到達します。ただし副作用があります——Claude Code が起動する tmux セッションと stdio MCP サーバーのサブプロセスでも設定され、IDE 拡張は統合ターミナルで設定します。つまり人間のユーザーが CLI を直接実行する可能性がある。生のタグが人の目に触れうる、ということです。

CLAUDE_CODE_CHILD_SESSIONClaude Code 自身が生成するサブプロセス(ツール呼び出し、hook コマンド、status line コマンドなど)でのみ設定されるので、タグは通常、人間のターミナルには到達しません。ただし2つの弱点があります。セッション内で開始された長時間実行プロセス(tmux サーバーなど)は変数をキャプチャするので、そこから後で起動されたシェルは依然として生のタグを表示します。そしてv2.1.172 以降が必要なので、古いバージョンのセッションではヒントが出ません。

公式の例は最大限のリーチのために CLAUDECODE を選んでいます。4言語分が掲載されているので、そのまま引用します。

if (process.env.CLAUDECODE) {
  process.stderr.write(
    '<claude-code-hint v="1" type="plugin" value="example-cli@claude-plugins-official" />\n',
  )
}
import os, sys
if os.environ.get("CLAUDECODE"):
    print(
        '<claude-code-hint v="1" type="plugin" value="example-cli@claude-plugins-official" />',
        file=sys.stderr,
    )
if os.Getenv("CLAUDECODE") != "" {
    fmt.Fprintln(os.Stderr,
        `<claude-code-hint v="1" type="plugin" value="example-cli@claude-plugins-official" />`)
}
[ -n "$CLAUDECODE" ] &&
  printf '%s\n' '<claude-code-hint v="1" type="plugin" value="example-cli@claude-plugins-official" />' >&2

example-cli を自分のプラグイン名に置き換えるだけです。4言語とも実質2〜4行で、導入コストは実質ゼロと言っていい。

どこで出力するか

**Claude Code はプラグイン別に重複排除するので、すべての呼び出しで出力しても欠点はありません。**これは実装を楽にする重要な事実です——「どこか1箇所で出す」を悩まずに、複数箇所に仕込んでいい。

推奨されるタッチポイントは4つです。

配置機能する理由
--help 出力Claude は不慣れな CLI を探索するときにヘルプを実行することが多い
不明なサブコマンドエラーClaude がインターフェースについて混乱している瞬間に到達する
ログインまたは認証成功ユーザーはすでにセットアップの心構えができている
初回実行ウェルカムメッセージ自然なオンボーディングの瞬間

ユーザーに何が見えるか

すべてのチェックを通ると、こういうプロンプトが出ます。

─────────────────────────────────────────────────────────────
  プラグイン推奨
    example-cli コマンドはプラグインのインストールを提案しています。
    プラグイン: example-cli
    マーケットプレイス: claude-plugins-official
    example-cli デプロイメント向けの公式統合
    インストールしますか?
    ❯ 1. はい、example-cli をインストール
      2. いいえ
      3. いいえ、プラグインインストールヒントを再度表示しない
─────────────────────────────────────────────────────────────

**プロンプトはヒントを生成したコマンドの名前を表示します。**この設計意図が明記されていて——ユーザーがツールと推奨するプラグインの間の不一致を検出できるようにするためです。無関係な CLI が別のプラグインを推してきたら、それが見えるようになっている。

30秒以内に応答しなければ「いいえ」として却下されます。

頻度制限は2段構えです。

  • プラグインごとに1回プロンプトが表示された時点でプラグインが記録され、ユーザーの回答に関係なく二度と出ません。
  • セッションごとに1回マシン上のすべての CLI にわたって、Claude Code セッションごとに最大1つのヒントプロンプトしか表示されません。

選択肢の結果も押さえておきます。「はい」はユーザースコープにインストール「再度表示しない」はそのユーザーの将来のヒントプロンプトをすべて無効化します。

タグの形式

必須属性は3つだけです。

属性必須説明
vはいプロトコルバージョン。1 が唯一サポートされる値
typeはいヒントの種類。plugin が唯一サポートされる値
valueはいname@marketplace 形式のプラグイン識別子

属性値は二重引用符で囲んでも、引用符なしでもよい(引用符なしの値は空白を含めない)。エスケープシーケンスはサポートされません。

強制される要件と、されない推奨

Claude Code が強制する条件は2つだけで、どちらかを満たさないヒントは削除されます。

  • 独立した行を占めること。ログステートメント内など、行の途中に埋め込まれたタグは無視される。先頭と末尾の空白は許可。
  • 公式マーケットプレイスを指すことvalue が Anthropic 管理のマーケットプレイス(claude-plugins-official など)のプラグインを参照していること。他を指すヒントは静かに削除される。

そして重要な仕様——**バージョンやタイプが認識されない場合でも、ヒント行は常にモデルに到達する前に出力から削除されます。**将来プロトコルが拡張されても、古い Claude Code が未知のタグをそのままモデルに見せてしまうことはないわけです。

残りは推奨だが強制されないものです。公式が正直に「Claude Code は CLI がそれに従っているかどうかを観察できない」と書いています。

  • stderr に書く:理由が実務的で、stderr なら example-cli deploy | jq のようなシェルパイプラインからタグが除外されるから。Claude Code は両方のストリームをスキャンするので stdout でも機能しますが、パイプで壊さないために stderr が勧められています。
  • 環境変数でゲートするCLAUDECODECLAUDE_CODE_CHILD_SESSION が設定されているときだけ出力する。

公式マーケットプレイスに載せるには

ここが最大のハードルです。このプロトコルは claude-plugins-official にリストされたプラグインでのみ有効で、Anthropic はそのマーケットプレイスを裁量で管理しています。

そして**アプリ内の送信フォームはプラグインをコミュニティマーケットプレイスに追加するもので、ヒントプロトコルはそちらをチェックしません。**第54回・第56回でも出てきた話ですが、ここでも同じ壁があります。

現実的な道は1つだけ明示されています——Anthropic のパートナー連絡先と協力しているなら、公式マーケットプレイスのリスト調整を相談する。

4. まとめ + 次回予告

  • CLI が stderr に1行のマーカーを書くだけで、Claude Code がユーザーにプラグインのインストールを促す。
  • **マーカーはモデルに届く前に削除される。**会話に現れず、トークンも消費しない。
  • **Claude Code の外では何も起きない。**環境変数でゲートするだけなので、既存の出力を変えない。
  • ゲート変数は2択。CLAUDECODE は到達範囲が最大だが、tmux・MCP サブプロセス・IDE 統合ターミナルでも設定されるので人間の目に触れうる。CLAUDE_CODE_CHILD_SESSION は人目に触れにくいが v2.1.172 以降が必要で、長時間実行プロセス経由の漏れは残る。
  • **プラグイン別に重複排除されるので、複数箇所で出してよい。**推奨は --help / 不明サブコマンドのエラー / 認証成功 / 初回実行。
  • 強制される条件は**「独立した行」と「公式マーケットプレイス」の2つだけ**。未知のバージョンやタイプでも行は必ず削除される。
  • stderr 推奨の理由はパイプライン汚染の回避(stdout でも動く)。
  • 頻度はプラグインごとに1回、セッションごとに1回30秒無応答は「いいえ」。「再度表示しない」で全ヒントが無効化。
  • プロンプトはヒントを出したコマンド名を表示する——不一致をユーザーが検出できるように。
  • 公式マーケットプレイスへの掲載が前提で、そこは Anthropic の裁量。コミュニティマーケットプレイスは対象外。

第59回と第60回は「プラグインを提案する」の両側でした。**マーケットプレイス側が状況を見て提案するのが relevance、CLI 側が自分で名乗り出るのが plugin-hints。**どちらも管理者やユーザーの同意なしには成立しない設計になっています。

第54回から7本続いたプラグイン系は、これでひと区切りです。

次回予告(暫定):**プラグインの作成(plugins)**を取り上げ、skills・agents・hooks を使った実際のプラグイン構築のチュートリアルを扱う予定です。


よっしー
よっしー

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

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

コメント

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