Claude Code modsとは:導入手順と、validateだけでは見えない権限
Claude Code modsは自分の権限で動き、askルールより先にツール呼び出しを許可できます。denyが守られるのは組織のガードがある環境だけです。
目次

Claude Code modsは、Claude Codeのプロセスの中で動くJavaScript/TypeScriptの関数を収めたプラグインです。Anthropicが2026年10月1日に発表し、ターミナルのClaude Codeは2.1.287以降、Claude Desktopアプリに同梱されたClaude Codeは2.1.286以降で、最初から有効になっています。ツール呼び出しを止める・書き換える、プロンプトの上に独自の表示を出す、Claudeのターンを使わずに即実行される/コマンドを足す、といった改造ができます。ゲームのMODとは関係ありません。
入れる前に押さえておくべき点は1つです。modはあなたのユーザー権限のまま、サンドボックスの外で動きます。askルールなら確認が出るはずのツール呼び出しを先に許可でき、Read(.env)のようなdenyルールはmod自身のファイル読み取りを止めません。claude plugin validateの出力で「どの種類の操作をするか」までは分かりますが、「どのプログラムを起動し、どのファイルを読み、どこへ送るか」はソースを読むまで分かりません。
実行したこと:2026年10月6日、macOS上のClaude Code 2.1.288(Claude Desktopに同梱のCLI、未ログイン)で、ドキュメントのチュートリアルmodのvalidate・test・claude -p、空ディレクトリでの読み込み可否チェック、Anthropic公式サンプル3つのvalidateとソースの確認、マーケットプレイス追加からインストール・無効化・アンインストールまでを実行しました。インストール系は普段の~/.claudeとは別の設定ディレクトリで行っています。以下に載せる出力はこのときのものです。
実行していないこと:対話セッションは開いていません。そのため、ペインやバンドの描画、ホットリロード、/pluginに出るmods activeの行、Claudeにmodを書かせたときの承認画面は見ていません。デスクトップアプリのCodeタブ、VS Code拡張、Windows、Team/Enterpriseプランでのガードの挙動、コミュニティ製のmodも試していません。これらの部分はAnthropic公式のmodsドキュメント(日本語版「Mods の概要」)の記述にもとづきます。
modが要るのはどんなとき:settings hook・skill・MCPとの違い
modが必要になるのは、Claude Codeの画面そのものに手を入れたいときと、イベントの流れに割り込んで答えを差し替えたいときです。決まった処理でツール呼び出しを止めたり記録したりするだけなら、従来のsettings hook(settings.jsonに書くフック)で足ります。settings hookは廃止されておらず、modと並んで動きます。
用語が紛らわしいので先に整理します。公式ドキュメントは、settings.jsonに書くシェルコマンド型のフックを「settings hook」、modの中の関数を「hook」と呼び分けています。以下もこの呼び方に合わせます。
| mod | settings hook | skill | MCPサーバー | |
|---|---|---|---|---|
| 正体 | プラグイン内の関数。Claude Code自身のプロセスで呼ばれる | ライフサイクルイベントで実行されるシェルコマンド、HTTPリクエスト、プロンプト | Claudeが読む指示を書いたSKILL.md | Claudeにツールを渡す外部プロセスやサービス |
| 変えられるもの | ツール呼び出し、プロンプト、コマンド、ターン、画面の描画 | ツール呼び出しやプロンプトを通すかどうか、引数と結果、Claudeに足す文脈 | Claudeが知っていること・やること | Claudeが使えるツール |
| 画面に描けるか | 描ける | 描けない | 描けない | 描けない |
| 書くもの | JavaScriptかTypeScript | スクリプトとsettings.jsonの設定 | Markdown | 任意の言語のサーバー |
| 選ぶ場面 | ペイン、プロンプトの上のバンド、独自コマンド、イベントの書き換えが欲しい | 手元のスクリプトでブロック・許可・記録したい | 同じ指示を何度も貼り付けている | Claudeに外部システムを触らせたい |
出典は公式ドキュメントの比較表です。1つのプラグインにmod、skill、MCPサーバーを同梱することもできます。
modにしかできないことを具体的に挙げると、次の5つです。
- トランスクリプトの横のペインや、プロンプトの上のバンドに、タブ・ボタン・テキスト欄を描く
- Claude Code自身が描く部分(ツール呼び出しの行、スピナー、Claudeが質問するダイアログ)を置き換える・装飾する
- ツール呼び出しを保留してユーザーに尋ねる、ツールを実行せずに代わりの結果を返す、1つのリクエストだけ別のモデルに送る
- Claudeが作業中でも、ターンを使わずにすぐ自分の関数を実行する
/コマンドを足す - 同じファイル内の複数のhookで変数を共有する(1つのhookで数えた値を別のhookが表示する)
逆に、画面下部に情報を出したいだけならClaude Code Statusline 設定:経路、フィールド、スクリプト、修正手順のstatuslineスクリプトで済みます。settings hook・skill・スラッシュコマンドの選び方はClaude CodeのHooks・Skills・スラッシュコマンドを使い分ける:呼び出し方と設定例にまとめてあります。
modが動く環境:2.1.287以降、VS Codeとclaude -pでは描画なし
まずバージョンを確認します。ターミナルではシェルでclaude --versionを実行し、2.1.287以降なら対応しています。デスクトップアプリはClaude Codeを内蔵しているので、Codeタブのローカルセッションで/statusと入力し、Claude Codeの行が2.1.286以降かを見ます。古い場合の更新手順はClaude Codeのインストール方法:全プラットフォーム対応セットアップガイド(2026年版)を参照してください。
アーリーアクセス期間にCLAUDE_CODE_ENABLE_FUNCTION_HOOKSを設定していた場合は消して構いません。2.1.287以降はこの変数を無視するので、0にしてもmodは止まりません。
modのhookはプラグインを読み込むすべてのセッションで動きますが、描画が見えるのは一部の画面だけです。
| Claude Codeを使う場所 | hookは動くか | modの描画は見えるか |
|---|---|---|
ターミナルのclaude(エディタ内蔵ターミナル、JetBrainsプラグインを含む) | 動く | 見える |
| デスクトップアプリのCodeタブ(WSLセッションを除く) | 動く | 見える。ただしターミナル専用の要素は除く |
| デスクトップアプリのWSLセッション | 動かない。WSLセッションではプラグイン自体が使えない | 見えない |
| VS Code拡張のチャットパネル | 動く | 見えない |
claude -pとAgent SDK | 動く | 見えない |
| claude.aiやモバイルアプリからのRemote Control | 手元のマシンのセッションで動く | 手元のターミナルに出る |
| クラウドセッション | プラグインがクラウドセッションに引き継がれれば動く | 見えない |
公式ドキュメントの表をもとにしています。VS Code拡張で「modを入れたのに何も表示されない」のは、この仕様どおりの挙動です。hookによるブロックや書き換えは効いているので、表示が出ないからといって無害とは限りません。
mod自体が読み込める状態かをclaude plugin testで確かめる
バージョンが足りていても、設定や組織のポリシーでmodが止められていることがあります。modを入れる前に、modのない空のディレクトリでclaude plugin testを実行すると状態が分かります。セッションもログインも要りません。2.1.288での出力は次のとおりでした。
claude plugin test: .../empty: no hooks module to load; there is no hooks/hooks.json naming one in "modules"メッセージの意味は公式ドキュメントのトラブルシュートにあります。
| メッセージに含まれる文字列 | 意味 |
|---|---|
no hooks module to load | modは読み込める。このディレクトリにテスト対象のmodがないだけ |
hooks modules are turned off here | 自分の設定のdisableAllHooksか、組織のポリシーがmodを止めている |
hooks modules are turned off in this process | Anthropicがインストール済みmodをリモートで止めている。手元の設定では戻せない |
組織がallowManagedModsOnlyで組織のmodだけを許可している場合、このチェックには出ません。その場合はmodを入れても読み込まれず、理由はデバッグログに出ます。
modの権限:askより先に許可でき、denyはガード次第
modは、インストールしたあなたのアカウントでできることを、ほぼすべてできます。公式ドキュメントが挙げている範囲は次のとおりです。
- アカウントが触れる場所ならどこでもファイルを読み書きし、プログラムを起動し、ネットワークに接続する
- 環境変数や設定ファイルを読む。そこに置いたAPIキーも含む
- 送ったプロンプトと、Claudeのツール呼び出しをすべて見る
- プロンプトやツール呼び出しを書き換える、あなたが入力したかのようにプロンプトを送る、別のセッションにメッセージを送る
- 確認が出る前にツール呼び出しを許可する
- あなたのプランやAPIキーでモデルを呼び出し、使用量を消費する
問題になりやすいのは、これらが既存の権限ルールとどういう順番で効くかです。ツール呼び出しを許可・拒否するのはtool.checkというhookで、tool.callのhookとPreToolUseのsettings hookのあとに、allow・ask・denyのどれかを返します。
| 守りたいもの | modに対して効くか |
|---|---|
askルールによる確認 | 効かない。modが先に許可すれば確認は出ない |
自分の設定ファイルやプラグインのPreToolUseによるブロック | 効かない。modはブロックされた呼び出しを許可できる。modがツールを実行せず自前の結果を返すと、これらのsettings hookはそもそも走らない |
| auto modeの分類器 | modが許可した呼び出しは分類器のチェックを通らずに実行される |
denyルール | ガードが読み込まれる環境では効く(管理者がallowModsToOverrideDenyRulesを設定した場合を除く)。ガードがない環境で効くとは書かれていない |
管理設定のPreToolUse | 効く。どのmodより先に走り、そのブロックは最終。modが呼び出しを書き換えると、書き換え後の呼び出しにもう一度かかる |
mod自身の$.fsと$.process | denyルールの対象外。ガードがあっても、Read(.env)を拒否していても、modは$.fs.readで.envを読めるし、それを読むプログラムを起動できる |
| 組織のネットワークポリシー | $.http.fetchには効く。$.process.runで起動したプログラムには効かない |
| サンドボックス | 囲うのはClaudeが実行するBashコマンドだけ。modが起動したプロセスは外で動く |
| 権限確認の画面 | modは見た目も表示内容も変えられない。ただし画面が出る前に許可・拒否はできる |
ここでいうガードは、組み込みmodのcc-plugin-sec-defaultです。ユーザーが入れたどのmodより先に読み込まれ、ユーザーは止められません。読み込まれる条件は次のどちらかです。
- マシンに管理設定(managed settings)がある
- TeamかEnterpriseプランでClaude Codeにログインしている
APIキー、Amazon Bedrock、Google CloudのAgent Platform、Microsoft Foundryで使っている場合は、管理設定があるマシンでだけ読み込まれます。この2条件を素直に読むと、個人のProやMaxプランでログインしていて管理設定もないマシンでは、ガードは読み込まれないことになります。その環境では、denyルールがmodの許可より優先されるとはドキュメントに書かれていません。

