AIDive

未公開のClaude Code Mod自作。ガードは素通りした

AIDive · 公開

コーディングエージェントAI セキュリティ

「欲しければ作れ」からテトリスまで、12日間

Claude Code Modsは、Claude Codeのエンジン内部で動き、そのイベントを関数としてフックするTypeScriptモジュールだ。Claude Codeを率いるBoris Chernyは、わずか5語でこれを発表した。「Claude modsが今、届く」。この投稿は2,400のいいねを集め、その時点ですでに誰かがターミナルの中にテトリスを作り上げていた。テトリス、Doom、Claudeがテストを走らせている間に育つペット——どれもプロンプトの上にトークン消費ゼロで描画される。

発表にはドキュメントページへのリンクはない。リンクされているのは、その12日前にAnthropicのエンジニアが立てたGitHub issueで、そこには一つの条件が書き込まれていた。Alice Poteatは、この機能が出荷されるかどうかはコミュニティの反応次第になるだろうと書いた。177件のコメントを経て、人々はフラグ付きのバイナリを叩き、タイムアウトを計測し、その上にゲームを作り上げていた。

Measure Value
Likes on the announcement 2,400
Comments on the GitHub issue 177
Typed surface in this week's build 10,700 lines
Events on nouns (issue-thread build) 84 on 19
Mods on GitHub inside 48 hours 31

この記事執筆時点で、ドキュメントページは404を返す。本稿では、Claude Codeを拡張する4つの方法、意図的に作って壊した一つの実用的なMod、そして出荷する前にまだ不安定な部分を扱う。

Modとは、途中に挟まる関数のこと

ソースツリーはそれを一文で定義している。Modとは、その振る舞いがhooksモジュールに宿るClaude Codeプラグインのことだ。一つのregisterエントリが、エンジンのイベントを関数としてフックする。ディスク上では、プラグインフォルダ、モジュールを一つだけ指定するhooksマニフェスト、そしてそのモジュール自体からなる。

すべてのhookは3つのものの関数だ——あらゆる副作用が通る扉である$、イベント、そしてその下に続くチェーンである継続。hookはミドルウェアのように入れ子になる。最初に登録されたものがそのイベントを所有し、それより下流のどれもそれを止められない。この順序は設定によるもので、インストールの順ではない。Alice Poteatの言葉を借りれば、順序はインストールした時点ではなく設定で決まる。

アンビエントなアクセス権は存在しない。Modが行うことはすべて$を通るので、管理者はどのイベントでも監査し、許可し、拒否し、記録できる。あるコメントはこう要約した——プラグインが何をしたかは、それが行った呼び出しそのものだ。*に対する一つのhookがすべてのイベントを見るので、監査ログは一つの関数で済む。Modは描画もできる。インターフェースがReactだからだ。BunのプロセスにおいてP99で50マイクロ秒で動く。一つの環境変数でオンになる。$に実際に何が乗るかは、いまなおアーリーアクセスのパートナーとともに設計中だ。

Claude Codeを拡張する4つの方法、それぞれの使いどころ

シェルhookは、エンジンが決まったタイミングで呼び出すスクリプトだ。標準入力でJSONを受け取り、終了コードで答える。答えには上限がある——コンテキストとして戻せるのは8,000文字、一部のhookでは2,000文字だ。Prathamの言葉では、Windowsではしばしば奇妙な形で壊れるという。

プラグインは箱だ。一つのマニフェストが、skill、agent、hook、MCPサーバーをまとめる。マーケットプレイスからインストールするか、ディスク上のフォルダから直接読み込む。何かが実行される前に、一つのコマンドがその箱を検証する。

skillは、モデルが必要なときに読むプローズだ。本文は、それに一致するプロンプトが来たときにだけロードされる。今なお、振る舞いを変える最も安上がりな方法であり続けている。

Modは同じ箱に、もう1ファイルが加わったものだ——モジュールを一つ指定するhooksマニフェスト、そしてそのモジュールはTypeScriptで、型付きで、インプロセスで、あらゆるエンジンイベント上で動く。違いはそれがすべてだ。

Mechanism What it is Runs Ceiling
Shell hook Script called at a fixed moment Subprocess, exit code 8,000 chars back (2,000 for some hooks)
Plugin Bundle of skills, agents, hooks, MCP servers Installed or loaded from disk Validated before it runs
Skill Prose loaded on a matching prompt In the model's context Cheapest change
Mod Plugin plus a TypeScript hooks module In process, on every event Typed, early access

これらの型は一つのスラッシュコマンドから生まれ、$が提供するものの全一覧をあなたのプロジェクトにそのまま書き出す。古いシェルhookは廃止されたのではなく、ラップされているだけだ。あるアーリービルドでは、Spencer Morleyはそのラッパーが読み込みに失敗し、それでも宣言されたままになるのを目にした。経験則はこうだ——Claudeが知っていることを変えるならskillを書く、ある瞬間にスクリプトを走らせるならシェルhook、バンドルを出荷するならプラグイン、エンジンの内側に座るならMod。フラグがオフの環境では、シェルhookは今も変わらず動く。

