AIコーディングエージェントに『自分ルール』を守らせる——メモリではなくフックで割り込ませる
『この種のファイルを触るときは必ず○○の手順を踏め』という自分ルールを、AIエージェントに確実に守らせたい。メモリやシステムプロンプトに書くだけだとモデルが忘れれば素通りする。PreToolUseフックで対象ファイルを判定してリマインダーを割り込ませるのが正攻法。permissionDecisionを付ける落とし穴も。
「この種のファイルを触るときは必ず ○○ の手順を踏め」という自分ルールを、AI コーディングエージェント(Claude Code など)に確実に守らせたい。メモリやシステムプロンプトに書くだけだと、モデルが忘れれば素通りする。確実なのはフックで割り込ませることだ。
事象
エージェントに独自ルールを守らせたい。例として「特定ディレクトリのファイルを編集する前に、必ず決まったチェックリストを読ませる」としよう。CLAUDE.md やメモリに「編集前に ○○ すること」と書いても、文脈が長くなるとモデルが見落として素通りすることがある。ルールの適用が確率的になり、たまに抜ける。
原因
メモリやシステムプロンプトは「読んでくれたら効く」ソフトな指示で、実行を強制する仕組みではない。確実に割り込ませるには、エージェントの実行基盤が持つ「フック」を使う。フックは、決まったタイミングで自動的に走る外部スクリプトのことだ。ここではツールの実行前に走るフック(PreToolUse)で、これから編集しようとしているファイルが対象かどうかを判定し、リマインダーを注入する。フックはモデルの気分に左右されず必ず走るのが強みだ。
解決策
Edit / Write 系ツールの PreToolUse フックを 1 本用意する。標準入力でツール呼び出しの JSON(tool_input.file_path など)を受け取り、対象パスに一致したときだけ、モデルに届くコンテキストを返す。正しい出力はこれだ。
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"additionalContext": "このファイルを編集する前に ○○ の手順を踏むこと"
}
}
additionalContext に入れた文字列が、モデルへ渡るリマインダーになる。フックは exit 0 で終える。対象外のパスなら何も出力せず exit 0(=無害・沈黙)。
// PreToolUse フック(Edit|Write|MultiEdit)
import { readFileSync } from "node:fs";
const data = JSON.parse(readFileSync(0, "utf8"));
const path = data.tool_input?.file_path ?? "";
if (!TARGET.test(path)) process.exit(0); // 対象外は黙って終了
process.stdout.write(
JSON.stringify({
hookSpecificOutput: {
hookEventName: "PreToolUse",
additionalContext: "編集前に ○○ の手順を踏むこと",
},
})
);
process.exit(0);
落とし穴:リマインダー目的なら permissionDecision を付けない
リマインダーを出したいだけなら、permissionDecision: "allow" を付けてはいけない。これを付けると、そのツール呼び出しを自動承認する意味になり、許可フローを勝手に緩めてしまう(本来なら確認が要る編集まで素通りさせる)。ただの注意喚起が目的なら additionalContext だけを返し、permissionDecision には一切触れないこと。
補足
- フックは「必ず走る」のが利点だが、ノイズにもなりやすい。対象ファイルに一致したときだけ鳴らし、それ以外は完全に沈黙させる(無出力)と、実用に耐える
- ツールを止めたいわけではないので、フックは常に
exit 0で返す。ブロックはしない - 出力スキーマ(
hookSpecificOutput/additionalContext)はエージェントのバージョンで変わることがある。導入時に最新のフック仕様を確認する
※ 本記事にはアフィリエイトリンクが含まれます。