monitors.jsonでプラグインにバックグラウンド監視を組み込む
プラグインのmonitors.jsonでログ監視やステータス監視を自動起動する設定方法と、whenトリガー・変数展開・Monitorツールとの違いを解説します。
monitors.jsonでできること
プラグインのmonitors/monitors.jsonに監視対象を書いておくと、そのプラグインが有効な間、Claude Codeが自動でバックグラウンド監視を起動します。ユーザーが毎回「このログを見ていて」と頼む必要がありません。
対象はログファイルの追跡、外部APIのステータスポーリング、ファイル変更の監視など、標準出力に1行ずつ書き出せるものなら何でも使えます。監視コマンドが出力した各行はセッション中の通知としてClaudeに届き、エラーや状態変化にその場で反応できます。
社内向けの開発支援プラグインを配るときによく出てくるのが、「導入したメンバー全員に同じ監視をお願いしたいが、頼み忘れる人が必ず出る」という悩みです。monitorsはこの頼み忘れそのものをなくす仕組みで、インストールした時点で全員に同じ監視が行き渡ります。
最小構成の書き方
プラグインルートにmonitors/monitors.jsonを置き、監視対象を配列で並べます。
[
{
"name": "error-log",
"command": "tail -F ./logs/error.log",
"description": "Application error log"
}
]必須フィールドは3つだけです。
| フィールド | 役割 |
|---|---|
name | 役割プラグイン内で一意な識別子。リロードやスキル再実行のたびに同じプロセスを重複起動しない |
command | 役割セッションの作業ディレクトリで常駐実行するシェルコマンド |
description | 役割何を監視しているかの短い説明。タスクパネルと通知の要約に表示される |
plugin.jsonのexperimental.monitorsにこの配列をそのまま書けばインラインでも指定できます。既定のパス以外を使いたい場合は、experimental.monitorsに"./config/monitors.json"のような相対パス文字列を渡します。monitorsは仕様が固まりきっていない実験的コンポーネントなので、将来のリリースでスキーマが変わる可能性がある点は前提にしておく必要があります。
起動タイミングをwhenで絞る
すべての監視を常時起動する必要はありません。whenフィールドで起動条件を選べます。
| 値 | 挙動 |
|---|---|
"always"(既定) | 挙動セッション開始時とプラグインのリロード時に起動する |
"on-skill-invoke:<skill-name>" | 挙動同じプラグイン内の指定スキルが最初に呼ばれたタイミングで起動する |
デバッグ用の監視だけ、そのスキルを使うときにしか起動させたくない場合はon-skill-invokeが向いています。常時起動と条件起動を1つのファイル内で混在させることもできます。
[
{
"name": "deploy-status",
"command": "\"${CLAUDE_PLUGIN_ROOT}\"/scripts/poll-deploy.sh",
"description": "Deployment status changes"
},
{
"name": "error-log",
"command": "tail -F ./logs/error.log",
"description": "Application error log",
"when": "on-skill-invoke:debug"
}
]上の例では2つの監視を組み合わせています。deploy-statusは${CLAUDE_PLUGIN_ROOT}配下に置いたスクリプトを常時実行し、デプロイの状態変化をセッション開始からずっと拾い続けます。一方のerror-logは相対パスの./logs/error.logを対象にし、whenでdebugスキルを最初に呼んだときだけ起動します。常に見ておきたい監視と、必要になったときだけ動かしたい監視を、同じファイル内で使い分けられることがこの例から読み取れます。
commandで使えるパス変数
commandの値には${CLAUDE_PLUGIN_ROOT}(プラグイン自身のディレクトリ)、${CLAUDE_PLUGIN_DATA}(永続データ領域)、${CLAUDE_PROJECT_DIR}に加えて、環境変数由来の${ENV_VAR}も展開できます。スクリプトをプラグイン自身のディレクトリから実行したい場合は、コマンドの先頭にcd "${CLAUDE_PLUGIN_ROOT}" && を付けます。
user_configを参照できない制約
monitorsのcommandは${user_config.*}の値を参照できません。コマンドはシェル経由で実行されるため、設定値をそのまま埋め込むとシェルに任意の文字列を実行させる経路になってしまうからです。参照しようとするとClaude Codeはエラーを返し、監視自体を起動しません。APIトークンのような設定値を監視スクリプトに渡したい場合は、そのスクリプト側で自分が持つ設定ファイルを読ませる必要があります。monitorプロセスにはCLAUDE_PLUGIN_OPTION_<KEY>環境変数も渡らないため、hookやMCPサーバー設定と同じ感覚で書くと動きません。
手動のMonitorツールとの違い
Claude Codeにはユーザーが対話中に「このログを見ていて」と頼んで使うMonitorツールもあります。プラグインのmonitorsは同じ仕組みを使い、可用性の制約も共有しますが、起動の主導権が違います。
| 観点 | Monitorツール(対話依頼) | プラグインのmonitors |
|---|---|---|
| 起動方法 | Monitorツール(対話依頼)ユーザーやClaudeがセッション中に依頼 | プラグインのmonitorsプラグイン有効化時に自動起動 |
| 対象 | Monitorツール(対話依頼)その場で決めた任意のコマンド・WebSocket | プラグインのmonitorsあらかじめmonitors.jsonに定義した固定コマンド |
| 停止方法 | Monitorツール(対話依頼)Claudeに依頼するかセッション終了 | プラグインのmonitorsセッション終了時(手動キャンセルは不要) |
| 向く場面 | Monitorツール(対話依頼)一時的な調査・その場での監視 | プラグインのmonitorsプラグイン導入者全員に同じ監視を配りたいとき |
動作条件と権限
プラグインのmonitorsはMonitorツールと同じ制約を継承します。対話的なCLIセッションでのみ動作し、hooksと同じ信頼レベルでサンドボックスなしに実行されます。Monitorツール自体が使えないホストでは、monitorsもスキップされます。
command実行時の権限判定はBashと同じ仕組みを使うため、Bashに設定したallow/denyルールがmonitorsの起動コマンドにもそのまま適用されます。
具体的には、Amazon Bedrock・Google Cloudのエージェントプラットフォーム・Microsoft Foundry経由では利用できません。DISABLE_TELEMETRYまたはCLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFICが設定されている環境でも無効になります。エンタープライズ環境でプラグインを配布する前に、対象ユーザーがどの面でClaude Codeを使っているかを確認しておくと、監視が起動しないという問い合わせを避けられます。
Linux・WSL環境でCLAUDE_CODE_TOOL_MEMORY_LIMITによるメモリ上限を設定している場合、monitorsの起動コマンドもBash・PowerShellの使用量と合算した1つの上限の対象になります。個々のmonitorごとに上限が分かれるわけではないため、複数のmonitorを常駐させるプラグインを配る場合は、想定される合計メモリ量を見積もっておく必要があります。この合算ルール自体はv2.1.233以降の機能で、Monitorツールのコマンドが上限の対象に含まれるようになったのはv2.1.246からです。それより前のバージョンでは、Monitorツールのコマンドだけ上限の外で動いていました。
monitors機構が育ってきた流れ
プラグイン向けのmonitors機構はv2.1.105で導入されて以降、周辺の仕様が段階的に整備されてきました。Monitorツール自体がWebSocketソースに対応したのはv2.1.195で、サーバー側がすでにイベントをpushしている場合はポーリングスクリプトを書かずに直接接続できます(WebSocketソースの仕様と権限・メモリー上限の扱いはClaude Code Monitorツールの使い方で扱っています)。ただしこのWebSocket入力は対話的なMonitorツールだけの機能で、プラグインのmonitors.jsonが使うcommand形式では選べません。監視対象がWebSocket配信のサービスでも、プラグイン側では自前でクライアントスクリプトを書いて標準出力に流す形にする必要があります。
プラグイン無効化・更新時の挙動
セッションの途中でプラグインを無効化しても、すでに起動しているmonitorプロセスはその場では止まりません。プロセスが止まるのはセッションが終了するタイミングです。無効化した直後に監視が止まって見えなくても、想定どおりの動作です。
プラグインをセッション中に新しいバージョンへ更新した場合も注意が必要です。hooksやMCPサーバー、LSPサーバーは/reload-pluginsを実行すれば新しいバージョンのパスに切り替わりますが、monitorsだけはセッションの再起動が必要です。--plugin-dirでmonitors.jsonを編集しながら開発しているときも同様で、「編集して/reload-plugins」ではなく、セッションを再起動して確認する流れになります。
よくあるつまずき
CLAUDE_PLUGIN_ROOTをダブルクォートで囲み忘れる: パスにスペースを含む環境で展開が壊れる。公式サンプルどおり"${CLAUDE_PLUGIN_ROOT}"とクォートで囲む${user_config.*}をcommandに書いてしまう: エラーで監視が起動しない。設定ファイル経由で値を渡す設計に変えるnameを使い回す: プラグインのリロードやスキルの再実行のたびに同じ監視が重複起動しないための識別子なので、プラグイン内で一意にする- 常時監視が必要ないのに
whenを省略する: 既定は"always"。デバッグ用の監視まで毎セッション起動させると、不要な常駐プロセスが増える descriptionを後回しにして空欄気味に書く: タスクパネルと通知の要約に使われる必須フィールドなので、何を監視しているか一目で分かる文言にしておくと、複数のmonitorが並んだときに見分けやすい
使い分け早見表
| 用途 | おすすめ | 理由 |
|---|---|---|
| チーム全員に同じログ監視を配りたい | おすすめプラグインのmonitors | 理由インストールした時点で自動起動し、頼み忘れが起きない |
| その場限りの一時的な調査 | おすすめMonitorツールへの対話依頼 | 理由定義ファイルを用意する手間がなく、すぐ試せる |
| デバッグ用のスキルを使うときだけ監視したい | おすすめwhen: "on-skill-invoke:<skill>" | 理由常時起動を避けつつ必要なときだけ動かせる |
| APIトークンなど秘密情報を渡したい | おすすめ監視スクリプト側の設定ファイル読み込み | 理由${user_config.*}はcommandに書けない |
よくある質問
monitorsはどのバージョンから使えますか
プラグイン向けの常駐monitors機構はv2.1.105で導入されました。実験的コンポーネントの扱いのため、フィールドの追加や挙動の変更は以降のリリースでも起こり得ます。
複数のmonitorを1つのプラグインに定義できますか
できます。monitors/monitors.jsonは配列なので、nameが重複しない限り何個でも並べられます。
WebSocketで届くイベントも監視できますか
monitors.jsonのcommandは標準出力を1行ずつ読む方式です。WebSocket接続はMonitorツールの機能で、ユーザーやClaudeが対話中に依頼する形でのみ使えます。
監視コマンドがエラー終了したらどうなりますか
commandはセッションの作業ディレクトリで常駐実行されるプロセスです。異常終了すればそこで出力が止まりますが、Claude Code側が自動で再起動する仕組みは用意されていません。
メモリ使用量が気になる場合はどうすればよいですか
Linux・WSL環境ならCLAUDE_CODE_TOOL_MEMORY_LIMITでBash・PowerShell・Monitor(monitorsを含む)の合計使用量に上限をかけられます。macOSやWindows(WSL以外)ではこの仕組み自体が対象外です。
まとめ
monitors/monitors.jsonは、プラグインを有効にした全員に同じバックグラウンド監視を配るための仕組みです。name・command・descriptionの3フィールドで最小構成が作れ、whenで起動タイミングを絞れます。設計段階で織り込んでおきたい制約が2つあります。対話的なCLIセッションでのみ動き、hooksと同じ信頼レベルでサンドボックスなしに実行されること、そして${user_config.*}をcommandに書けないことです。一時的な調査ならMonitorツールへの対話依頼で十分ですが、チーム全員に同じ監視を配りたいならプラグインのmonitorsが向いています。実験的コンポーネントという扱いなので、配布前には手元の--plugin-dir環境で一通り動作を確認してから公開するのが安全です。