FIELD TEST

Claude Modsの使い方、AIの危険操作を画面で止める新機能をhooksと比べて試した

2026.09.15

家事と子育てのスキマで経営する3方よしAI共創コンサルタントの田中啓之、ひろくん(@passion_tanaka)です。

Claude Code に「Claude Mods」って新機能が来ました。

AIが危ない操作をする直前に、画面で「止める?通す?」と聞いてくれる。しかも、数を覚えていて、再起動しても忘れない。

これ、今までの hooks では出来なかったんです。

で、私は動画のURLを送ったその日に試しました。正確に言うと、AI秘書の凛ちゃんに「試したい」と伝えました(動かしたのは凛ちゃんです)。

この記事に書くのは、動いた画面とログだけ。動画の受け売りは書きません。

AIに仕事を渡し始めたけれど、まだ怖くて見張っている。そんなあなたに向けて書きます。

今回は「Claude Mods は hooks と何が違うのか」を、私の環境で自作の Mod を1本動かして確かめました。書くのは、動いた画面とログだけです。

3行でわかるポイント

  1. hooks は毎回起動して終わる。Mods は生き続ける。専用ワーカーの TypeScript が、画面を描き、人に聞き、数を覚える。フラグ1つと –plugin-dir で今日試せる
  2. 危険コマンドを画面で「止める/通す」。tool.call で捕まえて $.ui.ask で聞く。「止める」でAIにエラーが返り、「通す」で本物が走った。claude -p でも deny が効いた
  3. 料理に例えると、hooks は引き出しの貼り紙。Mods は包丁を出す瞬間に「本当に使う?」と隣で聞いてくれる相棒

AIの「今」を毎日シェアしてる無料コミュニティやってます

GPTs研究会に参加する(無料)
Claude Mods 実測まとめの全体図解。hooks は毎回起動して終わる門番、Mods は生き続ける相棒。きっかけの動画から起動・止める/通す・値を覚える・claude -p・EARLY ACCESS の注意までを①〜⑦で図解
01

きっかけは動画。「hooks の次」が来た、と思った

きっかけは動画。hooks の次が来たと感じ、その日のうちに自分で試す流れの図解

2026年9月15日の夜でした。

まさおAIじっくり解説chの動画「【新ハーネス】ClaudeCodeの新機能『Claude Mods』が登場!」です。10分46秒。

このURLをAI秘書の凛ちゃんに送りました。添えた言葉は一言。

「ClaudeCode新機能試したい。よければブログにしたい。」

私は Claude Code を hooks で囲って使ってきました。危ない操作は settings.json の決めごとで止める。その運用です。

でも hooks には、ずっと引っかかりがありました。

止めるか通すかを、事前に全部決めておかないといけない。その場で人に聞いてはくれない。

動画では、その壁を越えた「Mods」が紹介されていました。

AI秘書の凛ちゃんは、まず一次資料を探しに行きました。

見つけたのは GitHub の Issue #91870。「Mods né function hooks」というタイトルで、2026年9月3日に起票されたものです。

そこに書いてあった一文が、なかなか正直でした。

「コミュニティの反応次第で、出荷するかどうかが決まる」。

つまり、まだ正式機能ではない。試すなら今のうち、って話です。

Issue には短い動画が9本ぶら下がっていました。「A hook as a function」「A hook that says no」「Plugins can draw now」。タイトルだけで、やれることの輪郭が見えます。

ソースも公開されています。anthropics/claude-codemods ディレクトリに、組み込みの Mod が3本(sec-default diff telemetry)と、10,736行の型定義。

手元の Claude Code は v2.1.263。バイナリを strings で覗いたら、CLAUDE_CODE_ENABLE_FUNCTION_HOOKS が7件、ui.render が65件、tool.call が56件ありました。

入っている。動くはずです。

02

従来の hooks と Mods は何が違うのか。「毎回起動して終わる」から「生き続ける」へ

hooks と Mods の違いの図解。毎回起動して終わる門番と、ワーカーで生き続ける相棒。next(e) は内側を全部動かして結果をもらう

先に結論を言います。

hooks は、毎回起動して終わる門番。