Anthropic自身の3つのMod、ソースを読む

3つのModがバイナリの中に同梱されており、そのソースはGitHub上で読める——セキュリティデフォルト、diffペイン、そしてテレメトリだ。

セキュリティデフォルトは最も外側に座る。managed settingsが設定されたマシン上、あるいはTeamまたはEnterprise組織では、個人がインストールしたものは何もそれより上に来ない。12のイベントをフックし、どのhookも3つの動きのうちどれか一つを行う——user tierの先へ進める、user tierの呼び出し元を名指しで拒否する、あるいは通過させる。fail closedであり、doc commentにもそう二語で書かれている。それがスレッドが気にかけていた部分だ——管理者が$から機能を取り除けば、それより下に登録されたどれもそれを呼び出せなくなる。あるコメントの言葉では、それはプラグインに「やらないでくれ」と頼むのとはカテゴリーが違う。

Diffは、トランスクリプトの横に並ぶペインで、そのセッションの未コミットの変更をファイルごとに表示し、Claudeが編集するたびに更新される。session startで登録され、27のヘルパーファイルにまたがる、おもちゃではない代物だ。

Telemetryは、エンジン生成の内側から$に一つのnounを加える。下流にあるものをawaitし、それとそれ自身を返す。内部ビルドでのみ動く。

READMEは、ソースから一つを実行し、ソースから一つをテストするよう指示している。今日のビルドのヘルプにはvalidate、eval、detailsが並ぶ。testはそのリストにないが、それでもtestヘルプ自体は答える。組み込みのtierは、あなたのコピーも拒む——それらの名前のいずれかでプラグインを出荷しても、バイナリは自分自身のものをロードする。

42行——モデルからシークレットを隠すMod

型を書き出すあのスラッシュコマンドは、このビルドでは11,700行を出力する——23のnounにまたがる84のイベントだ。tool callのhookは、結果かdenyのどちらかで答える。テキストそのものでは決して答えない。その部分はcoreによって固定されている。

このModは3ファイルからなる——プラグインマニフェスト、1行だけのhooksマニフェスト、そしてモジュールだ。モジュールは42行。下流にあるものをawaitし、結果をスクラブし、それを返す。4つのパターンが、2種類のベンダーキー形式、GitHubトークン、そしてkey、secret、tokenという名前の変数に代入されたものすべてをカバーする。

Validateは、実行される前にソースを読む。そのモジュールがフックするイベントと、$に対して呼ぶただ一つのものを名指しする。唯一の警告はauthorの欠落だ。フラグをオンにしてディスクからロードすると、テストファイルには構造上偽の2つのキーが含まれ、モデルは「redacted」と読む。モデル自身の言葉では、値は「redacted」として返ってきたので、その中身を見ることはできない。

Measure Value
Module length 42 lines
Hop latency, worker included 28 ms
Tokens added to the session 0

エンジンはこのhopを「hooksモジュールによって解決された」とログに記す。インベントリにはskillもagentも常時オンのものも何も表示されない。一つだけ限界が残る——モデルから隠すことは、画面から隠すことではない。トランスクリプトには、そのツールが実際に出力した内容がそのまま表示される。それは別のModの仕事だ、とShip NotesのMaxは一言でそう指摘した。

壊してみる——遅いガードは素通りされるガード

同じModに1行だけ加える——下流にある呼び出しの前に、15秒のsleepを挟む。10秒後、エンジンはそれを諦め、そのhookが予算を超えたためskippedになったと報告し、その下にあるものがその代わりに実行される。コマンドはそれでも実行され、「hi」と出力する。

sleepをthrowに置き換えると——574ミリ秒、判定は同じくskipped、そしてコマンドは実行される。

Case Time Verdict
Healthy hook 28 ms Resolved
Throw 574 ms Skipped, command ran
Hang over 10 s Skipped, command ran

どちらの失敗も同じ一語に行き着く——skipped。このスレッドは、その非対称性を1週間前にすでに計測していた。ロード時に欠けている機能はfail closedになる。予算を超えたhookはfail openになる——うるさく鳴るが、素通りされる、とSpencer Morleyは言う。理由のないblockは、モデルを別のツールへ向かわせるだけだ。Prathamは、モデルが別のツールを選び、それでもファイルを書き込むのを目にした。