実際の判断に落とすと、次のようになります。
.envや秘密鍵をdenyルールで守っているつもりでも、modのファイル読み取りは止まらない。秘密を扱うリポジトリで使うmodほど、ソースを読む価値がある- auto modeや
--dangerously-skip-permissionsと同じく、modの許可は人の確認を経ない。分類器が何を止めているかはClaude Code Auto Mode:仕組み、何がブロックされ、いつ使うべきか(2026)、確認を外す影響はClaude Code --dangerously-skip-permissions:何を外し、いつ使わないかが詳しい - 対話セッションでは、初めて開くディレクトリの信頼確認に答えるまでmodは読み込まれない
modを入れるのは、その作者が書いたスクリプトを自分のアカウントで常駐させるのと同じだと考えておくのが安全です。
インストール前の確認:validateのcalls行とソースを読む基準
modを入れる前に、コードを実行せずに中身を調べられます。手順は4段階です。
- プラグインのファイルを手元に取得する。たとえば
git clone https://github.com/OWNER/REPOでリポジトリを複製する - シェルで
claude plugin validate ./some-modを実行する - 出力の
hooks:行とcalls:行を読む - 下の表で「ソースを読む」に当たる呼び出しがあれば、その箇所のコードを読む
validateは、Claude Codeがmodを読み込むときと同じ静的解析を、コードを実行せずに行います。modがファイル・プロセス・ネットワーク・モデルに触れる手段はmods API(コード上の$)しかなく、validateが読み取れない書き方でAPIを使うmodはClaude Codeが読み込みを拒否します。つまりcalls:行は「このmodが使える能力」の一覧として信頼できます。足りないのは、その能力を何に使うかです。