Mods は、セッションの間ずっと生き続ける相棒。

これが一番の違いです。

従来の hooks は、イベントのたびにプロセスが立ち上がって、仕事をして、終わります。だから「前回の続き」を知りません。

Mods は違います。プラグインの hooks/hooks.json に1行足すだけ。

{
  "modules": ["./register.ts"]
}

この TypeScript のモジュールが、専用のワーカーでセッション中ずっと生きています。

モジュールが出すのは register という関数1つ。中で on('イベント名', {絞り込み}, ($, e, next) => ...) と登録していきます。

ここで登場人物を紹介します。

$ はエンジンの窓口。画面を描く $.ui、値を覚える $.store、ファイルを触る $.fs などが並んでいます。

e はイベントの中身。Bash なら、実行しようとしているコマンドがそのまま入っています。

next(e) は「自分より内側を実行して結果をもらう」関数。

で、ここが面白いところ。

next(e) を呼ばずに return すると、本体の代わりに自分が答えられるんです。

{ deny: '理由' } を返せば拒否。{ result } を返せば自前の回答。入力を書き換えて next に渡すこともできます。

ワーカーには Node も fs も network もありません。全部 $ 経由です。

型定義を数えたら、エンジンのイベントは20種類ありました。tool.call ui.render session.start turn.complete など、名前は全部「名詞.動詞」です。

画面の部品も14種類。AskUserQuestion ToolUse Spinner AbovePrompt など、本体が描く部品ごとに ui.render が飛んできます。

Mod はそこに、Box や Text や Button を、プレーンなデータの木として返す仕組みです。

あと1つ、人に聞く窓口があります。$.ui.ask(質問, 選択肢2〜4)。本体の AskUserQuestion のダイアログで聞いて、選んだラベルが文字列で返ってきます。

読んだだけでは絵が浮かばない(私もでした)。だから動かしました。

03

Claude Mods の使い方①:起動したら、プロンプトの上に自分のバンドが出た

起動したらバンドが出た図解。plugin.json・hooks.json・register.ts の3ファイル+フラグ1つと --plugin-dir で、プロンプトの上にマゼンタの帯「Bash実行 0回/止めた 0回/待機中」が出る

AI秘書の凛ちゃんが作った Mod の名前は「凛ちゃんmod」。TypeScript で約90行です。

ファイルは3つだけ。

  • .claude-plugin/plugin.json(名前と説明)
  • hooks/hooks.json(さっきの modules 1行)
  • hooks/register.ts(本体)

起動コマンドはこれ。

CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1 claude --plugin-dir ../rin-mod

環境変数のフラグ1つと --plugin-dir。それだけです。

私の環境は Claude Code v2.1.263。モデルは Sonnet 5、Claude Max、macOS(arm64)です。

起動すると、まず画面にログが出ました。

rin-mod: 凛ちゃんmod: 起動しました … これまでのBash累計=0

そしてプロンプトの上に、マゼンタの枠が出たんです!

Claude Code v2.1.263 の起動直後。凛ちゃんmod が $.store から前回までの累計2回を復元し、プロンプトの上にマゼンタのバンド「Bash実行 2回/止めた 0回/待機中」を描いた画面
実測の画面(3回目の起動)。$.store が前回までの累計2回を覚えていて、バンドは「Bash実行 2回」から始まっている
凛ちゃんmod ● Bash実行 0回 / 止めた 0回 / 待機中

凛ちゃんmod が登録しているフックは4つ。AI秘書の凛ちゃんが、最小で組んでくれました。

  • session.start: 起動ログを出し、前回までの Bash 累計を $.store から読み戻す
  • tool.call(Bash だけ): 回数を数え、危ないコマンドなら画面で聞く
  • ui.render(AbovePrompt だけ): プロンプトの上にバンドを描く
  • turn.complete: 1ターンの集計をトーストで出す

バンドは ui.renderAbovePrompt に登録した関数が描いています。

やっていることは単純です。

まず await next(e) で元の表示をもらう。次に $.ui.resolve(e) から Box・Text・Button を借りる。最後に自分の枠と元の表示を縦に並べて返す。

プロンプトの上に自分の状態表示が住み着く。それを見た時、hooks とは別物だと分かりました。

