この記事はもともと EthereaLogic.ai に掲載されました。
この連載の最初の記事では、5層からなるガバナンス・スタックを紹介し、1つの「荷重負担(ロードベアリング)」になる主張を行いました。すなわち、ドキュメントの中に存在する層は必要であり、一方で、コードとして動作する層がシステムの信頼性を生み出す、ということです。この記事では、最も効果が大きいコード層――Claude Hooks によるランタイム強制――の中に踏み込み、実際にエンジニアリングチームが作る必要があるレベルの細部で、それがどのように見えるのかを示します。
最初の記事の主張は、CLAUDE.md または AGENTS.md 内の指示は、エージェントの作業メモリから無視される、推論の対象になる、またはコンテキストウィンドウによって文脈外に押し出されることができる、しかし「ステータス 2 で終了するフック」はできない、というものでした。この記事の主張は、フックという抽象的なアイデアを、実際のサブエージェントのトラフィック下で確実に成立する「番人(ガード)」に変えること自体が、独自のエンジニアリング分野である、ということです。そこには小さいながらも明確な一連のパターン、失敗モード、テストがあります。フック層に到達したほとんどのチームは、このエンジニアリング分野を過小評価しています。本記事で示す実証的な根拠は、その過小評価のうちの1つから得られました。
層4は、エージェントの意図と、ツール呼び出しの効果の間に位置します。フックは標準入力(stdin)でJSONとしてツールペイロードを受け取り、許可するかブロックするかを判断し、ブロック時にはステータス2で終了します――これは Claude Code のハーネスが「ハードな拒否」として扱い、その理由がモデルに戻される唯一の終了コードです。
フェイラーモード:ドキュメントでは閉じられない
エージェント型のコーディング・ワークフローを運用しているチームは、いずれ必ず同じ失敗モードに遭遇します。つまり、プロジェクトのドキュメント上に存在するルール、エージェントの指示の中にあるルール、ユーザーの永続メモリにあるルールであるにもかかわらず、しかも高速に動くサブエージェントによって、なお違反されてしまうルールです。そのルールは曖昧ではありません。ルールは変わっていません。エージェントはそれを事前に読みました。それでも次の違反を防げないのは、これらの場所が「実行ポイント」ではないからです。これらは「意図(インテント)のポイント」なのです。ツール呼び出しこそが実行ポイントです。
2026年4月11日、太平洋時間19:56に GovForge プロジェクトで、自動化された /implement のサブエージェントがコミット 3f3b7f9 を生成し、それをそのまま main にプッシュしました。「main への直接プッシュ禁止」というルールは、AGENTS.md に書かれているだけでなく、プロジェクト憲法の原則 P1(「保護ブランチはハードな境界である」)としても記載されており、さらにユーザーのメモリとして feedback_no_direct_push_main.md にも保存されていました。これらの場所はすべて、サブエージェントの親コンテキストによって読み込まれていました。それでもプッシュは行われました。なぜなら、次の3つの条件が積み重なって有効になったからです。プロジェクトの pre-tool-use.js フックが、リポジトリ内に「空のスタブ」として存在しており、同じ構成の別プロジェクトのスキャフォールドをそのままコピーしただけだったこと。加えて .claude/settings.json には PreToolUse の登録がなく、仮にフックが空でなかったとしても実行されない状態だったこと。そして最後に、オペレーターのホームレベルの Claude Code 設定に skipDangerousModePermissionPrompt: true が入っており、通常なら破壊的な操作を捕捉するはずだった確認ダイアログが抑制されていたことです。49分後、コミット b404fbe により、空のスタブが実際の保護ブランチ用ガードに置き換わり、.claude/settings.json の中で PreToolUse:Bash として登録されました。それ以降、この同種の試みは毎回、ステータス2で終了しています。
指示は存在していました。指示だけでは不十分でした。強制(enforcement)を行うのはフックです。
PreToolUse フックとは実際に何か
Claude Code のフックは、ハーネスがツール呼び出しの前後で呼び出す「実行可能ファイル」です。プロトコルは、3文で説明できるほど小さいです。ハーネスはツール名とツール入力を記述したJSONペイロードを書き込み、それをフックの stdin に渡します。フックは許可するかブロックするかを決め、許可するならステータス0で、ブロックするならステータス2で終了します。ブロックの場合、ハーネスはフックの stderr を読み取り、それをモデルに拒否理由として提示します。これにより、エージェントは次のターンでそれを前提に推論できる文章による説明を得ます。
この最後の細部は、聞こえる以上に重要です。フックは無言で強制するものではありません。ブロックされた状態になっているモデルへ向けて、自然言語で自分自身を説明する強制です。つまり、同じフックが失敗モードを閉じるだけでなく、代わりに何をすべきかをエージェントに教える――多くの場合、同じターンの中で――ということになります。GovForge のガードでは、stderr メッセージが、ルールが由来するポリシーファイル名を示し、ブロックされた具体的なサブコマンドを示し、理由を名指しし、モデルに試すべき修正を正確に伝えます。すなわち、chore/feat/fix ブランチを作成し、そこでコミットをリトライし、PR を開くことです。フックが着地すると、ガードにぶつかったエージェントは通常、オペレーターの介入なしに次のメッセージで解決します。
登録は .claude/settings.json の小さなブロックです:
{
"hooks": {
"PreToolUse": [
{
"matcher": "Bash",
"hooks": [
{ "type": "command", "command": "node .claude/hooks/pre-tool-use.js" }
]
}
]
} }
}
これがインターフェースのすべてです。matcher は、どのツール呼び出しにフックを適用して検査するかを選びます――ここでは Bash です。すべての git 操作は Bash ツールを通じて流れるためです。command は実行ファイル名(実行コマンド)を指定します。SDK はありません。デーモンもありません。走って判断して終了する、短いスクリプトが1本あるだけです。
ガードが捕捉しなければならないもの
難しいのはプロトコルではありません。難しいのは、「main への直接コミットとプッシュをブロックする」というものが、見た目よりもはるかに広い表面(サーフェス)を持っていることです。
素朴な実装では、Bashコマンドのリテラルトークン列 git commit または git push を検査し、main という語があるかを確認して、両方が含まれていれば2で終了します。しかし、このガードは初日から有能なエージェントに対して破られます。GovForge のガード(320行)の中で、迂回の6つのカテゴリが封じられています:
Refspecの書き換え。 git push origin main は明白な形です。git push origin HEAD:main と git push origin +refs/heads/master は、異なる構文ではあるものの同じ操作です。ガードは refspec を解析し、先頭の + を取り除き、コロンで分割し、refs/heads/<branch> を正規化したうえで、デスティネーション側を PROTECTED_BRANCHES セットに対してチェックする必要があります。ソース側は無関係です。問題になるのは、リモート上のどこにコミットが着地するかだけです。
保護ブランチに対する暗黙の refspec。 refspec を指定せずに git push を実行すると、push.default と設定された upstream に応じて、現在のブランチまたは upstream ブランチを更新できます。もし HEAD が main 上にあるなら、現実的な結果はいずれもコミットが main に着地します。ガードは git rev-parse --abbrev-ref HEAD を呼び出し、明示的な refspec がない場合に保護された現在ブランチをブロックとして扱うことで、各設定を個別にモデル化することなく、push.default のあらゆる構成の範囲を閉じています。
広範モードのフラグ。 git push --all と git push --mirror は、オペレータが特定のブランチ名を挙げなくても保護ブランチを更新し得ます。--all は、ローカルの全ブランチをプッシュします。main がローカルにあればそれも含まれます。--mirror はさらに広く、リモートが従来知らなかった ref も同期します。どちらも、オペレータの意図が曖昧であり、失敗の挙動が非対称であるためという理由で無条件にブロックされます。
git commit ではない、コミットを生成するサブコマンド。 git merge、git rebase、git cherry-pick、git revert、git am、git pull はすべて、git commit を直接呼び出さずに、HEAD 上に新しいコミットを生成します。commit だけに一致するガードでは、これらのすべてが通ってしまいます。GovForge のガードは明示的な COMMIT_PRODUCING_SUBCOMMANDS セットを保持し、HEAD が保護ブランチ上にあるとき、このセットとのマッチを git commit と同等に扱います。git pull がセットに入っているのは、それが fetch に続いて merge または rebase を行うためであり、まさに HEAD が保護されているときにブロックするためにガードが存在する失敗経路だからです。
ネストしたシェルによる迂回。 空白文字でトークン化する方式では、bash -c "git push origin main" を3トークンのコマンドとして扱い、最初のトークンは git ではなく bash になります。素朴なトークンチェックでは発火しません。GovForge のガードはネストしたシェルのパターンを認識し、インラインのペイロードを抽出して、病的なネストを上限付きにするため深さ制限4で内側のコマンドに対してフルの評価器を再帰的に再実行します。認識される形式は bash -c '...'、sh -c '...'、zsh -c '...' — これらのシェルが公開する実際の -c フラグ — に加えて、現在リストされているシェルはいずれもサポートしていないものの、エージェントがもっともらしく幻覚(hallucinate)し得る --command= スタイルのフラグに対する防御的マッチも含みます。ガードは、シェルにやらせるのではなく、パターンを最初から拒否します。ブロック時には、stderr のメッセージが理由に (via nested shell) を追記し、どの層がそれを捕捉したのかをモデルが正確に見られるようにしています。
連結コマンド。 git status && git push origin main は単一のBash呼び出しですが、論理的には2つの操作です。ガードは、他の検査の前にサブコマンドを &&、||、;、改行、および単一のパイプ(|)で分割し、各断片を独立に評価します。最初の断片は通過します。git push origin main の断片が呼び出し全体をブロックします。| を区切りとして扱うのは重要です。エージェントは探索的なシェルコマンドをパイプで組み立てることがよくあります。ガードは、パイプが意味論的に有意かどうかを推測しようとせず、両側を評価します。
これら6つのカテゴリの形状は、フック工学で何が難しいのかを教えてくれます。難しいのはポリシーではありません。ポリシーは一文です。表面を列挙し、見かけ上はポリシーに似ているが実際には別のコマンドであるパターンを見つけ、そしてそれぞれが線のどちら側にあるかを判断することです。pre-tool-use.js の320行のほとんどが、その列挙です。
各カテゴリは一見するとポリシーに似ていますが、構文上は別のコマンドです。6つすべては、明示的なセットチェック、再帰的評価、またはコマンド分割によって、ガード対象の断片が着地する前に封じられています。
Why The Hook Is Not A Security Boundary
GovForge のガード内のコメントには、これが明示的に書かれています。フックは Claude のハーネスに対するアドバイザリであり、セキュリティ境界ではありません。ハーネスの外で動く意欲ある人間は、いかなる方法でもそれを打ち破れます。たとえば、ペイロードをbase64でエンコードする、g を git の別名にする、.git/HEAD を直接改変する、別の作業ツリーを持つ兄弟クローンを用意する、といった具合です。ガードはそれらへの対策を試みません。対策しようとすると実装が膨れ上がり、「閉じ込められている」という誤った安心感を生むことになります。
フックが防ごうとしている脅威は、より狭く、しかし重要です。ハーネスのもとで高速に動作するエージェントで、skipDangerousModePermissionPrompt: true が有効になっている場合(多くのオペレータがこの設定を使います。持続的な自動化下ではプロンプトが騒がしすぎるためです)、書かれたルールに違反する破壊的呼び出しを行うことです。これこそが GovForge のインシデントで起きた事例です。これが、ガードが不可能にしようと設計された事例です。ガードの価値は、敵対者に対して弾丸のように完全無欠であることではなく、特定の実行時環境における特定の失敗モードを閉じることにあります。
この区別を明示しておく価値はあります。なぜなら、代替となる捉え方――「もし執念深い攻撃者がそれを回避できるのなら、そんなものは無意味だ」――だと、チームはフック層をまるごとスキップしてしまい、これはガバナンスのスタック全体で最もインパクトの大きい単一のミスだからです。正しい捉え方は、エンジニアがすでに適用している次のものと同じです。すなわち、lintルール、型チェック、pre-commitフックに対して行っている考え方です。これらのツールが守るのは、悪意ではなく、16時に疲れている開発者という現実的な失敗モードです。現実的な失敗モードが共通しているからこそ、これらは“支える構造(load-bearing)”になります。
テストはもう半分
入力が正しいときに2で終了し、正しい入力では0で終了するフックは必要ですが、それだけでは不十分です。GovForgeのインシデントで証明されたもう一つのことは、フックは黙って劣化しうるという点です。3f3b7f9当時の空のスタブ状態は、運用者の視点では動作するフックと見分けがつきませんでした。ファイルは存在し、パスは正しく、プロジェクトは管理されているように見えました。実行時の差――ロジックが存在しないため、あらゆるペイロードでファイルが0で終了していた――は、破壊的な呼び出しが実行されるまで目に見えませんでした。ビルドシステムも気づきませんでした。CIも気づきませんでした。フックが“見えない”ことが失敗だったまさにそのとき、フックは見えなかったのです。
そのギャップを埋める回帰テストがtests/test_pre_tool_use_hook.pyで、354行にわたる22のテスト関数があります。pytestのパラメータ化により32件として収集される形に拡張されており、フックをエンドツーエンドで、ノードのサブプロセスとして実際の一時的なgitリポジトリ上で実行します。最初の2つのテストが、空スタブの失敗モードに対する“支える(load-bearing)”ものです。T-1は、フックファイルが空でないこと、"use strict"を含むこと、そしてどこかにprocess.exit(2)が含まれていること――という3つのプロパティを検証します。これらはいずれも、フックが正しく動作している版が満たし、空スタブは満たしません。T-2は、.claude/settings.jsonがPreToolUse:Bashとして引き続きフックを登録していることを検証します。これら2つのテストは、元のインシデントの両方の有効化条件――空ファイルと登録の欠落――が、出荷される前にCIによって検知されることを保証します。
残りのテストは、上で列挙した“表面”をカバーします。mainへの明示的なrefspecによるpush、HEAD:mainへのpush、--allおよび--mirrorの広範なモード、保護ブランチ上でのプレーンなpush、保護ブランチ上でのコミット、保護ブランチ上でのすべてのコミット生成サブコマンド、保護ブランチを介したネストされたシェルの迂回(bash -c、sh -c、およびzsh -cファミリ)、途中に保護ブランチ操作を含む連結コマンド、git status | git push origin mainのような単一パイプ合成、そして多数のネガティブケース――フィーチャーブランチへのpush、main上での読み取り専用gitコマンド、gitではないコマンド、Bash以外のツール呼び出し、空のstdin――のすべてが、変更されずに通過しなければなりません。各テストはtmp_path配下に新しいgit initリポジトリを生成し、ハーネスが送るJSONペイロードを使ってフックをサブプロセスとして呼び出します。モックは一切ありません。このテストは、ハーネスが通るのと同じコードパスを実行します。
事実
以下は、GovForgeリポジトリおよび、2026年4月11日のインシデントを対象とする公開された同期記録から抽出した、検証済みの計測事実です(2026年5月4日に検証)。これらはGovForgeプロジェクトの範囲内で読み取られるべきものです。
.claude/hooks/pre-tool-use.jsにある保護ブランチガードは320行のJavaScriptで、外部のnpm依存関係はありません。必要なのはNodeのビルトインのみ(node:child_process、node:fs)です。.claude/settings.jsonにおいてPreToolUse:Bashとして登録されています。tests/test_pre_tool_use_hook.pyの回帰テストスイートは354行で、pytestのパラメータ化により32件として収集される22個のdef test_関数を含みます(この「32テスト」という数字は、本シリーズ最初の記事に引用されています)。一時的なgitリポジトリに対して、ノードのサブプロセスとしてフックを実行します。そのうち2つの関数は、空スタブの失敗モードがCIによって捕捉されることを検証します。すなわち、フックファイルが空でないことと、PreToolUse:Bashが登録されていることです。- 2026年4月11日のインシデント――自動化された
/implementサブエージェントがコミット3f3b7f9を太平洋時間19:56にmainへpushした件――は、太平洋時間20:45にコミットb404fbeによってクローズされました。49分後です。ガードを強化する2つの追随コミットがあります。6b11a35は--all/--mirrorによる広範なpushの検知を追加し、cffdc57は回帰テストスイートを追加しました。さらに後のコミット038b0e8では、コミットを生成するサブコマンド集合にgit pullを含めるよう拡張されています。 - ガードの回避(bypass)の表面には6つのカテゴリがあります。保護ブランチを対象とする明示的なrefspec、
HEADが保護ブランチ上にあるときの暗黙のpush、広範モードの--all/--mirrorフラグ、コミット生成サブコマンド(merge、rebase、cherry-pick、revert、am、pull)、ネストされたシェルラッパ(bash -c、sh -c、zsh -c、さらに防御的な--command=のマッチ)であり、深さ制限付きの再帰的評価(最大深さ4)が行われます。そして、連結コマンドは&&、||、;、改行、および単一パイプ(|)の区切りで分割されます。 - ドキュメント基盤を運ぶ開発ディレクトリ内の6つの稼働中プロジェクトのうち、GovForgeと
sdlc_appの両方が、PreToolUse:Bashによる保護ブランチガードを組み込んでいます。GovForgeの実装は監査済みの模範例――320行と、354行の回帰テストスイート、そしてGF-PLAN-015の監査ドキュメントが対になっています。sdlc_appの実装は、同じパターンの別途設計された278行バリアントです。ADWS Pro、AetheriaForge、DriftSentinelは.claude/hooks/にフックスタブを保持していますが、settings.jsonには登録していません。spec-driven-docs-systemは別の形のフックを配線しており――Pythonのドキュメントに対する、Write|Editマッチャーへの前後書き込みバリデータであり、Bashの保護ブランチガードではありません。 sdlc_appプロジェクトのdoc_pre_write.pyは277行です。spec-driven-docs-systemプロジェクトは、4ファイルのPythonフックスイート(doc_pre_write.py、doc_post_write.py、doc_post_review.py、hook_utils.py)を提供しており、合計751行です。これは、パスに応じたマッチャーによってドキュメントファイルにスコープされています。
解釈
以下は、これらのプロジェクトでフック層を運用する中で得られたエンジニアリング上の判断です。これらは、普遍的な処方箋として読むのではなく、著者の経験に基づく主張として読んでください。
フックはスタック内で最もレバレッジの高い単一の層です。なぜなら、書かれたルールが、ハーネス内部で構造的に破れなくなる唯一の場所だからです。ほかのすべての層は、ルールを説明する(ドキュメント)か、事後に違反を検知する(CI)かのどちらかです。フックは、違反がそもそも着地することを防ぎます。この非対称性こそが、その層が存在する理由のすべてです。そして、ドキュメント基盤のみしか持たないチームが、ルールが3度目に明確化された後でも、セッションをまたいで同じクラスのインシデントが繰り返し発生するのは、その理由によるものです。
空のスタブ状態は、標準的な失敗モードであり、正確に2つのアサーションによって検出されます。 1つ目は、フックファイルが空ではなく、どこかにリテラル process.exit(2) が含まれていることです。2つ目は、settings.json にまだ登録が残っていることです。これらはいずれも、20行以内のテストコードに収まります。どちらも実行はミリ秒単位です。プロジェクトの既存テストスイートにこれらを追加することは、元のGovForge事件の有効化条件を退役させるための、最も安価な単一変更です。この層で書くコードがこの2つだけになるなら、その2つのテストが正解です。
ネストされたシェルの扱いは、多くのチームが過小評価している抜け道です。 git push origin main を捕捉するガードを書くのは簡単ですが、bash -c "git push origin main" が別の表面(surface)では同じ操作であることを見落としがちです。エージェントが敵対的である必要はありません。Makefile、シェルスクリプト、ツールチェーンは日常的にシェルアウトし、エージェントがそれらの1つに手を伸ばした瞬間、内部コマンドはトークンレベルのインスペクタには見えなくなります。深さ制限付きの再帰的評価が正しい手段です。これはガードのコードが最も増える部分でもあります。インラインのペイロード抽出では複数の引用形式に対応する必要があり、再帰では無限ループにならないように同じ評価器へ再入させなければならないからです。
フックは自分で説明します。 ガードの“支えになる”振る舞いの驚くほどの割合が、終了コードではなく stderr メッセージにあります。終了コードがアクションを止めます。メッセージは、なぜダメなのか、そして次に何をするべきかをエージェントに伝えます。よく書かれたメッセージ――ポリシーファイル名、サブコマンド名、理由名、修正内容名――は、拒否を自己修正するサイクルへ変えます。簡潔すぎるメッセージは、混乱したリトライのループに変えてしまいます。メッセージを書く作業は小さく、レバレッジは大きいのです。
フックはジェネリックではなく、プロジェクトの形に合わせたものです。 spec-driven-docs-system プロジェクトには protected-branch ガードがありません。失敗モードが異なるからです。現実的なリスクは、破壊的なgit操作ではなく不正なドキュメントであり、フックの表面は Write|Edit マッチャです。これはPythonバリデータを実行し、禁止されたパターン、欠けた構造、整合性ルールをチェックします。sdlc_app プロジェクトは両方の形を持ちます。同じ理由から GovForge と同様の 278行の PreToolUse:Bash protected-branch ガードがあり、加えてドキュメント志向の Write|Edit バリデータが、自身のドキュメント用の表面を対象にしています。3つのプロジェクトすべてで、アーキテクチャのパターンは同じです。違うのは各プロジェクトのポリシーです。GovForge のフックを、リスク表面が異なるプロジェクトにそのままコピーするチームは、この仕事の“カルト版”をやってしまっています。正しい手は、プロジェクト固有の失敗モードを列挙し、それらに対してガードを書くことです。
Practical Implications for Teams Considering the Pattern
あなたのチームにドキュメントの土台があり、フックがまだないなら、まず protected-branch ガードを書いてください。エージェント型コーディングのワークフローにおける最も重大な破壊的操作であり、さらに最も自信のあるサブエージェントによってスピード優先で実行されがちなものです。最初は最も単純で正しいバージョンから始めましょう。Bashコマンドを解析し、git commit または git push をチェックし、現在のブランチを調べます。HEAD が protected branch 上にあり、操作がこの2つのうちのどちらかであれば 2 で終了します。.claude/settings.json に登録してください。空のスタブ状態を検出する、2つのアサーションによる回帰テストも追加します。このバージョンは1晩の作業で、支配的な失敗モードを閉じます。
基本のガードが配置され、テスト済みになったら、段階的に強化してください。GovForge の流れを基に、私が推奨する順序は次の通りです:HEAD:main および +main 形式のための refspec 解析;--all と --mirror のための broad-mode フラグ検出;merge、rebase、cherry-pick、revert、am、pull をカバーする、コミットを生成するサブコマンドの拡張;bash -c、sh -c、zsh -c のためのネストされたシェルの再帰。追加のたびに、それぞれ独立したコミットと、それに対応するテストを用意します。追加のたびに、初日には起きにくいが30日目には確実になっている“抜け道”のカテゴリを潰していきます。
チームにフックがあるが、それを set-and-forget(設定して放置)として扱っているなら、回帰スイートを書いてください。空のスタブの失敗モードは静かです。ファイルは存在し、設定は正しそうに見え、エラーは一切出ず、フックは機能を停止します。これを捕捉できるのは、フックをエンドツーエンドで実行し、既知のブロック対象ペイロードが実際に 2 で終了することをアサートするテストだけです。そのテストをCIで実行してください。フックのテストが失敗した場合は、ユニットテストが失敗したのと同じ重大度で、CIをブロックするイベントとして扱います。ガードはプロダクションの表面の一部です。同じ扱いを受けるべきです。
新しいプロジェクトを始めるなら、初回コミットでフックを出荷してください。動作する protected-branch ガードを書くコストは、初日と30日目で同じです。持たない場合のコストは非対称です。プロジェクトがそれなしで長く動けば動くほど、スピードで動作するサブエージェントが破壊的操作を生成する可能性は高まり、その一方でスタック全体はそれを捕捉できる体制になっていないことが多くなります。GovForge のインシデントが起きたのは、フックの雛形が兄弟プロジェクトからコピーされたものの、実際の振る舞いとしては配線(wired)されていなかったためです。初日から動作するフックがあれば、それは防げていたでしょう。初日からの空のスタブは、ファイルがまったく無いよりも悪い状態でした。統治(governance)が効いているように見せてしまいながら、強制(enforcement)を行わないからです。
実行時の強制レイヤは、エージェント型コーディングが“生産性の実験”で終わるのをやめ、規制されたビジネスでも確信を持ってデプロイできるシステムになる場所です。フックは小さい。ポリシーも小さい。レバレッジは、スタック全体における最大の単一の非対称性です。エージェント型コーディングを本番環境へデプロイする準備が最も整っているチームは、この境界線を理解し、越えてきたチームです。
Get the templates
この記事で説明している protected-branch フック――.claude/settings.json への登録、そして空のスタブの失敗モードを捕捉する回帰テストスイート――は、etherealogic.ai/agentic-governance-stack-templates にある、エージェント型ガバナンス・スターターキットの一部として提供されています。このフックは、シリーズ最初の記事の“ドキュメントの土台”ファイルと並んで、コピペしてそのまま使える形でページ上に掲載されています。
References
- Anthropic Claude Code ドキュメント―― Claude Hooks の仕様。PreToolUse / PostToolUse の契約や、終了コード2ブロックプロトコルを含みます。
- AGENTS.md オープンスタンダード ― agentsmd/agents.md、Linux Foundation の Agentic AI Foundation によって統治されています。
- GovForge ― 本記事で言及しているガードと回帰スイートを実装している公開リポジトリ。権威ある成果物は、
.claude/hooks/pre-tool-use.js、.claude/hooks/README.md、tests/test_pre_tool_use_hook.py、specs/GF-PLAN-015_Hook_Guard_Audit.md、およびreport/2026-04-12T03-41-21Z-notion-sync-record.mdのインシデント同期記録です。後者は、コミット3f3b7f9に対するオペレータが報告したガバナンス注記を保持しています。 - 本シリーズの最初の記事 ― CLAUDE.md Is Not Enough: The Governance Stack for Agentic Development。
これは、エージェント型ガバナンス・スタックに関するEthereaLogicシリーズの2本目の記事です。次の記事では、同じ深さで外部検証レイヤーを扱います。具体的には、4つの本番プロジェクトで使用しているCodacy、Codecov、Snykの構成、可変タグのサプライチェーン問題を塞ぐSHAピン留めの実践、そして、CIが一致しない場合にエージェント自身の自己申告が決して権威を持たないというルールを含みます。






