TL;DR
- Claude Code Mod は 3 つのファイルでできています。
.claude-plugin/plugin.json、{"modules":["./index.ts"]}を持つhooks/hooks.json、そしてregister(on)を export する TypeScript モジュールです。ロードに必要なのはこれだけです。 - ビルド 2.1.272 では、
/plugin-typesが書き出す型は 11,783 行のclaude-code.d.tsです。23 個の noun にまたがる 84 個のイベント名または call 名があります。fs.readFileは消え、noun はfs.readとfs.writeになりました。 - 42 行の
tool.callフックにより、モデルは Read ツールでも Bash ツールでも本物のキーではなくAPI_KEY=[REDACTED]を読みました。正常時 1 ホップあたり 27.9 ms で、セッションに加わるトークンは約 0 です。 - 10 秒の予算を超えてスリープするフック、または例外を投げるフックはスキップされ、その下のコマンドが実行されます。ログには出ますが、実際には素通りです。ガード用の Mod は fail open します。
- 生成パスは機能します。1 文から 190 行の Mod と 53 行のテストが約 4 分、$1.23 で生成され、
claude plugin validateは警告なし、claude plugin testは 4 pass / 0 fail でした。 - 1 点だけ再現しませんでした。Mod は
claude -pではロードされましたが、pty 経由のインタラクティブ REPL では 2 回試しても無反応でした。REPL でのロードは、実際のターミナルで確認するまで未検証として扱ってください。
計測が示すこと
以下はすべて、CLAUDE_CODE_ENABLE_FUNCTION_HOOKS を設定した Claude Code 2.1.272 で、手書きの redact-secrets という Mod と、それを壊すために作った 3 つの使い捨て Mod を使って実行したものです。この機能自体は Function Hooks の提案 issue で追跡されており、今でも公式仕様に最も近いものです s3。
ツールはドキュメントより先に存在します。ビルド 2.1.272 には claude plugin validate、test、eval、details が含まれています。plugin --help のコマンド一覧には載っていませんが、test は動きます s3。セッション内で /plugin-types を実行すると、.claude/types/claude-code.d.ts に 11,783 行が書き出され、さらに 7 つのサーバーの 150 個の MCP ツールをカバーする 3,438 行の claude-code-mcp.d.ts も作られます s3。生成された型を数えると、23 個の noun に 84 個のイベント名または call 名があります。9 月の記事で読んだかもしれない点が 1 つ変わっています。fs.readFile はもう存在せず、使えるのは fs.read と fs.write です s9。同じ型によれば、tool.call フックは { result, context? } または { deny } を返します。text と ref は core 由来でフック自身の戻り値には含まれないため、書き換えるのは text ではなく result です s3。
claude plugin validate は、Mod が一度も動く前にフットプリントを表示します。./index.ts hooks: tool.call と ./index.ts calls: $.ui.toast、モジュールがホストの機能に触れない場合は calls: nothing on $ です s4。この静的な 1 行は、awesome-claude-code-mods のようなディレクトリが現時点で自動化できる唯一の審査であり、次の段落を読むときに重要になります。
リダクションは -p モードで動きます。42 行のフックが tool.call を横取りし、ファイルとシェル出力に sk-test1234567890abcdef が入っていた箇所で、モデルは Read ツールでも Bash ツールでも API_KEY=[REDACTED] を受け取りました s3。デバッグログでは、正常な 1 ホップは往復 27.9 ms で、ワーカーへのホップと next() を含みます s3。claude plugin details はこの Mod が全セッションに加えるトークンを約 0 と見積もりました。Mod はプロンプトのテキストではなくプロセス内のコードであり、これがシェルフックやスキルに対する推進派の主な論拠です s7。
ガードは fail open します。15 秒スリープする slow-guard という Mod は 10 秒の予算で打ち切られ、hook failed: slow-guard: exceeded 10000ms budget (tool.call; skipped; what is below it ran in its place) と出ましたが、echo hi は実行されました s3。例外を投げる throw-guard という Mod も同じようにスキップされ、hook failed: throw-guard: boom (tool.call; skipped; what is below it ran in its place) と 574.2 ms が報告されました s3。ログでは騒がしいのに、実際には素通りです。何かをブロックするための Mod は、この点を踏まえて読む必要があります。ガードのバグはクラッシュではなく穴になります。
生成は安上がりです。1 文から、モデルは動作する 190 行の Mod と 53 行のテストを約 4 分、34 ターン、$1.23 で書きました(出力トークン 19,053、キャッシュ読み取り 497,282、thinking 8,357)s3。その Mod は claude plugin validate を警告なしで通り、claude plugin test は 0.31 秒で 4 pass / 0 fail、実際にキーを隠しました s3。手書きの Mod では、claude plugin test は API キーもモデル呼び出しもなしで、0.25 秒で 1 pass でした s3。テンプレートで同じ実験を繰り返したいなら、エージェントに Mod の書き方を教えるスキルがすでにあります s12。
再現しなかったこと。pty 経由の REPL では 2 回とも Mod がロードされなかったため、$.ui.toast は一度も表示されませんでした。-p では、同等のものがデバッグ行として出ただけです。X で出回っている「REPL のみ」という主張とは逆の結果が観察され、根本原因は特定できていません s8。ワーカーが固まったときの 5 秒ハートビートもテストしていません。測定したのは 10 秒の await 予算と例外パスだけです。
計測結果
| ケース | Mod の動作 | 結果 | 時間 |
|---|---|---|---|
| redact-secrets、Read ツール | tool.call で result を書き換える |
モデルには API_KEY=[REDACTED] が見える |
1 ホップ 27.9 ms |
| redact-secrets、Bash ツール | 同じフック、シェル出力 | モデルには API_KEY=[REDACTED] が見える |
1 ホップ 27.9 ms |
| slow-guard | tool.call 内で 15 秒スリープ |
スキップされ、echo hi が実行された |
10000 ms で打ち切り |
| throw-guard | tool.call 内で boom を投げる |
スキップされ、コマンドが実行された | 574.2 ms |
| 生成された Mod | 1 文から 190 行 + テスト 53 行 | validate: 警告なし、test: 4 pass / 0 fail | 約 4 分、34 ターン、$1.23 |
redact-secrets への claude plugin test |
API キーなし、モデル呼び出しなし | 1 pass | 0.25 s |
claude plugin details |
Mod のセッションコスト | 約 0 トークン追加 | n/a |
手順: Claude Code 2.1.272、環境変数で function hooks を有効化。各 Mod は plugin.json、hooks/hooks.json、1 つの index.ts を持つプラグインディレクトリです。実行はデバッグログを有効にした claude -p で行い、用意したファイルとシェルコマンドの両方に sk-test1234567890abcdef を含めました。fail open のケースは、15 秒スリープする Mod と例外を投げる Mod で動かし、ガード対象のコマンドは echo hi です。インタラクティブ REPL は pty 経由で操作し、2 回とも Mod はロードされませんでした。
月曜にやること
- セッションで
/plugin-typesを実行し、.claude/types/claude-code.d.tsを開く。9 月の記事のスニペットを信じる前に、fs.readとtool.callを検索する。 - 3 ファイルの Mod の骨組み(
plugin.json、{"modules":["./index.ts"]}を持つhooks/hooks.json、register(on)を export するindex.ts)を書き、claude plugin validateを実行する。hooks:とcalls:のフットプリント行を読む。 - いちばんよく使うシェルフックを、
resultを書き換えるtool.callハンドラに移植し、デバッグログのホップ時間をシェル版と比べる。 - Mod の隣に
claude plugin testのファイルを追加し、CI で API キーなしでガードが動くようにする。 - すべてのガードハンドラを try/catch で包み、失敗時は
{ deny }を返す。このビルドでは、例外や 10 秒の停止でガードがスキップされ、コマンドが通ってしまう。 - Mod を
claude -pと実際のインタラクティブなターミナルで別々にテストし、どちらでロードされたかを記録する。 - サードパーティの Mod をインストールする前に
claude plugin validateを実行し、Mod が使う理由のないホスト機能をcalls:行に挙げているものは断る。
さらに読む
- 提案 issue を、コメントに添付されたアーキテクチャ PDF も含めて最後まで読む。
register(on)、予算、ワーカーへのホップについての唯一の文書化された契約です s3。 - Command Code Mods の設計と比べる。ホストプロセス内の
ModApiに対して TypeScript を実行するもので、2 つのシステムは形も early access の制限も共通です s2。 - claudefa.st のプレビューは、機能がまだ提案だった頃に書かれています。9 月 3 日の文章と 2.1.272 のバイナリの間で何が変わったかを見るのに役立ちます s9。
- Prathkum のノートツイートは、プロセス内フックがトークンとレイテンシでシェルフックに勝つ理由を、最も短く明快に述べています s7。
- cc-mod-waitwhat は最初に読む Mod として良い例です。プロンプトの上に UI を出し、トランスクリプトには何も書き込みません s11。
- cc-arcade は
$.uiがどこまで届くかを示します。Mod からプロンプトの上にゲームを描画しています s5。 - フックのリファレンスは今もシェルモデルを説明しています。古い各イベントを新しい
noun.event名に対応づけるため、開いておいてください s1。 - X の懐疑派は、プラグインですでに同じことができ、リリースのたびに表面が壊れると主張しています。
fsnoun の改名はその主張を支える 1 つのデータポイントです s23。
情報源
- Function Hooks proposal (issue #91870), GitHub, anthropics/claude-code. 読む理由: Mod についての仕様に近い唯一の文書で、コメントにアーキテクチャ PDF と出荷までの経緯があります。
- Hooks reference, Claude Code docs. 読む理由: 移行元のシェルフックのモデルを、イベントごとに説明しています。
- Command Code Mods documentation, Command Code. 読む理由: プロセス内 TypeScript という同じ形の先行例で、Anthropic が何を真似し何を避けたかを見分けるのに役立ちます。
- awesome-claude-code-mods, GitHub, karanb192. 読む理由: 公開 Mod を自動スキャンしたディレクトリで、審査は validate のフットプリントだけです。
- cc-arcade, GitHub, sezaakgun. 読む理由: この機能を目に見えるものにしたデモで、
$.uiの見本市でもあります。 - Boris Cherny announcement tweet, X, Boris Cherny. 読む理由: ブログ記事がないため、Anthropic のエンジニアによる唯一のローンチ声明です。
- Prathkum: Function Hooks explained, X, Prathkum. 読む理由: すでにシェルフックを書いている人向けの、フックと Mod の違いの最良の短い説明です。
- shipnotesai reaction thread, X, shipnotesai. 読む理由: 「REPL のみ」という主張が広まった場所で、私たちの実行はそれと矛盾しました。
- Claude Code Function Hooks: Preview Behind a Flag, claudefa.st. 読む理由: 出荷前の解説で、提案とバイナリを突き合わせるのに向いています。
- cc-mod-waitwhat, GitHub, GGGODLIN. 読む理由: トランスクリプトではなく UI に書き込む、小さくて読みやすい Mod です。
- claude-mods-skill, GitHub, BeLazy167. 読む理由: 1 文の実験を繰り返したい人向けの、Mod 生成用スキルです。
- AxialisSoftware reaction, X, AxialisSoftware. 読む理由: 懐疑的な立場を 1 つのツイートにまとめています。
FAQ
Mod は今すぐシェルフックの代わりになりますか?
ブロックが必要なものについては、まだです。2.1.272 では、例外を投げるか 10 秒を超えて止まるフックはスキップされ、コマンドが実行されます。シェルフックは引き続き動くので、宣言的な catch や fail closed のオプションが入るまで、ブロック用のものはそちらに置いておいてください。
Mod が問題なく動くなら、なぜ validate が重要なのですか?
hooks: と calls: の行が、Mod が $ 上で何に触れるかを示す唯一の静的ビューだからです。自作の Mod ならフットプリントの確認になり、サードパーティの Mod なら、コードが自分のプロセスで動く前に得られる審査のすべてです。
Mod は 1 セッションあたりいくらかかりますか?
claude plugin details は約 0 トークンの追加と報告しました。Mod はプロンプトのテキストではなくエンジン内で動くコードであり、スキルや CLAUDE.md のルールに対する主な利点です。
なぜ Mod は -p ではロードされたのに REPL ではロードされなかったのですか?
不明です。pty 経由の 2 回の試行は無反応で、claude -p ではロードされてフックが適用されました。原因は機能ではなく pty 環境にある可能性が高いので、どちらの結果も頼る前に自分のターミナルでテストしてください。
AIDive