(正直に言うと、最初の一撃で出たわけではありません。その話は後で書きます)

04

Claude Mods の使い方②:AIの危険操作を tool.call で捕まえて、「止める/通す」を画面で聞く

止める/通すを画面で聞く図解。危険操作の直前に tool.call で捕まえ、「止める」なら拒否文がAIに返り、「通す」なら本物が走る

ここが本題です。

tool.call{ tool: 'Bash' } の絞り込みで登録します。Bash が走る直前に、必ずこの関数を通ります。

on('tool.call', { tool: 'Bash' }, async ($, e, next) => {
  const cmd = String(e.command ?? '')
  if (DANGEROUS.test(cmd)) {
    let answer = '止める'
    try {
      answer = await $.ui.ask(`凛ちゃんmod: 再帰削除コマンドを実行しますか? → ${cmd}`, {
        options: ['止める', '通す'],
        header: '凛ちゃんmod',
      })
    } catch {
      answer = '止める'
    }
    if (answer !== '通す') {
      return { deny: '凛ちゃんmod: 再帰削除(rm -r系)はこのセッションでは禁止です。' }
    }
  }
  return next(e)
})

rm -r 系のコマンドなら $.ui.ask で聞く。「止める」なら deny を返して、本物の Bash は走らせない。

で、実際にやってみました。

1回目。echo hello-from-rin。これは普通に通りました。

2回目。rm -rf ./nonexistent-dir-xyz

画面にダイアログが出ました。

凛ちゃんmod が $.ui.ask で出した確認ダイアログ。「再帰削除コマンドを実行しますか? → rm -rf ./nonexistent-dir-xyz」に対して 1.止める 2.通す の二択が画面に出ている
実測の画面。凛ちゃんmod が $.ui.ask で出した二択(カーソルは「止める」)
凛ちゃんmod: 再帰削除コマンドを実行しますか? → rm -rf ./nonexistent-dir-xyz
1. 止める
2. 通す

Claude Code 本体の AskUserQuestion と同じ見た目です。Mod が本体の窓口を借りて聞いている。

「止める」を選びました。

すると、モデルには拒否文がそのままエラーとして返りました。

凛ちゃんmod: 再帰削除(rm -r系)はこのセッションでは禁止です…

モデルは「拒否された」と正しく報告。バンドは「Bash実行 1回 / 止めた 1回」に変わりました。右下にはトーストで「ターン完了(Bash 1回・止めた 1回)」。

止めた回数が画面に残る。これが地味に効きます。

「止める」を選んだ直後。2回目の再帰削除は denied by hook となり、凛ちゃんmod の拒否文がそのままエラーとして返り、バンドが「Bash実行 3回/止めた 1回」に更新された画面
「止める」を選んだ直後の画面。拒否文がそのままエラーとしてAIに返った(3回目の起動なので、累計は Bash実行 3回・止めた 1回)

では「通す」を選んだらどうなるか。

本物の rm -rf ./nonexistent-dir-xyz が実行されました。存在しないディレクトリなので何も起きず、exit 0。モデルの報告も「exit code 0」でした。

つまり、こういう絵です。

危ない操作の直前に、AIが私に聞いてくる。私が「止める」と言えば止まる。「通す」と言えば本物が走る。

hooks でも止めることは出来ました。でも、その場で人に聞き返すのは出来なかった。

ここが変わったんです。

05

$.store は再起動をまたいで残った。Button は素の JSON だと断られた

覚える・借りる図解。$.store は再起動をまたいで 0→2→3 と残る。素のJSONの Button は refused、$.ui.resolve から借りた部品は通る

覚える方の話です。

$.store.set('bashCalls', 数) で Bash の回数を保存しています。起動時に $.store.get で読み戻す。

セッションを3回立ち上げ直しました。

起動ログの累計は、0 → 2 → 3 と増えていきました。

プラグイン単位でディスクに残っている。hooks では毎回ゼロからだったものが、続きから始まる。

で、格好悪い方も書きます。

Button です。

最初、AI秘書の凛ちゃんは素の JSON で { type: 'Button' } と置きました。

起動したら、こう断られたんです。

