エージェント別の連携方式
標準入力の hook subprocess を使うエージェント
この 9 つのエージェントでは、標準入力から JSON を読み取るhook <flag> コマンドが保護を担います。実行前イベントの名前もコマンド用ツールの名前もエージェントごとに異なり、標準出力に求められる拒否の形式も異なります。
エージェントごとにイベント名も拒否の形式も異なるため、CC Safety Net はそれぞれに合った形式で出力します。たとえば Gemini CLI は、Claude Code の
hookSpecificOutput ではなく、終了コード 0 と decision/systemMessage を持つオブジェクトを求めます。出力形式を自分で設定する必要はありません。指定したフラグによって自動的に決まります。共通の Coding CLI hook を使う
hook --coding-cli(短いフラグは -cc)が、Claude 形式の hook の正式な名前です。このエントリーポイントは、その形式のペイロードを送ってくるエージェントであればどれでも受け付けます。そのため「Claude Code」ではなく「Coding CLI」という名前にしています。
hook --claude-code は以前からのエイリアスとして受け付けますが、hook --help には表示されません。新しい設定では使わないでください。
これとは別に、3 つのエージェントについては hook を省略する以前のトップレベルの書き方も残っています。cc-safety-net -cc / --claude-code、-gc / --gemini-cli、-cp / --copilot-cli です。正式な --coding-cli は、意図的にトップレベルのフラグにしていません。cc-safety-net --coding-cli だけを実行すると、Unknown option: --coding-cli というエラーになります。
statusline コマンドは hook とは無関係で、引き続き --claude-code または -cc を指定する必要があります。ステータスラインを参照してください。hook 設定の場所
9 つのうち 5 つは、CC Safety Net がファイルを直接書き込みます。4 つは hook の設定エントリとして、Hermes Agent は管理対象プラグインとして書き込みます。残りの 4 つは、それぞれのプラグインや拡張機能の配布経路を通して接続し、そのうえで標準入力の hook を呼び出します。
Kimi Code の
Bash 呼び出しでは、tool_input.cwd があればその値を実行ディレクトリとして使います。値は空でない文字列で、セッションの cwd の内側に解決できる必要があります。無効な値や外側を指す値は fail closed になります。GitHub Copilot CLI では、powershell と PowerShell の呼び出しを PowerShell のアナライザーに振り分けます。
Grok Build の呼び出しでは、信頼するルートは workspaceRoot で、workspaceRoot がない場合は cwd をルートとします。cwd はそのルートの内側のディレクトリとして正規化できる必要があり、cwd がないか空の場合は . として扱います。ルートを正規化できない場合や、cwd がルートの外を指す場合は fail closed になります。toolInputTruncated: true も fail closed になります。Grok Build はツール入力を 128 KB で切り詰めるため、途中で切れたコマンドは解析できません。
Codex が hook に到達する仕組み
Codex は、cc-marketplace マーケットプレイスのプラグイン cc-safety-net@cc-marketplace として CC Safety Net を読み込みます。このプラグインは Codex 独自の形式でパッケージ化されており、マニフェストが指す hooks/codex.json が PreToolUse hook を登録します。cc-safety-net スキルも同じプラグインに同梱されています。
Codex は信頼されていない hook を実行しないため、Codex 内で信頼済みにするまで hook は動作しません。手順はインストールを参照してください。
Hermes Agent が hook に到達する仕組み
Hermes は、hook の設定ファイルから hook コマンドを実行するわけではありません。CC Safety Net は、Hermes がプロセス内で読み込む管理対象の Python プラグインをインストールし、そのプラグインがpre_tool_call のハンドラーを登録します。対象のツール呼び出しのたびに、ハンドラーは npx -y cc-safety-net hook --hermes-agent を実行し、呼び出し内容を JSON で標準入力に書き込みます。標準出力が空であれば許可を意味します。{ "action": "block", "message": … } が返ればブロックで、Hermes はそのメッセージをツール結果としてモデルに提示します。
プラグインが渡すツールは 4 つです。コマンド解析用の terminal、書き込み保護用の write_file と patch、読み取り保護用の read_file です。それ以外の Hermes のツール呼び出しは渡されず、判定も行われません。
Hermes は例外を投げたプラグインのコールバックを無視するため、プラグイン自身がすべての失敗を明示的なブロックに変換します。対象は、PATH に npx がない、プロセスの起動に失敗する、タイムアウトする(30 秒でアナライザーのプロセスグループ全体を kill)、終了コードが 0 以外になる、出力が読み取れないか想定外である、といった場合です。Hermes のセッションディレクトリを読み取れない場合もブロックします。誤ったディレクトリを基準に解析すると、パスに基づく保護がすべて失われてしまうためです。
ここでは、ディレクトリに関する 2 点が重要です。terminal の呼び出しでは、プラグインはまず Hermes がセッションごとに保持する作業ディレクトリの記録を読み取ります。この記録には、そのセッションでの cd の状態が反映されています。最初のコマンドでまだ記録がない場合は、TERMINAL_CWD、次に Hermes のプロセスのディレクトリを使います。使用できない workdir を持つ terminal の呼び出しは fail closed になります。また、アナライザーの subprocess は Hermes の作業ディレクトリではなくホームディレクトリから起動します。これにより、npx が正規のパッケージの代わりにリポジトリ内の cc-safety-net を解決してしまうのを防ぎます。
管理対象のファイルはいずれも、CC Safety Net のファイルであることを示すヘッダー行で始まります。インストーラーは、このヘッダーがないファイルを上書きしません。Hermes はディスク上に存在しないプラグインを解決しないため、アンインストールではファイルを削除する前に hermes plugins disable cc-safety-net を実行します。インストール・アンインストールのいずれの場合も、Hermes を再起動するまでプラグインの変更は反映されません。設定と削除のコマンドはインストールを参照してください。
Pi の場合と違い、doctor は管理対象プラグインのディレクトリと Hermes の config.yaml の plugins.enabled の一覧だけを見て、ディスク上から Hermes Agent を検出します。実行時のプローブは使いません。
エージェントが読み込むプラグイン
OpenClaw
OpenClaw は、ネイティブの OpenClaw プラグインとして CC Safety Net をプロセス内に読み込みます。プラグインは 3 つのファイルからなるパッケージ済みディレクトリとして提供されます。実行エントリのindex.js は、ローカルディレクトリからのインストールでは node_modules が存在しないため、依存関係をすべてインライン展開した自己完結型のバンドルになっています。openclaw.plugin.json のマニフェストは、コードを読み込む前に OpenClaw が検証します。package.json の openclaw.extensions がエントリを指しています。hook フラグも、標準入出力を経由する JSON のやり取りもありません。
プラグインは、exec ツールに一致する before_tool_call のハンドラーを登録します。解析するのは、タグの付いていないシェルの exec だけです。Code Mode の JavaScript exec のように toolKind の識別子が付いた exec イベントには判定を返しません。それらの command フィールドがシェルコマンドを表す保証がないためです。それ以外の OpenClaw のツールはガードに渡しません。ハンドラーは、判定なし(許可)か { block: true, blockReason } のいずれかを返すだけで、ツールのパラメーターを書き換えることはありません。
エージェントのワークスペースディレクトリは OpenClaw の実行時 API で解決し、ポリシー用と実行用の両方のディレクトリとして使います。呼び出しに含まれる workdir は、ワークスペースの内側に収まるように解決します。CC Safety Net が fail closed になるのは、次の場合です。
- イベントが不正
- コマンドが欠けているか空
- ワークスペースを解決できない
workdirがワークスペースの外を指す- すでにキャンセル済みの呼び出し
host が auto と gateway 以外の exec 呼び出しもブロックします。gateway はローカルであることが確認できているためです。host: "auto"(または host の指定なし)の呼び出しは、ローカル Gateway の前提で解析しますが、OpenClaw が実際にどこへ振り分けるかまではプラグインからは確認できません。サンドボックスの場合については、既知の制限を参照してください。
プラグインの状態は OpenClaw が管理しているため、インストールには OpenClaw 自身の CLI を使います。openclaw plugins install <packaged dir> --force を実行し、続けて openclaw plugins enable cc-safety-net を実行します。--force を使うコマンドの前に、CC Safety Net は対象の拡張機能ディレクトリが自身の管理対象ファイルだけを含むことを確認します。これにより、自分のものだと確認できないプラグインを上書きしたり削除したりすることはありません。インストール後には openclaw plugins inspect cc-safety-net --runtime --json を実行し、状態が loaded の場合だけ成功とみなします。バンドルが壊れたまま有効になっているプラグインは、インストール自体は問題なく完了しても、何も保護しないまま終わってしまうためです。
インストールされたファイルは <state dir>/extensions/cc-safety-net/ にあります。state dir は、設定されていれば OPENCLAW_STATE_DIR、次に OPENCLAW_CONFIG_PATH があるディレクトリ、いずれもなければ ~/.openclaw です。有効・無効の状態は OpenClaw 自身の設定(state dir の openclaw.json、または OPENCLAW_CONFIG_PATH)にあります。全体の plugins.enabled スイッチ、plugins.allow / plugins.deny の一覧、プラグインごとの plugins.entries.cc-safety-net.enabled の項目が、いずれも影響します。plugins.allow を設定している場合は、そこに cc-safety-net も記載する必要があります。
インストールまたはアンインストールの後は、OpenClaw Gateway を再起動してください。マニフェストは起動時にプラグインを有効化する設定(activation: { onStartup: true })になっているため、実行中の Gateway には変更が反映されません。設定と削除のコマンドはインストールを参照してください。
OpenCode
OpenCode は CC Safety Net をプロセス内に読み込みます。読み込む対象は、~/.config/opencode/opencode.json(または .jsonc)の plugin 配列で宣言し、OpenCode 自身の @opencode-ai/plugin の仕様を実装したプラグインオブジェクトです。プラグインが行うことは 2 つです。
tool.execute.beforeを実装します。OpenCode は各ツールの実行前にこれを呼び出します。CC Safety Net は呼び出しを解析し、コマンドが破壊的であれば拒否を例外として投げます。標準入出力経由の JSON のやり取りはありません。configの hook を実装し、CC Safety Net の組み込みコマンドを OpenCode のコマンド一覧に追加します。ユーザーがすでに定義しているコマンドを上書きすることはありません。
bash ツールでは、プラグインは OpenCode の shell の設定からアナライザーの方言を選びます。この設定が文字列でない場合、Windows では PowerShell を既定とし、それ以外では SHELL を参照します。認識できる powershell と pwsh の実行ファイルなら PowerShell を、認識できる POSIX シェルなら POSIX を選びます。それ以外の値の場合は自動判定に任せます。指定された workdir は、読み取りと検索ができるディレクトリとして解決できた場合にかぎり、実行ディレクトリになります。Windows では、/C:、/C、/cygdrive/C、/mnt/C という文書化された形式を正規化し、それ以外のスラッシュ始まりのパスは OpenCode 側で解決できるようそのまま渡します。
OpenCode が古いキャッシュのプラグインを使い続けることがあるため、キャッシュを消去するまで設定変更が反映されない場合があります。インストールを参照してください。
Pi の拡張機能
Pi は、パッケージのpi.extensions フィールドで宣言され、~/.pi/agent/settings.json にパッケージの取得元 npm:cc-safety-net として記録された、プロセス内の拡張機能として CC Safety Net を読み込みます。拡張機能が行うことは 2 つです。
tool_callイベントのハンドラーを登録します(pi.on('tool_call'))。ハンドラーは Pi のツール呼び出しを実行前に検査し、コマンドやパスがポリシーに違反していればブロックの結果を返します。プロセスの境界を越えるやり取りは一切ありません。- Pi 内から rulebook を対話的に管理するための、組み込みコマンド
/cc-safety-netを登録します。
Pi で保護されるツール
Pi でコマンド用ツールとして扱われるのは、組み込みのbash ツールだけです。その command はセッションのカレントディレクトリを基準に実行されます。以前のカスタム Shell ツールには対応していません。Pi のコマンド以外のツールも、引き続きパスの保護とシークレット保護の対象になります。特に find は読み取り専用の glob ツールとして分類されるため、検索自体を書き込みとして扱うことなく、pattern とパスの値を検査します。コマンドの呼び出し内容やセッションのカレントディレクトリが不正な場合、CC Safety Net は fail closed になります。
Pi の検出
検査すべき hook の設定ファイルがないため、doctor コマンドは実行時のプローブで Pi を検出します(pi を起動し、拡張機能が読み込まれて有効になっているかを確認します)。そのため、Pi がインストール済みでもプローブを実行できない場合、doctor の Pi の状態が n/a になることがあります。
Amp Code のイベントプラグイン
Amp Code は CC Safety Net を personal plugin として読み込みます。実体は、Amp アカウントがホストする Personal Plugins リポジトリ内のcc-safety-net ディレクトリで、自己完結したエントリファイル index.ts を収めています。このプラグインは @ampcode/plugin の API を使って Amp の tool.call イベントを購読し、allow か、メッセージを添えた reject-and-continue を返します。Pi、OpenClaw、OpenCode と同様、プロセス内で動作します。personal plugin は 1 台のマシンではなくアカウントに紐づくため、Amp Orb のようなリモート環境で実行されるスレッドも保護できます。
Amp のワークスペースルート(amp.system.workspaceRoot)が設定ディレクトリになります。シェルのツール呼び出しに文字列の dir が含まれる場合は、その値が実行ディレクトリになります。相対パスはワークスペースルートを基準に解決し、その結果を realpath で正規化します。実在するディレクトリであることも必要です。Windows の名前空間パスは拒否します。解決できない dir は fail closed になり、このときコマンドが破壊的かどうかは解析しません。この拒否は、アナライザーの想定外の失敗としては報告しなくなりました。作業ディレクトリが原因であることを示し、すでに存在してアクセスできるディレクトリを使うか、存在しないディレクトリであれば先に作成するよう、エージェントに伝えます。OpenClaw の workdir とは異なり、解決後のディレクトリがワークスペースの内側に収まっている必要はありません。Amp は自身のスキルのキャッシュや隣接するリポジトリを指定することがあり、これは正当な使い方です。同じ作業を cd <dir> && … と書いた場合も、もともとそこで実行されます。設定ディレクトリはワークスペースルートのままなので、プロジェクト自身のルール設定は引き続き適用されます。さらに、Git メタデータのガードは実行ディレクトリと設定ディレクトリの両方を起点とするため、コマンドを別の場所で実行しても、ワークスペース自身の .git は保護されたままです。Git メタデータを参照してください。
install --amp は、このプラグインをリポジトリに公開します。まずアカウントに書き込み可能な Personal Plugins リポジトリがあることを確認し(amp plugins repositories --json)、使い捨てのディレクトリにクローンして(amp clone user-plugins)、cc-safety-net/index.ts を書き込み、コミットしてプッシュします。ステージングでは、ディレクトリを渡さず明示的なパス(git add -- cc-safety-net/index.ts)を指定します。そのため、プラグインのパスが gitignore されている場合は、何もステージしないまま進むことはなく、インストールが止まります。インストールもアンインストールも、書き込みや git rm の対象はこのエントリ 1 つだけなので、同じディレクトリに置いた他のファイルに触れることはありません。
エントリには、CC Safety Net の管理対象であり安全に置き換えてよいことを示す管理用ヘッダーが付きます。インストールもアンインストールも、cc-safety-net がシンボリックリンクである場合やディレクトリでない場合、また index.ts がシンボリックリンク、通常ファイル以外、管理対象外のいずれかである場合は、そのプラグインを拒否します。ディレクトリ構成になる前のリリースは、リポジトリのルートに cc-safety-net.ts を公開していました。これが管理対象であれば同じコミットで削除し、管理対象外であればインストールは失敗します。
ローカルのプラグインは personal plugin を覆い隠すため、インストールは ~/.config/amp/plugins/ 以下も片付けます。削除するのは、管理対象の旧ファイル cc-safety-net.ts と、管理対象の index.ts だけを含む手作業でコピーされた cc-safety-net/ ディレクトリです。この 2 つのパスにそれ以外のローカルエントリがある場合、インストールは失敗します。設定と削除のコマンドはインストールを参照してください。
埋め込まれるポリシーのスナップショット
公開されるファイルには、ユーザーのポリシーのスナップショットが含まれます。ファイル末尾に追加されるglobalThis.__CC_SAFETY_NET_EMBEDDED_POLICY__ = … という 1 つの代入で、ポリシーは書き込み前に正規化されます。実行時にこのスナップショットが適用されるのは、自前のポリシーファイルを持たないマシン、つまりホームディレクトリが空の Orb のような環境だけです。ポリシーファイルがあるマシンでは、たとえその内容が不正でも、そのマシン自身の設定が優先されます。監査ログの保持期間、ユーザー rulebook、プロジェクトスコープのポリシーは埋め込まれず、ポリシーの変更は次回の install または update で反映されます。
Amp は起動時にプラグインを読み込むため、新しく公開したプラグインや削除したプラグインは、Amp を再読み込みするまで実行中のセッションに影響しません。
Amp Code の検出
doctor は amp plugins list の出力を解析してプラグインを検出します。personal スコープのプラグインは ✓ cc-safety-net (User Plugins) <status> と表示されます。この出力にはバージョンが含まれないため、doctor は Amp 側のバージョンのずれを報告しません。cc-safety-net update は常に、現在のファイルを公開し直します。
Amp Code の対象範囲の制限
- Amp は、同じ
tool.callイベントを購読する複数のプラグインの実行順序を定めていません。CC Safety Net は受け取った入力をその時点で評価するだけで、許可を返した後に別のプラグインが入力を書き換えた場合、それを評価し直すことはできません。
連携を検証する
npx cc-safety-net doctor は、エージェントごとに検出した連携方式と設定ファイルのパスを報告し、保護が有効な場合はセルフテストも実行します。オプションと終了時の挙動は CLI コマンドを参照してください。
特定のエージェントで hook が動作しない場合は、トラブルシューティングのエージェント別の手順を参照してください。
次に読むページ
技術ガイドは、ユーザー向けのライフサイクルの説明から設計の理由へと順に降りていく構成です。このページはその 2 番目にあたります。- 戻る:仕組みでは、同じインターセプトを 1 回のツール呼び出しとして最初から最後まで説明しています。
- 次へ:アーキテクチャでは、このページのすべての連携が接続するガードと、順序付きステージの一覧を説明します。
- その次:解析エンジンでは、分類処理に届いたコマンドをどう分類するかを説明します。
- 最後:設計原則では、これらの連携方式とガードの順序を採用した理由を説明します。