Mod API リファレンス

next と実行の規則

出典: Claude Code 2.1.294 が書き出す型定義 Early access:リリースごとに変更される可能性あり ← 私家版 Claude Mods まとめ

next のプロパティ

プロパティ説明
next(e)後続のフック、Claude Code 本体の順に実行し、その結果を返す。呼び出すたびに後続の処理がもう一度実行される。
next.signalこの dispatch(イベント1回分の処理)が中止されたときに abort される AbortSignal。ユーザーが中断した、先行するフックが結果を返した、自分の制限時間を超えた、のいずれかで abort される。フックが開始した処理はこのシグナルで停止させる。
next.budget制限時間 { ms, remainingMs }。参照するたびに最新の値が返る。if (next.budget.remainingMs < 2_000) return next(e) のように使う。
next.originこの dispatch の発生元({ plugin, tier })。Claude Code 本体が発生させた場合は { plugin: "engine", tier: "core" } になる。値はホストが設定するため、プラグインが偽装することはできない。
next.eventこのイベントの名前。glob で登録したフックがイベントごとに処理を分けるときに使う。
next.is(pattern, e)e が指定したパターンのイベントかどうかを判定する型述語。
next.to(e, tier)途中のティアを飛ばし、指定したティアから処理を続ける。ティアとは、チェーンの順序を決める層のことで、自作の mod は user ティアに入る(権限を含む詳細は後述のティア表を参照)。組織が配布する managed プラグイン向けの機能で、user ティアのフックが組織のフックを飛ばすことはできない。
next.trace直近の next() 呼び出しで、後続の各フックがどのように処理されたかの記録。近い順に並び、最後が Claude Code 本体になる。
next.called / next.error.catch ハンドラの中で使う。called はフックが next を呼んだかどうか、error.kind は失敗の種類(throw / timeout / re-entry)を表す。

マッチャー

on(event, matcher, hook) の matcher には、e の一部の形を指定します。

書き方意味例
スカラー値=== で比較する{ tool: 'Bash' }
正規表現値を文字列として照合する{ command: /^p4 / }
配列いずれか1つに一致すればよい{ tool: ['Edit', 'Write'] }
オブジェクト入れ子のオブジェクトに部分一致する{ props: { origin: { kind: 'task-notification' } } }

{ startsWith: 'p4' } のような演算子はなく、このように書いても文字列には一致しません(型が付いている箇所では型エラーになります)。telemetry.* のイベントは名前で指定する必要があり、* や否定のパターンでは選択されません。

ティア(チェーンの順序)

ティアは、プラグインを誰が入れたかによってフックを分けた層です。同じイベントのフックは、表の上から順に、外側から内側へ入れ子になって実行されます。外側のティアほど権限が強くなります。

ティア内容権限
prepend管理者が配布する managed プラグイン(外側)最も強い
userユーザーがインストールしたプラグイン。自作の mod はこのティアに入る2番目に強い
append管理者が配布する managed プラグイン(内側)3番目に強い
builtinバイナリに同梱されたプラグイン4番目に強い
coreClaude Code 本体(最も内側)最も弱い

next.to(e, tier) は、組織が配布する managed プラグイン(prepend と append)のフックのための機能です。prepend のフックは append、builtin、core のいずれかを、append のフックは core を指定できます。user ティアのフックが組織のフックを飛ばすことはできません。

制限時間

名前値説明
ms10,000 ms1回の dispatch でフックが使える時間。next や $ の呼び出しの完了を待っている間は計測が止まるため、1分かかる $.model.complete を待っても消費されない。ただし $.clock.sleep の待ち時間は消費される。
catchMs1,000 ms.catch ハンドラに与えられる時間。ハンドラが呼ばれた時点から改めて計測する。
lingerMs5,000 msnext.signal が abort された後もフックが実行を続けてよい時間。超えると、終了していないフックとして報告される。

ストリーミングのフック(async generator)は、フック自身のコードが実行されている時間だけを計測します。turn.step では応答全体の合計、process.spawn ではチャンクごとに計測します。session.end ではチェーン全体で1つの短い制限時間を共有し、engine.create には制限時間がありません。

失敗と .catch(ガード)

失敗したフック(例外を投げた、制限時間を超えた、そのイベントで受け付けない形の値を返した)はスキップされ、チェーンはそのフックを除いて続行されます。そのため、拒否のためのガードが失敗すると、拒否は行われずに処理が通ってしまいます。拒否によって保護したいフックには、必ず .catch を付けてください。

on('tool.call', { tool: 'Edit' }, ($, e, next) =>
  /(^|\/)\.env(\.|$)/.test(e.file_path)
    ? { deny: `${$.plugin.name}: ${e.file_path} は保護されています` }
    : next(e),
).catch(($, e, next) =>
  next.called ? next(e) : { deny: `${$.plugin.name}: ガードの処理に失敗しました` },
)
  • next.called が true のとき、next(e) は先に実行した呼び出しの結果を返すだけで、処理が二重に実行されることはない。そのため、ガードは next を呼ぶ前に判定する。
  • tool.check では next(e) は判定結果を読み出すだけで何も実行しないため、ハンドラは常に { decision: 'deny' } を返してよい。
  • ハンドラは再入(re-entry)のときにも呼ばれる。再入とは、フック自身の $ 呼び出しから同じイベントが発生した場合のことで、このときフック本体は実行されない。next.error.kind は 're-entry'、next.called は false になる。呼び出した名前空間の処理から発生した場合は next.error.cause が 'lent' になる。再入時のハンドラ内で $ を呼ぶと reject される。
  • claude plugin validate は、戻り値で拒否できるイベントのフックを gating hook with .catch: または gating hook without .catch: として列挙する。これは警告ではなく、事実の報告である。

拒否を表す戻り値はイベントごとに異なります。tool.call、agent.spawn、config.set、prompt.mention は { deny }、prompt.submit は { drop }、command.run は { text }、agent.offer は { isOffered: false }、plugin.register は { refuse } です。

絞り込みの条件に一致する行がありません。