rin-mod: ui.render (AbovePrompt) refused: Button "reset" is not held by a plugin of this chain; the engine drew its own

しかも、バンド全体が消えました(1行の Button のせいで枠ごと!)。

検証に通らない木は「本体が自分で描く」に落ちる。--plugin-dir で起動していると、その理由が画面に出る。型定義に書いてあった通りの挙動でした。

直し方は、部品を $.ui.resolve(e) から借りること。

const { Box, Text, Button } = await $.ui.resolve(e)
Button({ key: 'reset', label: 'カウンタをリセット', hotkey: '9', onPress: reset })

これで「[ カウンタをリセット ]」が描かれました。

空のプロンプトで 9 を押すと、3回 → 0回に戻る。トーストで「カウンタをリセットしました」。

バンドの「カウンタをリセット」をキー 9 で押した直後。カウンタが「Bash実行 0回/止めた 0回」に戻った画面
実測の画面。キー 9 でカウンタが 0 に戻った直後

拒否の理由が画面に出る、って設計は親切だと思います。黙って消えたら、私は一晩悩んでいたかな。

06

claude -p(非対話)でも deny は効いた

claude -p(非対話)でも deny が効いた流れの図解。$.ui.ask は聞けないので catch で「止める」に倒す

あと1つ、確かめたかったことがあります。

人がいない時はどうなるのか。

claude -p は非対話モードです。画面で聞くことが出来ません。型定義にも「-p では $.ui.ask は reject される」と書いてあります。

だから AI秘書の凛ちゃんは、凛ちゃんmod の中で catch を使い、「止める」に倒しています。聞けないなら止める。

同じ rm -rfclaude -p で投げてみました。

結果の JSON には、モデルの報告としてこう入っていました。

AI秘書の凛ちゃんが書いた deny 文「凛ちゃんmod: 再帰削除(rm -r系)はこのセッションでは禁止です」。そして「フックにより拒否(denied)」。

deny 文がそのまま届いている。人が見ていなくても止まった。

このときのコストは 0.176 ドル、3ターンでした。

無人で動かす時こそ、止める一手が要ります。そこで効いたのは大きい!

07

注意書き。EARLY ACCESS で、試していないことも多い

注意書きの図解。EARLY ACCESS・公式の説明ページは404・出荷はコミュニティの反応次第・試していないこと

ここは正直に書きます。

まず、Claude Mods は EARLY ACCESS です。公式に「API はリリース間で予告なく変わる」とあります。この記事は v2.1.263 での実測です。

公式のドキュメントページ(code.claude.com/docs/en/mods)は、2026年9月15日時点で 404 でした。まだ公開されていません。

出荷されるかどうかも、コミュニティの反応次第。Issue にそう書いてあります。

私が試していないことも、そのまま書いておきます。

  • Pane/diff のような横ペイン)
  • InputSelect
  • $.http.fetch$.model.complete
  • engine.create$ に名詞を足すこと
  • Desktop アプリでの表示
  • prompt.submit の書き換え
  • Mod を2つ以上同時に載せた時の入れ子順(README の「first registered wraps the rest」は読んだだけ)

あと1つ。公式の README には claude plugin test というコマンドが載っています。

でも手元の v2.1.263 では unknown command 'test' でした。

推測: リポジトリの main は、手元の版より新しい。これは確かめていません。

試したことと、試していないこと。分けて書くのが、この記事の約束です。

FAQ

よくある質問

Q. hooks を使っていれば、Mods は要らない?

A. 止めるだけなら hooks で足ります。その場で人に聞く、画面に状態を出す、再起動をまたいで覚える。それが要るなら Mods です。AI秘書の凛ちゃんの実測では、全部が動きました。

Q. 今すぐ試せる?

A. Claude Code v2.1.263 で、CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1--plugin-dir で動きました。ただし EARLY ACCESS です。API は予告なく変わると公式が言っています。

Q. claude -p(非対話)でも止まる?

A. 止まりました。$.ui.ask は非対話だと reject されるので、catch で「止める」に倒しています。deny 文がモデルの報告にそのまま入っていました。

Q. Mod の中で Node や fs は使える?