テーブルの上にある答えはcatchだ。Alice Poteatは、時間を掛けすぎるか、throwした場合に走る、hookのreturnに対するcatchを提案する。書き直されたwriteには、それでもモデルへの一言のメモが要る——キャッシュの都合上、モデルは自分が書こうとした内容をそのまま見るので、コンテキスト行を一つ添える必要がある。予算は同時に隔離でもある。hooks workerは独立して動いており、クラッシュするとエンジンはそれを再起動し、そのセッションのhookをオフにする。修正すべきは、より長い予算ではなく、宣言されたcatchだ。

Modsの48時間、たった一文で何が作れるか

2日が経った時点で、プロンプトの上にテトリスと、他に7つのゲームが並び、Claudeが作業している間にトークン消費ゼロで遊べるようになっていた。Doom、1993年のオリジナル版はそれ自身のプロセスで動き、Modはローカルのhttp経由でそこに到達し、1秒あたり10回描画し直す。スピナーには呼吸するようなペーサーがあり、hooks workerの内部で動く26万パラメータのストーリーモデルが、APIトークン消費ゼロで走っている。

レジストリはvalidateで31のModsをスキャンした。14がホストプロセスを実行できる。13があらゆるtool callを見る。

コミュニティスレッドのDemo 8は、モデルがシークレットを読む前にそれを隠すプラグインを一文で書けると約束していた。私たちも一つ求めてみた。

Measure Value
Time 4 min
Turns 34
Cost $1.23
Lines (plus a test file) 190, against our 42
Tests 4 pass in a third of a second

それは隠したものを種類ごとにラベル付けし、validateはクリーンに通り、APIキーもモデル呼び出しも要らない。ある返信はこう言い表した——製品はallowlistであり、テトリスはただのデモだ。

結論——今は自分用に作り、配布は後で

レジストリ自身の数字が、その警告そのものだ。31のModsのうち14がホストプロセスを実行でき、その検証手段は静的な足跡だけだ。evalのヘルプ自体がそう述べている——パスするテストスイートは、セキュリティの検証ではない。

Signal Value
Events on the 8th 20
Events on the 15th 84
CLI versions in a fortnight 14
Hacker News points 2
Replies to the compatibility question 0

10秒の予算はruntimeの中に生きており、型の中にはない、とMaratは指摘する。changelogの一行もドキュメントページもローンチ投稿もまだない。あるライバルは、Anthropicがそれをコピーしたと言う——Ahmad AwaisはCommand Codeのmodsを指し示し、その上で彼らのexample modを自ら書いており、その点は割り引いて受け止めるべきだ。「early access, APIs may change」という投稿は357のいいねを集めた。

すでにhookを書いているなら、監査、redaction、あるいはペインが欲しいなら、今すぐ一つ作るといい。契約がまだ書かれていないうちにチームへ配布するのは待った方がいい。fail openになる予算、MCP呼び出しの型の不一致、ラッパーの失敗が数日のうちにユーザーによって見つかったのも、この同じ開放性のおかげだ。

出典

よくある質問

Claude Code Modとは何か?
Modとは、その振る舞いがTypeScriptのhooksモジュールに宿るClaude Codeプラグインのことだ。このモジュールはエンジンのイベントに関数を登録し、Bun上でインプロセスに動き、あらゆる副作用は`$`オブジェクトを通る。
Claude Codeのhook、plugin、skill、Modの違いは何か?
シェルhookは決まった瞬間に呼ばれ、終了コードで答えるスクリプトだ。pluginはskill、agent、hook、MCPサーバーの束だ。skillは一致するプロンプトのときにモデルが読むプローズだ。Modは、あらゆるエンジンイベントをインプロセスでフックする、型付きのTypeScriptモジュールが一つ加わったpluginだ。
Claude Code Modはモデルからシークレットを隠せるか?
できる。ツール結果をawaitし、key・secret・tokenのパターンをスクラブして、redact済みのテキストを返す42行のModは、1hopあたり28msを加えるだけでトークンは消費しない。ただし画面上のトランスクリプトからは値を隠さない——それには別のModが要る。
遅いClaude Code Modはなぜfail openになるのか?
hooks workerは各hookに10秒の予算を与える。それを超えるか、throwしたhookはskippedと記録され、その下にあるチェーンが代わりに実行されるので、ガードされていたコマンドはそれでも実行される。Anthropicが提案する修正は、hookのreturnに宣言されたcatchだ。
Claude Code Modsは安全にインストールできるか?
まだ、標準では安全とは言えない。最初の48時間でインデックスされた31のModsのうち、14がホストプロセスを実行でき、13があらゆるtool callを見ており、検証手段は静的な足跡だけだ。Managed settingsは、ユーザーがインストールするものよりも上にAnthropicのsecurity defaultを置く。
今Claude Code Modを作るべきか?
すでにhookを書いていて、監査ログ、redaction、diffペインが欲しいなら、今すぐ一つ作るといい。チームへの配布は待った方がいい——この機能はアーリーアクセスで、APIは1週間で20から84のイベントに変わり、ドキュメントページもchangelogの行もまだない。

関連動画