Claude Codeのプラグインを自作していて、セッション中ずっと何かを見張らせたい人向け
公開作業の進み具合やエラーのログを、毎回「見張ってて」と頼まずにClaudeへ自動で気づかせたいとき。自作プラグインの monitors.json か plugin.json の experimental.monitors に monitor を数行宣言しておくと、セッション開始時またはプラグイン読み直し時に見張りが立ち上がる
Claude Codeにずっと裏で何かを見張らせたいとき、たとえば公開作業の進み具合とエラーのログを横で監視させ続けたいとき、毎回「これを見張ってて」と頼むのは面倒です。Plugin monitors は、自作プラグインの設定に数行書いておくと、Claude Codeがセッションの間ずっと裏で1つのコマンドを動かし続け、その出力をClaudeへの通知として届けてくれる仕組みです。
頼まれなくても、Claudeはログの一行ごとに気づいて反応できる。そこが普通のコマンド実行と違う点です。
そもそも monitor って何を指してるのか
プラグインには skill や hook など色々な部品を持たせられますが、monitor もその部品の1つです。役割は「見張り役」。あなたが指定したコマンドを、Claude Codeがセッション開始と同時に起動して、終わるまで止めずに動かし続けます。
公式の定義はこうです。「プラグインは、有効なときにClaude Codeが自動で起動する裏方の monitor を宣言できる。各 monitor はセッションが続く間ずっと1つのコマンドを動かし、出力の一行ごとを通知としてClaudeに届ける。だからClaudeは、見張りを自分で始めろと頼まれなくても、ログやステータス変化に反応できる」。
イメージとしては、新しい職場の初日に「あの掲示板に張り紙が出たら教えてね」と頼んでおくのに近いです。一度頼めば、こちらが何も言わなくても更新があるたびに知らせてくれる。monitor はその張り紙係を、プラグイン側にあらかじめ仕込んでおく仕組みです。
大事な前提:これは対話セッションでしか動かないし、無防備に走る
monitor を仕込む前に、3つの条件を頭に入れておかないと「書いたのに動かない」で詰まります。公式が制約をはっきり書いています。
「Plugin monitors は Monitor ツールと同じ仕組みを使い、その利用条件を共有する。対話的なCLIセッションでだけ動き、hook と同じ信頼レベルで防御なしに動き、Monitor ツールが使えない環境ではスキップされる」。
つまり、自動実行のような無人の流れでは動かない。そして防御の囲いなしで動くので、ここに書くコマンドは「自分が信頼している中身だけ」にする必要があります。よそから拾ってきた怪しい一行をそのまま見張り役にするのは危険。
もう1つ、使えるのは Claude Code v2.1.105 以降です。それより古いと、書いても無視されます。
「料理ブログを公開する作業」を例に、実際の手順を見る
料理ブログを書きためたので、いよいよネット上に公開する。公開の進み具合と、途中で出るエラーのログを、Claudeにずっと横で見張らせる自作プラグインを作っていきます。完成イメージは、公開ボタンを押した後に放っておいても、Claudeが「公開が止まりました」「エラーログにこんな行が出ました」と勝手に知らせてくれる状態です。
ステップ1: 見張り役を置く場所を決める
monitor の宣言は、プラグインの一番上の場所に monitors/monitors.json というファイルを作って書くか、plugin.json の中に直接書くか、どちらでもいけます。今回は専用ファイルの monitors/monitors.json でいきます。中身は monitor の一覧を並べた形です。
ステップ2: 公式の例をそのまま置いてみる
公式ドキュメントが、まさに「公開状況」と「エラーログ」を見張る例を出しています。これをそのまま monitors/monitors.json に書きます。
[
{
"name": "deploy-status",
"command": "\"${CLAUDE_PLUGIN_ROOT}\"/scripts/poll-deploy.sh ${user_config.api_endpoint}",
"description": "Deployment status changes"
},
{
"name": "error-log",
"command": "tail -F ./logs/error.log",
"description": "Application error log",
"when": "on-skill-invoke:debug"
}
]
上が公開状況の見張り、下がエラーログの見張りです。2つ並べて宣言できるのが分かります。
ステップ3: name で見張り役に名札を付ける
1つ目の name は deploy-status、2つ目は error-log。この名札はプラグインの中で他とかぶらない一意の名前にします。なぜ一意が大事かというと、プラグインを再読み込みしたりスキルがもう一度呼ばれたりしたとき、同じ見張り役が二重に立ち上がるのを防ぐ目印になるからです。ここで初心者がやりがちな勘違いがあります。name はただの飾りラベルだと思って適当に同じ名前を付けると、見張りプロセスが二重に走って、通知が二重に飛んでくる。名札は管理の鍵です。
ステップ4: command に実際に動かす一行を書く
1つ目の command は、プラグインに同梱した poll-deploy.sh という小さなプログラムを動かして、公開状況を取りに行かせています。先頭の "${CLAUDE_PLUGIN_ROOT}" は「このプラグインが入っている場所」を指す変数です。これを付けることで、プラグインがどこに置かれても自分の中のプログラムを正しく呼べます。
2つ目の command は tail -F ./logs/error.log。エラーログのファイルを開きっぱなしにして、新しい行が書き込まれるたびに流し見する定番の一行です。
ちなみに、もしプログラムをプラグイン自身の場所で動かしたいなら、コマンドの先頭に cd "${CLAUDE_PLUGIN_ROOT}" && を付けます。
ステップ5: description で「何を見張っているか」を伝える
description はそれぞれ「Deployment status changes」「Application error log」。これは何を見張っているかの短い説明で、作業中のタスク一覧と、通知のまとめに表示されます。ここを丁寧に書いておくと、通知が来たときに「ああ、公開状況の方か」とすぐ判断できます。
ステップ6: when でいつ動き出すかを決める
1つ目には when がありません。書かないと既定の "always" 扱いになり、セッション開始時とプラグイン再読み込み時に起動します。公開状況はずっと見ていたいので、これで正解です。
2つ目には "when": "on-skill-invoke:debug" が付いています。これは debug という名前のスキルがこのプラグインで初めて呼ばれたときに、はじめて起動するという指定です。エラーログは「不具合を追い始めたとき」だけ見ればいいので、常時ではなく必要になった瞬間に立ち上がるようにしている。よくできた使い分けです。
つまり Plugin monitors は何をしてくれるのか
- やってくれる: セッション中、指定した1つのコマンドを裏で動かし続け、その出力の一行ごとをClaudeへの通知に変える。Claudeは頼まれなくてもログやステータス変化に反応できる
- やってくれない: セッションをまたいだ常駐や、無人の自動実行での見張りはしない。動くのは対話セッションの間だけ
- 意味が薄い場面: Monitor ツールが使えない環境。ここでは monitor 自体がスキップされるので、書いても起動しない
宣言の書き場所は「今まさに移行中」だと知っておく
ここは断定の罠があるので丁寧に書きます。monitor は実験的な部品で、まだ仕様が変わりうる扱いです。書き場所も移行の途中にあります。
整理すると、当初(v2.1.105)は plugin.json の一番外側に monitors を直接書けました。今は experimental の下、つまり experimental.monitors に書くのが推奨です。専用ファイルを別の場所から読ませたいときは、experimental.monitors に "./config/monitors.json" のような相対の場所文字列を入れます。
公式はこう書いています。「一番外側の宣言も今はまだ動くが、claude plugin validate が警告を出す。そして将来のリリースでは experimental.* の下が必須になる」。だから「一番外側に書くのが唯一の正解」と覚えてしまうと、いずれ動かなくなります。新しく作るなら最初から experimental.monitors に置くのが安全寄りです。
使いどころ3シナリオ(具体題材で再現)
シナリオ1: 料理ブログを公開し終わるまで放置で見張りたいとき
記事30本を一気にネット公開する。完了まで数分かかるので、その間に画像の最適化など別作業を進めたい。deploy-status を "always" で仕込んでおけば、公開が止まった瞬間にClaudeが気づいて「ここで止まっています」と知らせてくれる。私ならまずこのパターンから入ります。手を離していても見張りが効くのが、わざわざ monitor を使う一番の理由です。
シナリオ2: 家計簿アプリのエラーログを不具合調査のときだけ追いたいとき
普段はログを見たくないけれど、バグを追い始めたときだけ error.log を流し見したい。error-log に "when": "on-skill-invoke:debug" を付けておくと、調査用のスキルを呼んだ瞬間に見張りが立ち上がる。常時動かさないので通知に埋もれず、必要な瞬間だけ集中して見られます。
シナリオ3: 外部サービスの状態を一定間隔で取りに行かせたいとき
たとえば公開先のサービスが落ちていないかを定期的に確認したい。command に「一定間隔で状態を取りに行く小さなプログラム」を置いておけば、変化があるたびにClaudeへ通知が飛ぶ。${user_config.api_endpoint} のように、利用者ごとに違う宛先を差し込めるので、配るプラグインにしても各自の環境で動きます。ここは地味だけど効きます。
初心者が踏みやすい落とし穴
- 一番外側の monitors キーが今も唯一の正解だと思い込む。今は
experimental.monitorsが推奨で、一番外側はまだ動くもののclaude plugin validateが警告を出します。将来はexperimental.*が必須化予定。 - プラグインを無効にすれば見張りも即止まると思い込む。「セッション途中でプラグインを無効化しても、すでに動いている monitor は止まらない。止まるのはセッション終了時」と公式が明記しています。
/reload-pluginsで monitor も新しい版に切り替わると思い込む。プラグインがセッション途中で更新されても、monitor は前の版の場所を使い続けます。/reload-pluginsは hook・MCP・LSP を新しい場所に切り替えますが、monitor だけはセッションのやり直しが必要です。- どんな環境でも動くと思い込む。動くのは対話的なCLIセッション限定。Monitor ツールが使えない環境ではスキップされます。
- 防御なしで動くことを忘れる。monitor は hook と同じ信頼レベルで、囲いなしに動きます。だから
commandには自分が信頼できる中身だけを書く。 - name を適当にかぶせる。name はプラグイン内で一意の識別子で、見張りプロセスの二重起動を防ぐ目印です。同じ名前を使うと二重に走ります。
- when を書けば必ず止め時を指定できると勘違いする。
whenは「いつ始めるか」だけを決める指定で、止め方ではありません。書かなければ既定の"always"で動き出します。 - Monitor ツールで毎回頼めばいいのでは、と思い込む。Monitor ツールはその場で「このコマンドをずっと見張って」とClaudeに頼む操作で、セッションのたびに頼み直す必要があります。plugin monitors はプラグイン側に仕込んでおく仕掛けで、セッション開始と同時に自動で立ち上がります。毎回頼まず自動で走らせたいなら plugin monitors、今この場で1つだけ見張らせたいなら Monitor ツールで足ります。
experimental.monitorsに置き場所を書けばmonitors/フォルダも一緒に読まれると思い込む。この指定は既定のmonitors/フォルダを上書きします(読まれなくなる)。両方使いたいなら配列で並べて明示します(例:["./monitors/", "./extra/monitors.json"])。
書き方
monitors/monitors.json に monitor の一覧を書く(または plugin.json の experimental.monitors に同じ一覧を入れる)。各 monitor は name / command / description が必須、when は任意。when は "always"(既定:セッション開始時とプラグイン読み直し時に起動)か "on-skill-invoke:<スキル名>"(指定したスキルが初めて呼ばれたときに起動)の2値
やってみるとこうなる
入力
[
{
"name": "deploy-status",
"command": "\"${CLAUDE_PLUGIN_ROOT}\"/scripts/poll-deploy.sh ${user_config.api_endpoint}",
"description": "Deployment status changes"
},
{
"name": "error-log",
"command": "tail -F ./logs/error.log",
"description": "Application error log",
"when": "on-skill-invoke:debug"
}
]
出力例
セッション開始時に deploy-status が起動して公開状況を見張り始める。error-log は debug スキルが初めて呼ばれたときに起動する。各見張りの出力は一行ごとにClaudeへの通知として届き、作業中のタスク一覧と通知のまとめには description(「Deployment status changes」など)が表示される
このページに出てきた言葉
- monitor(モニター)
- プラグインに仕込む見張り役。指定したコマンドを裏でずっと動かし、出力をClaudeに届ける部品
- セッション
- Claude Codeを起動してから終了するまでの1回の作業のかたまり。monitor が動くのはこの間だけ
- plugin.json
- プラグインの名前や持っている部品を書く設定ファイル。monitor の宣言もここか専用ファイルに書く
- experimental.monitors
- 今 monitor を宣言する推奨の置き場所。<code>experimental</code>=まだ仕様が変わりうる実験的な部品という印
- ${CLAUDE_PLUGIN_ROOT}
- このプラグインが入っている場所を指す変数。command の中に書くと、置き場所が変わっても自分のプログラムを呼べる
- stdout
- コマンドが画面に吐き出す出力。monitor はこの一行ごとをClaudeへの通知に変える
- /reload-plugins
- プラグインを読み直すコマンド。hook・MCP・LSPは新しい版に切り替わるが、monitor はセッションのやり直しが必要