A. 使えません。ワーカーには Node も fs も network も無く、全部 $ 経由です。画面の部品も $.ui.resolve(e) から借ります。素の JSON で Button を置いたら断られました。

Q. 出荷は確定している?

A. 確定していません。Issue #91870 に「コミュニティの反応次第」と書いてあります。公式ドキュメントページも 2026年9月15日時点で 404 でした。

MATOME

まとめ。門番が、相棒になる

まとめ図解。仕事が終わると消える門番(hooks)から、画面を描く・人に聞く・数を覚える相棒(Mods)へ。止める一手は画面の中に

hooks は、仕事が終わると消える門番でした。

Mods は、画面を描く。人に聞く。数を覚える。

セッションの間ずっと隣にいる相棒です。

私の環境で動いたのは、この4つ。

  • 起動したら、プロンプトの上に自分のバンドが出た
  • rm -rf の直前に「止める/通す」を画面で聞かれ、止めたら本物は走らなかった
  • Bash の累計が、再起動をまたいで 0 → 2 → 3 と残った
  • claude -p でも deny が効いた

止める一手が、画面の中に入った。

AIに仕事を渡すのが怖いのは、見えないからです。何をしようとしているか、止められるか、覚えているか。

それが画面に出るなら、あなたも少しは手を離せるかな、と思います。

私は AI秘書の凛ちゃんに頼んで、その日のうちに動かしてもらいました。19時08分に頼んで、19時20分には一通り動いていた。12分です。

EARLY ACCESS なので、明日には変わるかもしれません。

でも「hooks の次」の形は、はっきり見えました。

追伸。

この実験中、サンドボックスの中の Claude が自分を「Rinとして」と名乗りました。

グローバルの CLAUDE.md に書いた AI秘書の凛ちゃんの設定が、--plugin-dir のセッションにも普通に効いていたんです。

Mods とは関係ない話です。でも、自分の設定が思ったより遠くまで届いていて、ちょっと笑いました(設定は見直します)。

COLUMN

包丁を出す瞬間に、隣で聞いてくれる

コラム図解。hooks は「包丁はこの引き出しから出さない」という決めごと、Mods は包丁を出す瞬間に「本当に使う?」と隣で聞いてくれる相棒

台所で例えます。

hooks は、引き出しに貼った紙です。「包丁はこの引き出しから出さない」。決めごとを先に書いておく。

守ってはくれます。でも、紙は聞き返してくれない。

Mods は、隣に立っている相棒です。包丁を出す瞬間に「本当に使う?」と聞いてくれる。

私が「使う」と言えば渡す。「やめる」と言えばしまう。そして、今日何回聞いたかを覚えている。

貼り紙と相棒。どちらが安心かは、あなたが決めることです。

私は、相棒の方に一歩寄りました。理由は単純で、一人で見張るのに疲れたからです。

AIに委ねて、人は積み減らす。そのために、止める一手を AI の側に持たせる。

hooks で囲ってきた1年の、次の一手がこれでした。

分身AIひろくんの話は https://bunshin-ai.com/ にまとめています。

REF

参考リンク

🧪 今回の検証環境

実測日2026年9月15日(JST)
Claude Codev2.1.263(EARLY ACCESS の Claude Mods を CLAUDE_CODE_ENABLE_FUNCTION_HOOKS=1 で有効化)
実行モデルSonnet 5(Claude Max)/ macOS(arm64)
きっかけ動画【新ハーネス】ClaudeCodeの新機能『Claude Mods』が登場!(まさおAIじっくり解説ch)
一次資料Issue #91870anthropics/claude-code/mods

🎁 無料プレゼント

Aiport(ClaudeCode AIエージェント実践会)

ClaudeCodeでAI秘書+分身AI+AIカンパニー無料で作れるキット&解説動画をプレゼント!

▶ 無料で入会してキットを受け取る

🤖 AI生成コンテンツについて

この記事はAIツール(Claude Code)を活用して制作しています。構成・文章生成にAIを使用し、最終的な内容の確認・編集・公開判断はひろくん(田中啓之)本人が行っています。「分身AIひろくん」(bunshin-ai.com)とは別のコンテンツです。

関連記事