hooks:行で注意するのは次のイベントです。
tool.call、prompt.submit:すべてのツール呼び出しとプロンプトを見て、書き換えられるsession.append:会話の各行を、保存される前に書き換えられるui.render{component=AskUserQuestion}:Claudeがユーザーに質問するダイアログを描き直せるtool.check:確認が出る前にツール呼び出しを許可・拒否できる。上の優先関係がそのまま当てはまる
calls:行は次の表で読みます。左2列は公式ドキュメントの説明、右列はソースを読むかどうかの目安です。
calls:に出る呼び出し | できること | ソースで確かめること |
|---|---|---|
$.process.run、$.process.spawn | あなたとしてプログラムを起動する | 必ず読む。どのコマンドを、どの引数で起動するか |
$.http.fetch | ネットワークに接続する | 必ず読む。送り先と、送る中身 |
$.fs.read、$.fs.write | アカウントが触れる場所ならどこでも読み書き | 読み書きするパス。ホームディレクトリ全体や秘密ファイルに届くか |
$.env.get、$.settings.read | 環境変数と設定を読む。APIキーを含みうる | 出力のenv reads:行で変数名が分かる。名前が用途と合っているか |
$.env.set | 以後に起動するコマンドやMCPサーバーの環境変数を変える | env writes:行の変数名。PATHのように実行内容を変えるものか |
$.model.complete | あなたのプランかAPIキーでモデルを呼ぶ | 呼ぶ頻度とトリガー |
$.prompt.submit | あなたの言葉としてプロンプトを送れる | 送る文面と送るタイミング |
$.session.send | 別のセッションやサブエージェントのClaudeにメッセージを送る | 送る相手と内容 |
$.mcp.call | 接続中のMCPサーバーのツールを呼ぶ。セッションの権限ルールに従う | どのツールを呼ぶか |
入れない判断の目安も置いておきます。$.http.fetchがあり、同時に$.fs.read・$.env.get・$.settings.readのどれかがあって、送り先と送る中身をソースで追えないmodは入れない。hooks:にtool.checkがあるのに、何を許可するのかが読み取れないmodも同様です。プラグインを更新すると中身のコードも変わるので、更新後にもう一度validateを通します。
Anthropic公式サンプル3つのvalidate結果
Anthropicはanthropics/claude-code-playgroundリポジトリのclaude-code/modsフォルダ(Anthropic公式のサンプルmod)でサンプルを公開しています。サポートなしで現状のまま共有されているものです。2026年10月1日のコミット569c5283を取得してvalidateにかけた結果は次のとおりです。
$ claude plugin validate claude-code/mods/token-weather
❯ ./token-weather.mjs hooks: session.start, turn.complete, ui.render{component=AbovePrompt}
❯ ./token-weather.mjs calls: $.session.usage (via takeReading), $.ui.invalidate (via takeReading), $.ui.resolve
✔ Validation passed
$ claude plugin validate claude-code/mods/blast-radius
❯ ./blast-radius.mjs hooks: tool.call{tool=Bash}, ui.render{component=Pane}, ui.render{component=AbovePrompt}
❯ ./blast-radius.mjs calls: $.clock.now, $.process.run, $.session.cwd, $.ui.close, $.ui.invalidate, $.ui.open, $.ui.resolve, $.ui.toast
✔ Validation passed
$ claude plugin validate claude-code/mods/replay-theater
❯ ./replay-theater.mjs hooks: session.start, command.run{command=replay}, tool.call, turn.start, turn.complete, ui.render{component=AbovePrompt}, ui.render{component=Pane}, ui.close
❯ ./replay-theater.mjs calls: $.clock.sleep (via openReplay), $.command.register, $.fs.exists (via stepsFor), $.fs.read (via stepsFor), $.session.cwd (via stepsFor), $.ui.close (via replayView), $.ui.invalidate, $.ui.open (via openReplay), $.ui.resolve
✔ Validation passed3つとも合格で、$.http.fetch、$.env.get、$.model.completeはどれも呼んでいません。読み方の例を挙げます。
- token-weather(プロンプトの上にコンテキストウィンドウの予報を出す):呼ぶのはセッションの使用量と描画だけ。ファイルにもネットワークにも触れない
- replay-theater(直前のターンでClaudeが加えたファイル編集を
/replayで順に見せる):$.fs.readがある。(via stepsFor)とあるので、どのファイルを読むかはstepsFor関数を見れば分かる - blast-radius(
rm -rfやforce pushのような危険なシェルコマンドを保留し、影響を見せて実行かキャンセルかを選ばせる):$.process.runがある。ここはソースを読む必要がある
blast-radiusのソースで分かったこと
validateが示すのは「プログラムを起動する」という能力だけです。hooks/blast-radius.mjsを読むと、$.process.runで起動しているのは次の3種類でした。
- 39行目と73行目:
sleep。実行/キャンセルのボタンが押されるまで待つためのループで、ソースのコメントによれば、hook自身の持ち時間は10秒だが$の呼び出し中の時間はそこに数えられないため - 278行目:
bash -cの補助スクリプト。cdの移動先を解決する - 337行目:
bash -cの補助スクリプト。rmが消すことになるファイル数とバイト数を数える
保留の対象は、-rや-f付きのrm、git reset --hard、git push --force・-f・--force-with-lease・+ref、alembic upgrade、rails db:migrate、prisma migrate、manage.py migrateです。どれも、危険なコマンドを保留して影響を見せるという公式の説明に沿った使い方でした。同じ$.process.runでも、起動するのがcurlで、引数に環境変数を詰めていれば話はまったく違います。その違いはcalls:行には現れません。
試す・入れる・止める・外す:modの管理コマンド
1セッションだけ試す:--plugin-dir
インストールせずに試すなら、プラグインのディレクトリを--plugin-dirで渡します。そのセッションだけ読み込まれ、保存するとhookのコードがホットリロードされます。複数試すときはフラグを繰り返します。フラグを渡せないアプリでは、環境変数CLAUDE_CODE_PLUGIN_DIRSで同じことができます。
git clone https://github.com/anthropics/claude-code-playground
cd claude-code-playground/claude-code/mods
claude --plugin-dir ./token-weathertoken-weatherが実際にプロンプトの上に描画される様子は、対話セッションを開いていないので確認していません。
インストールする:マーケットプレイス名を付けて指定する
modはプラグインとして、マーケットプレイスからインストールします。指定はプラグイン名@マーケットプレイス名です。
- セッション内:
/plugin install token-weather@claude-code-playground-mods - シェル:
claude plugin install token-weather@claude-code-playground-mods
シェルでインストールしたとき、すでにセッションを開いていれば、そのセッションで/reload-pluginsを実行すると読み込まれます。実行しなければ次の起動時から有効です。スコープの既定はユーザー単位で、--scope projectか--scope localで変えられます。
マーケットプレイスは/plugin marketplace addかclaude plugin marketplace addで追加します。指定できるのは、GitHubのowner/repo(#refで参照を指定可)、任意のgit URL、./か../で始まるローカルパス、ホストされたmarketplace.jsonのURLです。公式サンプルを複製したフォルダをマーケットプレイスとして追加し、インストールから削除までを2.1.288で実行した出力は次のとおりです。
$ claude plugin marketplace add ./
✔ Successfully added marketplace: claude-code-playground-mods (declared in user settings)
$ claude plugin install token-weather@claude-code-playground-mods --scope user
✔ Successfully installed plugin: token-weather@claude-code-playground-mods (scope: user)
$ claude plugin list
Installed plugins:
❯ token-weather@claude-code-playground-mods
Version: 0.1.0
Scope: user
Status: ✔ enabled
$ claude plugin disable token-weather@claude-code-playground-mods
✔ Successfully disabled plugin: token-weather (scope: user)
$ claude plugin uninstall token-weather@claude-code-playground-mods
✔ Successfully uninstalled plugin: token-weather (scope: user)ローカルの複製をマーケットプレイスにした場合、そのフォルダを移動・削除するとmodは読み込まれなくなります。
ターミナルのセッションで/pluginを開くと、タブの下に1 mod active · first-modのような薄い行で、読み込まれたmodの数と名前が出るとドキュメントにはあります。組み込みmodはこの行に含まれません。
止める・外す:範囲別の3つの方法
| 止めたい範囲 | 方法 | 一緒に止まるもの |
|---|---|---|
| 1つのmod | /pluginのInstalledタブ(Tabキーで切り替え)で無効化かアンインストール。シェルならclaude plugin disable/uninstall | なし |
| 1セッションだけ、入れたmodすべて | claude --safe-modeで起動 | ほかのカスタマイズも止まる |
| すべてのセッションで、入れたmodすべて | ~/.claude/settings.jsonに"disableAllHooks": true | 自分のsettings hookとカスタムstatusline。組織が管理するものは動き続ける |
disableAllHooksで止まるのはmodのコードだけで、同じプラグインに入っているskill、コマンド、エージェント、MCPサーバーは読み込まれ続けます。プラグインごと外したいならアンインストールします。組み込みmodは、disableAllHooks、--bare、--safe-modeのどれでも止まりません。
組み込みmod:you-should-knowとsec-defaultの役割
Claude Code自身の機能の一部もmodとして作られています。/pluginのInstalledタブでBuilt-inの下に並び、更新やアンインストールはできません。
/pluginでの名前 | 役割 | 止め方 |
|---|---|---|
cc-plugin-agents-md | AGENTS.mdをプロジェクトの指示として読み込む | /pluginで無効化、または読み込む指示ファイルを選ぶ |
cc-plugin-diff | /diffを引き受けてペインを描く | /pluginで無効化。/diffは組み込みの版が答える |
cc-plugin-plugin-authoring | mod作成用のplugin-authoring skillをClaudeに渡す。modのコードは持たない | /pluginで無効化 |
cc-plugin-sec-default | 組織が管理するものをユーザーのmodから守るガード | ユーザーは止められない |
cc-plugin-telemetry | Claude Codeと組み込みmodの分析記録を送る | /pluginで無効化、またはDISABLE_TELEMETRYなどで分析を切る |
cc-plugin-you-should-know | 長めの作業中に横で見張るエージェントを動かし、見落としそうなことをプロンプトの上に表示する | 既定で無効。/plugin enable cc-plugin-you-should-know@builtinで有効化し、止めるときは/pluginで無効化 |
diff、agents-md、sec-default、telemetryのソースはClaude Codeリポジトリのmodsフォルダ(Anthropic公式の組み込みmod)で公開されています。sec-defaultのコードは、ガードが実際に何を見ているかを確かめたいときに読めます。
modを自作する:Claudeに頼むか、3ファイルを自分で書く
Claudeに頼む場合:dev-modsに作られ、期限が来ると消える
対話セッションで欲しいmodを説明すると、Claudeが組み込みのplugin-authoring skillを使って書きます。/plugin-authoringで自分からskillを読み込ませることもできます。ドキュメントの例はmake a mod that shows the current git branch above the promptです。
- ファイルは
~/.claude/dev-mods/<セッションID>/<mod名>/に作られる。defaultとacceptEditsの権限モードでは~/.claudeが保護されたパスなので、ファイルごとに承認を求められる - 最初のファイルが保存されると、このセッションでホットリロードを有効にするかを聞かれる。有効にするとターンの終わりに読み込まれ、以後の変更もターンごとに反映される
- 読み込まれるのは作ったセッションの中だけ。フォルダは
cleanupPeriodDaysを過ぎると削除されるので、残したいなら~/mods/git-branchのような自分の場所へコピーし、claude --plugin-dir ~/mods/git-branchで読み込む claude -p、dontAskモード、信頼していないワークスペース、modを無効にしたセッションでは読み込まれない
この流れはログインした対話セッションが必要なため、実行していません。
自分で書く場合:hooks.jsonのmodulesキーとregister関数
Node.jsもバンドラーもビルドも要りません。Claude Codeが.jsと.tsを直接読み込みます。ドキュメントのチュートリアルfirst-modは3ファイルで、ツール呼び出しを数えてスピナーの横に表示し、/tallyコマンドで件数を出します。
first-mod/
├── .claude-plugin/
│ └── plugin.json
└── hooks/
├── hooks.json
└── register.jsplugin.jsonはマニフェストです。
{
"name": "first-mod",
"version": "0.1.0",
"description": "Counts Claude's tool calls, shows the count beside the spinner, and adds a /tally command",
"author": { "name": "Your Name" }
}hooks/hooks.jsonのmodulesキーが、このプラグインをmodにしている部分です。
{
"description": "The first-mod hooks module",
"modules": ["./register.js"]
}hooks/register.jsが本体です。各hookは($, e, next)を受け取ります。$がmods API、eがイベント、nextが次のハンドラ(ほかのmodとClaude Code本来の処理)です。
// 下のhookで共有するカウント
let calls = 0
// modが読み込まれたときに1回だけ呼ばれる
export function register(on) {
// セッション開始時に/tallyコマンドを登録
on('session.start', async ($, e, next) => {
await $.command.register({
name: 'tally',
description: 'Show how many tool calls Claude has made',
})
return next(e)
})
// Claudeがツールを使う直前に毎回呼ばれる
on('tool.call', async ($, e, next) => {
calls += 1
// 画面を描き直させて新しい件数を出す
$.ui.invalidate('ui.render')
// ツールは通常どおり実行させる
return next(e)
})
// /tallyと入力したときだけ呼ばれる
on('command.run', { command: 'tally' }, async () => {
return { text: 'Claude has made ' + calls + ' tool calls since this mod loaded' }
})
// スピナーを描くたびに呼ばれ、語の後ろに件数を足す
on('ui.render', { component: 'Spinner' }, async ($, e, next) => {
return next({ ...e, props: { ...e.props, suffix: ' · tool calls: ' + calls + '…' } })
})
}tool.callとsession.startはnext(e)を返して流れをそのまま通し(観察)、ui.renderは中身を変えてnextに渡し(書き換え)、command.runはnextを呼ばずに自分で答えます(応答)。hookにできるのはこの3つの扱い方です。
2.1.288で実行した確認の出力です。
$ claude plugin validate ./first-mod
❯ ./register.js hooks: session.start, tool.call, command.run{command=tally}, ui.render{component=Spinner}
❯ ./register.js calls: $.command.register, $.ui.invalidate
✔ Validation passed
$ cd first-mod && claude plugin test
tests/first-mod.test.ts:
(pass) /tally reports the tool calls the mod has seen [64.48ms]
1 pass
0 fail
Ran 1 test across 1 file. [0.34s]
$ claude -p "/tally" --plugin-dir ./first-mod
first-mod: Claude has made 0 tool calls since this mod loadedclaude plugin testが実行しているのは、ドキュメントにあるテストファイルtests/first-mod.test.tsです。ツール呼び出しを2回発生させて/tallyの返答を確かめるもので、セッションもログインもネットワークも使いません。所要時間は実行のたびに変わります。最後のclaude -p "/tally"は、ログインしていないCLIでもそのまま答えました。command.runはモデルを呼ばずに返答するためです。
validateが落ちたときのエラー例
わざと壊したコピーで出たエラーです。イベント名を'tool.calls'と打ち間違えた場合:
✘ Found 1 error:
❯ modules../register.js: bad-mod: .../hooks/register.js:7: "tool.calls" is not an event; $ is always spelled $.noun.event(...) at the call site, on is always on("<event>", hook), and next.to always next.to(e, "<tier>")
✘ Validation failedhooks.jsonのキーを"module"と打ち間違え、hooksキーもない場合:
✘ Found 1 error:
❯ root: hooks.json must have `hooks` (the hook matchers) or `modules` (hooks modules), or both
✘ Validation failedドキュメントのトラブルシュートには「modulesキーがない、または綴りが違うと、validateは通るがhooks行が出ない」とあります。2.1.288でhooksキーもmodulesキーもないhooks.jsonを試したところ、上のように不合格になりました。hooksキーがある場合は、ドキュメントの説明どおりになると考えられます。
静的解析に読ませるための書き方の決まりもあります。
$.store.get('notes')のように、mods APIは毎回$から省略せずに書く。const ui = $.uiのような代入や分割代入は不合格onに渡すイベント名は文字列リテラルで書く。変数やループは不可- importはプラグインのディレクトリ内のファイルを相対パスで。外部パッケージは
claude-codeだけ使える。動的なimport()は不可 - リロードのたびに
registerが呼び直され、モジュール変数はリセットされる。値を保つなら$.stateを使う --plugin-dirで読み込むと、そのバージョンの型定義が.claude-plugin/types/に書き出される。ドキュメントと食い違うときは型定義が正しい
配布するとき:名前とバージョンの注意
少人数ならディレクトリかzipを渡し、チームなら自分のマーケットプレイス(たとえば非公開リポジトリ)に載せます。組織全体には管理者が管理設定で配布でき、誰にでも公開するなら公開リポジトリにするかAnthropicのディレクトリに申請します。claude-で始まるような、Anthropic製に見えるプラグイン名はvalidateで落ちます。イベントやメソッドはリリースごとに変わりうるので、READMEには動作を確かめたClaude Codeのバージョンを書いておきます。インストールしたコピーはバージョン単位でキャッシュされるため、開発中は--plugin-dirで元のディレクトリを読み込みます。
modが動かない原因の切り分け:validateとデバッグログ
modが壊れていても、Claude Codeはそのmodを飛ばしてセッションを続けます。そのため「壊れている」と「何もしていない」が同じに見えます。次の順で切り分けます。
| 症状 | 確かめること |
|---|---|
| 追加したコマンドも描画も何も出ない | claude --versionで2.1.287以降か。次にclaude plugin validateでイベント名の誤りや読めないモジュールがないか |
| どのmodも読み込まれない | 空ディレクトリでclaude plugin test。turned offと出たら設定かポリシーが止めている |
| 初めて開いたディレクトリでだけ動かない | 対話セッションの信頼確認に答えていない |
| インストール済みのプラグインが1つも読み込まれない | --safe-modeで起動していないか |
VS Code拡張やclaude -pで表示が出ない | 仕様。hookは動いているが描画はされない |
| 組織のPCで自分のmodだけ動かない | デバッグログにallowManagedModsOnlyの行がないか。あれば管理者に相談する |
読み込みを拒否された理由は、modの名前を含む1行で記録されます。出る場所はセッションによって違います。
--plugin-dirで開いた対話セッション(ホットリロード中):トランスクリプトに薄い行で出る- マーケットプレイスから入れたmodを使うセッションなど:デバッグログにだけ出る。
claude --debugで起動して読む claude -pと--plugin-dirの組み合わせ:標準エラー出力に出る
拒否の行はhooks module <名前> not loaded:で始まり、コロンの後が理由です。disableAllHooks in managed settings、only managed plugins and built-in plugins run、(--bare)、another plugin of that name loads first(同名のプラグインが先に読み込まれた)などがあります。ガードがmodの許可を退けた場合はtried to lift a deny rule in your settingsと出て、その呼び出しは拒否されたままです。詳しい一覧は公式ドキュメントの「mod のトラブルシューティング」にあります。
Claude Code modsの使用量・settings hook・探し方についての質問
Claude Code modsを入れると使用量は増えますか
hookが動くこと自体はモデルの呼び出しではなく、上の/tallyのようにモデルを使わずに完結するmodもあります。使用量に直結するのは、calls:行に$.model.completeが出るmodです。この呼び出しはあなたのプランかAPIキーでモデルを使います。$.prompt.submitでプロンプトを送るmodも、そのぶんClaudeのターンが走ります。どのタイミングで呼ぶかはソースで確かめます。
Claude Code modsが出たらsettings hookは使わなくなりますか
使い続けて問題ありません。組織向けのドキュメントには、settings hookについて廃止されるものは何もないと明記されています。手元のスクリプトでツール呼び出しをブロック・記録するだけなら、settings hookのほうが単純です。
コミュニティ製のClaude Code modsはどこで探せますか
第三者が運営するawesome-claude-code-mods(GitHubで公開されたmodの非公式カタログ)があり、2026年10月6日時点で2,685件の公開modをclaude plugin validateの出力付きで掲載しています。Anthropicの公式ディレクトリではなく独立したスキャンで、カタログ自身も「検証は安全な挙動を保証しない」と書いています。気になるmodが見つかったら、validateの出力を見るだけで済ませず、自分で複製してcalls:行とソースを確かめてください。目的別のskillやMCPを探しているなら、Claude Codeで最初に使うべきSkills 2026年版:ワークフロー別の公式スターターとClaude Codeで最初に入れるべきMCP 2026年版:ワークフロー別の初手のほうが近い答えです。
参考資料5
本文で参照している外部ページを、登場順に並べています。最終更新日:2026年10月6日。
参考資料5
本文で参照している外部ページを、登場順に並べています。最終更新日:2026年10月6日。
- 1.Anthropic公式のmodsドキュメント(日本語版「Mods の概要」)code.claude.com/docs/ja/plugins/mods/overview
- 2.claude-code/modsフォルダ(Anthropic公式のサンプルmod)github.com/anthropics/claude-code-playground/tree/main/claude-code/mods
- 3.Claude Codeリポジトリのmodsフォルダ(Anthropic公式の組み込みmod)github.com/anthropics/claude-code/tree/main/mods
- 4.公式ドキュメントの「mod のトラブルシューティング」code.claude.com/docs/ja/plugins/mods/troubleshoot
- 5.awesome-claude-code-mods(GitHubで公開されたmodの非公式カタログ)github.com/karanb192/awesome-claude-code-mods





