signet-eval について
signet-eval は、AI エージェントのツール呼び出しを一貫して制御したいユーザー向けのローカルポリシーエンジンです。LLM を認可経路で使わず、順序付きルールを評価し、助言的な通知は認可処理と分離します。
主な機能
- 01ALLOW、DENY、ASK、GATE、ENSURE の決定論的ルール
- 02先に一致したルールを適用する順序評価
- 03変更できない自己保護ルール
- 04Claude Code、Codex、Cursor などのフックアダプター
- 05任意の助言コンテキスト注入
活用シーン
- 01実行前に破壊的なシェルコマンドを拒否
- 02指定したツール入力に確認を要求
- 03ポリシーファイルと signet-eval バイナリを保護
- 04支出や認証情報の条件をルールに追加
MCP 対応
ローカルの stdio MCP サーバーを通じて、クライアントからポリシーを管理できます。ロックされたルールはこの管理サーバーから変更できません。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
このサーバーのパッケージやリモートエンドポイントはまだ取得できていません。プロジェクトの README の手順に従ってください。
ツール
ローカルサーバーのツールはマシン上で起動して初めて取得できます。メンテナーはまだツール一覧を提供していません。
詳細
signet-eval
AI エージェントのツール呼び出しに対する決定論的なポリシー適用機能です。統合されたツール呼び出しは、実行前にユーザー定義のルールを通過します。認可処理に LLM は使用しません。助言的な提案は認可とは別に扱われます。
インストール
# crates.io
cargo install signet-eval
# from source
git clone https://github.com/wandercom/signet-eval
cd signet-eval
cargo install --path .
signet-eval の npm または PyPI パッケージはありません。一般向けの配布経路は
crates.io と GitHub からのソースインストールです。MCP Registry の掲載情報は
リポジトリのメタデータを参照しています。ランタイムはローカルで動作する
signet-eval serve の stdio サーバーです。
クイックスタート
以下のコマンドフックアダプターは引き続きサポートされており、互いに独立しています。Claude Code のオプションの早期アクセス版関数フックについては、 関数アダプターを参照してください。デフォルトでは無効です。 このパッケージをインストールまたはビルドしても有効化されず、ユーザー設定も変更されません。
1. Claude Code にフックを設定する — ~/.claude/settings.json に追加します。
{
"hooks": {
"PreToolUse": [{
"matcher": "",
"hooks": [{"type": "command", "command": "signet-eval", "timeout": 2000}]
}]
}
}
Codex の場合は、~/.codex/config.toml または <repo>/.codex/config.toml でフックを有効にします。
[features]
codex_hooks = true
次に、~/.codex/hooks.json または <repo>/.codex/hooks.json を追加します。
{
"hooks": {
"PreToolUse": [{
"matcher": "*",
"hooks": [{
"type": "command",
"command": "signet-eval --adapter codex",
"timeout": 30000,
"statusMessage": "Checking Signet policy"
}]
}],
"PermissionRequest": [{
"matcher": "*",
"hooks": [{
"type": "command",
"command": "signet-eval --adapter codex-permission",
"timeout": 30000,
"statusMessage": "Checking Signet approval policy"
}]
}]
}
}
Antigravity の場合は、このブロックを ~/.gemini/config/hooks.json に追加します(既存のフックグループがあれば統合してください)。
{
"signet": {
"enabled": true,
"PreToolUse": [{
"matcher": "*",
"hooks": [{
"type": "command",
"command": "/bin/bash -lc 'source ~/.profile >/dev/null 2>&1 || true; exec signet-eval --adapter antigravity'",
"timeout": 30,
"statusMessage": "Checking Signet policy"
}]
}]
}
}
同じ設定は hooks/antigravity-hooks.json でも利用できます。
Cursor の場合は、~/.cursor/hooks.json(ユーザー)または <repo>/.cursor/hooks.json
(プロジェクト)に追加し、既存のイベントがあれば統合してください。
{
"version": 1,
"hooks": {
"preToolUse": [{
"command": "/bin/bash -lc 'source ~/.profile >/dev/null 2>&1 || true; exec signet-eval --adapter cursor'",
"matcher": "^(?!Shell$|MCP:)",
"timeout": 30,
"failClosed": true
}],
"beforeShellExecution": [{
"command": "/bin/bash -lc 'source ~/.profile >/dev/null 2>&1 || true; exec signet-eval --adapter cursor'",
"timeout": 30,
"failClosed": true
}],
"beforeMCPExecution": [{
"command": "/bin/bash -lc 'source ~/.profile >/dev/null 2>&1 || true; exec signet-eval --adapter cursor'",
"timeout": 30,
"failClosed": true
}]
}
}
同じ設定は hooks/cursor-hooks.json でも利用できます。
preToolUse マッチャーは、専用イベントで評価されるシェルと MCP の呼び出しをスキップします。
これがない場合、各呼び出しは 2 回評価され、ログにも 2 回記録されます。
Muse Code の場合は、~/.config/muse/settings.json にトップレベルの hooks メンバーを追加します
(ユーザースコープでは、schema_version や他の設定はそのままにします)。または、ファイルを
<repo>/.muse/hooks.json として保存します(プロジェクトスコープでは、Muse は信頼された
ワークスペースでのみ有効にします)。
{
"hooks": {
"PreToolUse": [{
"matcher": "*",
"hooks": [{"type": "command", "command": "signet-eval --adapter muse"}]
}]
}
}
同じ設定は hooks/muse-hooks.json でも利用できます。
2. 完了です。 すべてのツール呼び出しがポリシー評価を通過するようになります。デフォルトのポリシーでは、破壊的な操作をブロックし、独自の設定を保護し、それ以外はすべて許可します。
3. (任意)カスタマイズする — MCP サーバーを使って Claude に話しかけます。
claude mcp add --scope user --transport stdio signet -- signet-eval serve
次のように伝えてください。「amazon の注文に 50 ドルの上限を追加して」、または*「すべての rm コマンドをブロックして」*。
デフォルトのポリシー
自己保護ルールはロックされています。MCP 管理サーバーを通じた場合でも、AI エージェントはこれらのルールを削除、編集、並べ替えできません。これにより、エージェントが自らのガードレールを無効にするのを防ぎます。
| アクション | 判定 | ロック |
|---|---|---|
.signet/ に触れる Write/Edit/Bash | 拒否 | はい |
signet-eval バイナリに触れる Write/Edit/Bash | 拒否 | はい |
settings.json / settings.local.json の Write/Edit | 確認 | はい |
signet を伴う Bash kill/pkill/killall | 拒否 | はい |
| 直近に Kindex タグ/検索/コンテキストがない状態での直接編集ツール | 拒否 | はい |
Claude TaskCreate、TaskUpdate、TaskList、TaskGet、TodoWrite | 拒否 | はい |
rm、rmdir | 拒否 | |
Cursor のネイティブ Delete ツール | 拒否 | |
git push --force | 確認 | |
対象の所有者 ID が一致しない Git リモートと gh の操作 | 拒否 | |
mkfs、format、dd if= | 拒否 | |
curl | sh、wget | sh | 拒否 | |
| マスクされたシークレットの値をそのまま含むツール入力 | 確認 | |
| その他すべて | 許可 |
カスタムポリシー
signet-eval init # write default policy to ~/.signet/policy.yaml
signet-eval validate # check policy for errors
signet-eval rules # show current rules
~/.signet/policy.yaml を編集します。
version: 1
default_action: ALLOW
rules:
- name: block_rm
tool_pattern: ".*"
conditions: ["contains(parameters, 'rm ')"]
action: DENY
reason: "File deletion blocked"
- name: books_limit
tool_pattern: ".*purchase.*"
conditions:
- "param_eq(category, 'books')"
- "spend_plus_amount_gt('books', amount, 200)"
action: DENY
reason: "Books spending limit ($200) exceeded"
- name: protect_my_config
tool_pattern: ".*"
conditions: ["contains(parameters, '/etc/')"]
action: ASK
locked: true
reason: "System config changes require confirmation"
ルールは順番に評価され、最初に一致したものが適用されます。1 つのルールに複数の条件がある場合は、AND 条件として扱われます。locked: true のルールは、MCP 管理サーバーを通じて変更できません。
ENSURE チェックのコンテキスト
ユーザー管理の ENSURE スクリプトには、正規化された元のツール名と入力が標準入力で渡されます。SIGNET_TOOL_COMMAND には、正規化された command フィールドと cmd フィールドのうち、最初に見つかった空でない文字列がリテラルな環境変数値として設定されます。どちらのフィールドにも値がない場合は空になります。
この転送の仕組みは、その値をシェルコードとして解釈しません。
SIGNET_TOOL_CWD は、正規化されたツールの cwd/workdir、ホストエンベロープの cwd、フックプロセスの作業ディレクトリの順に使います。空の値はスキップされます。
SIGNET_TOOL_CWD_SOURCE には、使用された値の出所として tool_input、host、process のいずれかが設定されます。
SIGNET_HOST_CWD にはホストエンベロープの cwd のみが設定され、ホストから送信されなかった場合は空になります。tool_input のディレクトリはホストがコマンドを実行する場所ですが、モデルが記述したものです。プロセスのフォールバックは、独立して検証された実行ディレクトリではありません。いずれも信頼できる場所の証明ではないため、場所に基づいて許可するチェックでは、この値を信頼する前に出所を確認してください。
Signet はコマンドを解釈しないため、その中の cd によって SIGNET_TOOL_CWD が変わることはありません。これらの環境変数はすべて継承された値を置き換え、標準入力は変更されません。
チェック用スクリプトがない場合、または解決できない場合、ユーザールールとロックされたルールのどちらでも、チェック名を含む理由とともに呼び出しを拒否します。Signet はチェック用スクリプトをインストールしないため、それを参照する rules.yaml とともに ~/.signet/checks/ をコピーしてください。
以前のリリースには github_identity_guard システムルールが含まれていました。policy.yaml に残っているそのコピーは無視され、signet-eval validate は警告として報告します。ID チェックを維持するには、管理するスクリプトとともにルールを rules.yaml に追加してください。
リポジトリのルートで cargo build --release を実行した後、以下の独立したローカル受け入れチェックを実行します。
SIGNET_EVAL_BINARY="$(pwd)/target/release/signet-eval" python3 tests/test_ensure_behavior.py
これらの Python 受け入れチェックはローカルで実行でき、Rust およびパッケージングのチェックとともに、Linux と macOS 上でリリースバイナリを対象とするホスト型 CI でも実行されます。
アドバイザリーインジェクション
INJECT ルールは、トリガーとなったツール呼び出しの前後にアドバイザリーコンテキストを確率的に追加します。これは促しであり、認可ではありません。通常の ALLOW/DENY/ASK/GATE/ENSURE の評価は、最初に一致したルールを適用する決定論的な方式で、引き続き最初に行われます。インジェクションはその後に実行され、一致するインジェクションルールが発動した場合にのみコンテキストを出力します。
rules:
- name: maybe_remind_kindex_on_git
tool_pattern: "^Bash$"
conditions: ["contains(parameters, 'git ')"]
action: INJECT
inject:
trigger:
mode: exponential
peak: 0.35
cooldown_seconds: 300
peak_after_seconds: 1800
max_per_session: 3
payload:
text: "Before committing, check whether project `.kin` files should be included."
トリガーモード:
| モード | 動作 |
|---|---|
constant / step | クールダウン後、固定確率で発動 |
linear | peak_after_seconds の期間で 0 から peak まで上昇 |
exponential | 指数減衰により peak に近づく |
ペイロードのソース:
| ソース | 備考 |
|---|---|
text | インラインのリテラルテキスト |
text_file | ~/.signet/injections/ 内のファイル名のみ |
from_command | ~/.signet/inject_commands.yaml の HMAC 署名付き許可リストエントリ。直接実行し、シェルは使用しません |
テンプレート置換はデフォルトで有効です。{tool_name}、{cwd}、{date}、{matched_param.X} を使用できます。examples/inject_examples.yaml を参照してください。
条件関数
| 関数 | 説明 | 例 |
|---|---|---|
contains(parameters, 'X') | ツール入力に文字列が含まれる | contains(parameters, 'rm ') |
any_of(parameters, 'X', 'Y') | いずれかの文字列が含まれる | any_of(parameters, 'mkfs', 'format') |
param_eq(field, 'value') | フィールドが値と等しい | param_eq(category, 'books') |
param_ne(field, 'value') | フィールドが値と等しくない | param_ne(role, 'admin') |
param_gt(field, N) | フィールドが数値より大きい | param_gt(amount, 100) |
param_lt(field, N) | フィールドが数値より小さい | param_lt(amount, 5) |
param_contains(field, 'X') | フィールドに部分文字列が含まれる | param_contains(command, 'sudo') |
matches(field, 'regex') | フィールドが正規表現に一致する | matches(file_path, '\\.env$') |
has_credential('name') | 認証情報が保管庫に存在する | has_credential('cc_visa') |
spend_gt('cat', N) | セッションの支出が上限を超える | spend_gt('books', 200) |
spend_plus_amount_gt('cat', field, N) | 支出とこの金額の合計が上限を超える | spend_plus_amount_gt('books', amount, 200) |
not(condition) | 条件を否定する | not(param_eq(format, 'json')) |
or(A || B) | いずれかの条件を満たす | or(contains(parameters, '-f') || contains(parameters, '--force')) |
has_recent_action('search', N) | ツール名または詳細が一致する、直近の許可済みアクション。パイプ区切りで OR 判定 | has_recent_action('EnterPlanMode|TaskCreate', 500) |
has_current_session() | フックホストが一意のチャット/セッション識別子を提供した | has_current_session() |
contains_masked_value(parameters) | ツール入力にシークレットのマスキングの参照ファイルに記載されたリテラル値が含まれる。フィールド名も指定可能。設定がない場合は一致しない | contains_masked_value(command) |
true / false | リテラル | true |
モデルスコープのルール
フックモードの呼び出しには、ツール呼び出しを行ったモデルを示す agent_model フィールドが含まれる場合があります。この値を提供できるのはホストだけです。Signet はフックエンベロープの model(文字列、または id を持つオブジェクト)か、Antigravity の modelName のみを読み取り、それ以外は読み取りません。
- ツール入力内の
agent_modelは、すべての評価経路(すべてのフックアダプター、MCP プロキシ、Kindex のタスク受け入れ)で破棄されるため、エージェントがモデルを偽って申告することはできません。ホストは元のツール入力を引き続き実行します。 - Signet はセッションのトランスクリプトからモデルを読み取りません。エージェントはそのファイルを書き換えられるため、そこに記録されたモデルは事実ではなく、自己申告にすぎません。
- Claude Code の従来の
PreToolUse入力にはモデルフィールドがないため、従来の Claude フックではagent_modelは認識されません。オプションの関数アダプター(adapters/claude-function)は、ホストが値を提供する場合に、ホストの$.session.model()の応答を渡します。これはセッションのモデルです。サブエージェント自身のモデルを示しているかどうかは保証されません。 - MCP プロキシと Kindex の受け入れ呼び出しには、ホストが証明したモデルがないため、このフィールドは常に存在しません。
- このフィールドが付与されるのは、ルールまたは有効なプリフライトで
agent_modelが指定されている場合のみです。それ以外のポリシーから見たツール入力は、これまでと変わりません。
モデルが不明な場合、このフィールドは存在せず、空文字列として比較されます。不明なモデルを拒否するには、許可リストを否定する条件を記述します。
- name: cloud_tools_require_opus
tool_pattern: "^Bash$"
conditions:
- "matches(command, '(^|[;&|(\\s])(gcloud|cloud-sql-proxy)(\\s|$)')"
- "not(matches(agent_model, '^claude-(opus|fable)-'))"
action: DENY
locked: true
reason: "gcloud and cloud-sql-proxy are limited to Opus and Fable"
モデルを報告しないホストでは、このルールに一致するすべての呼び出しが拒否されます。 コマンドの照合は引き続き部分文字列ベースのため、インタープリターやラッパースクリプトを介して同じバイナリに到達しようとするエージェントは、これを回避できる可能性があります。
シークレットのマスキング
任意です。シークレットを含むシェル環境ファイルを指定する ~/.signet/secret_mask.yaml(または $SIGNET_DIR/secret_mask.yaml)を作成します。
files: [~/.profile] # required; nothing is masked without files
keys: [OPENAI, "AWS_*_KEY"] # optional; default fragments below
min_length: 8 # optional; shorter values are ignored
このファイルがない場合、この機能は無効です。~ は $HOME に展開されます。相対パスは signet ディレクトリからの相対パスです。このファイルは ~/.signet/ の下に置かれるため、自己保護ルールによりエージェントは編集できません。
各参照ファイルは1行ずつ読み込まれます。省略可能な export に続き、NAME が [A-Za-z_][A-Za-z0-9_]* に一致する NAME=VALUE の形式である必要があります。値の前後にある引用符は取り除かれ、引用符で囲まれていない値の末尾にある #comment は削除されます。$ またはバッククォートを含む値、閉じていない引用符や連結された引用符を含む値、および min_length より短い値はスキップされます。
名前に keys のエントリーが含まれるキーが選択されます。大文字と小文字は区別されず、* は任意の文字列に一致します。そのため、完全な名前を指定した場合も、その名前を含む長い名前が選択されます。keys を指定しない場合、デフォルトの断片は KEY、TOKEN、SECRET、PASSWORD、PASSWD、PASS、PW、CREDENTIAL、AUTH、PRIVATE、SID、DSN、WEBHOOK、COOKIE、CLIENT_ID、ACCOUNT_ID、API です(src/secret_mask.rs の DEFAULT_KEY_PATTERNS)。
選択された値が出現するたびに、またその JSON エスケープ表記も、$NAME に置き換えられます。長い値から先に置換され、同じ長さの値はファイル内の順序で優先されます。複数の名前で共有される値は最初の名前でマスクされ、同じ名前が2回定義されている場合は両方の値がマスクされます。ファイルはキャッシュされ、mtime またはサイズが変わると再読み込みされます。ファイルが存在しない、または読み取れない場合は、パスを示す警告が stderr に1回出力され、そのファイルの値はマスクされません。設定が無効な場合は、警告が1回出力されてマスキングが無効になります。
マスキングは、signet-eval が保存または表示する情報に適用されます。対象は、アクション台帳、事前チェックの記録と違反、Kindex の結果の配信、Claude 関数アダプターで使われる integration redact サニタイザー、MCP の管理応答(最近のアクション、ステータス、違反、ルール一覧、テスト結果)、MCP プロキシの理由、フックの拒否/確認理由と参考情報、rules、test、log の CLI 出力です。ポリシーの評価対象となる入力は変更せず、ホストが実行するコマンドも書き換えません。マスクされた値を含む事前チェック定義は、ほかのシークレットと同様に拒否されます。Vault の認証情報は指定されたとおりに保存されます。
コマンドで値そのものが本当に必要になる場合もあります。そのため、デフォルトのルール block_masked_secret_literal は、ツール入力に値が含まれている場合、拒否ではなく確認を求めます。その理由にはキー($NAME)が記載され、値そのものは記載されません。また、代わりに $NAME を使うよう提案します。ほかのロックされていないデフォルトルールと同様に、rules.yaml でこのルールを上書きできます。ルールの理由や代替案では、{masked_keys} プレースホルダーを使用できます。これは一致したキー名に展開されます。signet-eval status は、マスクされたキー名とファイル数を報告します。
マスキングによって signet-eval が表示する情報から値を除外できますが、ホストがツールの出力をモデルに送信することは防げません。そのため、ロックされたルール protect_secret_reference_files は、コマンドまたはパスに参照ファイル名が含まれるツール呼び出しを拒否します。たとえば、cat ~/.profile、grep KEY $HOME/.profile、そのファイルに対する Read ツールの使用、そのファイルの編集やパッチ適用、またはコマンドがそのディレクトリ内で実行される(あるいは cd で移動する)場合のファイル名だけの指定が該当します。source FILE と . FILE は何も出力しないため許可されます。読み込んだ変数は名前で使用してください。書き込まれる内容、プロンプト、説明は検査されないため、ドキュメントでファイルに言及してもかまいません。一致判定は字句的に行われます。glob、シンボリックリンク、エージェントの外部で作成されたコピー、親ディレクトリの再帰検索は検出されません。設定がない場合、このルールは一致しません。
暗号化された Vault
パスフレーズから導出した鍵階層(Argon2id + AES-256-GCM)による3層の暗号化ストレージです。
| 層 | 暗号化 | 内容 |
|---|---|---|
| 1 | なし | アクションログ、支出台帳 |
| 2 | セッションキー | セッション状態 |
| 3 | コンパートメントキー | クレジットカード番号、API トークン、シークレット |
signet-eval setup # create vault with passphrase
signet-eval store cc_visa 4111... # store Tier 3 credential
signet-eval status # vault status and spending
signet-eval log # recent action log
signet-eval unlock # refresh session after timeout
認証情報は request_capability によるスコープ付きアクセスに対応しています。ドメイン制限、目的の制約、使用ごとの金額上限、および1回の使用後に自動的に無効化されるワンタイムトークンを設定できます。
支出上限には Vault 台帳を使用します。金銭を消費するツール呼び出しはすべて記録され、spend_plus_amount_gt() が累計額を確認してから次の購入を許可します。
自己保護
signet-eval には、AI エージェントが自身のポリシー適用を無効化できないようにするロック済みルールが含まれています。
-
protect_signet_dir —
.signet/(ポリシーファイル、Vault、HMAC)に触れる Write、Edit、または Bash コマンドを拒否します -
protect_signet_binary —
signet-evalバイナリ自体への改変を拒否します -
protect_hook_config —
settings.json(フックが設定されている場所)の変更前にユーザーの確認を求めます -
protect_signet_process — signet プロセスを対象とする kill/pkill/killall コマンドを拒否します
-
protect_preflight_storage — エージェント側による preflight レコードの変更を拒否します
-
require_kindex_engagement_before_edits — 永続的なセッションコンテキストが記録されるまで、直接編集ツールを拒否します
-
prefer_persistent_task_store — 上記の5つの Claude タスク状態ツールを拒否し、エージェントに永続的な Kindex タスクを案内します。
Agent、レガシーサブエージェントのTask、TaskOutput、TaskStopはタスク状態ツールではないため、このルールではブロックされません。 -
protect_checks_dir — エージェント側による信頼済み ENSURE スクリプトの置き換えを拒否します
-
protect_vault_passphrase — Vault のセットアップとロック解除の操作を人間に限定します
-
protect_signet_symlink — 保護された適用対象を狙うシンボリックリンクによる回避を拒否します
-
protect_secret_reference_files —
secret_mask.yamlに記載された env ファイルの読み取りを拒否します。sourceは引き続き許可されます(「シークレットのマスキング」を参照)
これらのルールには、次の特性があります。
- ロック済み — MCP ツールは、これらのルールの削除、編集、並べ替えを拒否します
- 位置保護 — ロック解除済みのルールを、ロック済みルールより上に並べ替えることはできません(最初に一致したルールを優先)
- デフォルトにハードコード — ポリシーファイルが破損または欠落している場合、バイナリは自己保護を含むハードコード済みのデフォルトにフォールバックします
- バージョン照合 — 現在のコンパイル済みデフォルトが、ルール名に基づいて古いシステムポリシーのスナップショットを上書きするため、アップグレード時に
initを再実行する必要はありません - 予約名の照合 — 組み込みルール名はバイナリが所有します。ホスト固有のシステムルールには別の名前を使用する必要があり、ユーザールールはロック解除済みデフォルトのサポート対象オーバーライドレイヤーとして引き続き利用できます
- HMAC による保護 — ファイルを直接編集するとポリシー署名が破損し、安全なデフォルトへのフォールバックが発生します
MCP 管理サーバー
Claude を通じてポリシーを会話形式で管理します。
claude mcp add --scope user --transport stdio signet -- signet-eval serve
| ツール | 目的 |
|---|---|
signet_list_rules | ロック状態とともにすべてのルールを表示します |
signet_add_rule | 新しいルールを追加します(ロックされたルールの後に追加されます) |
signet_remove_rule | ルールを削除します(ロックされたルールは拒否されます) |
signet_edit_rule | ルールのプロパティを変更します(ロックされたルールは拒否されます) |
signet_reorder_rule | ルールを移動します(ロックされたルールの移動、およびロックされたルールより上への配置は拒否されます) |
signet_set_limit | カテゴリーの支出上限を設定します |
signet_test | 現在のポリシーに照らしてツール呼び出しをテストします |
signet_validate | ポリシーにエラーがないか確認します |
signet_condition_help | 利用可能な条件関数を表示します |
signet_status | Vault の状態、支出合計、認証情報の数を表示します |
signet_recent_actions | 最近のアクションログを表示します |
signet_store_credential | Tier 3 認証情報を保存します |
signet_use_credential | 機能制約を通じて認証情報を要求します |
signet_list_credentials | 認証情報名を一覧表示します |
signet_delete_credential | 認証情報を削除します |
signet_sign_policy | ポリシーファイルに HMAC 署名します |
signet_reset_session | 支出カウンターをクリアします |
Vault が利用可能な場合、変更を伴うすべての操作でポリシーに自動署名します。
MCP プロキシ
ポリシー適用機能を備えたプロキシで、上流の MCP サーバーをラップします。エージェントはサーバーに直接接続せず、プロキシに接続します。ポリシーは呼び出しごとにホットリロードされます。
# Configure upstream servers
cat > ~/.signet/proxy.yaml << 'YAML'
servers:
linear:
command: npx
args: ["-y", "mcp-linear"]
env:
LINEAR_API_KEY: "your-key"
YAML
# Register proxy with Claude Code
claude mcp add --scope user --transport stdio signet-proxy -- signet-eval proxy
すべてのコマンド
| コマンド | 目的 |
|---|---|
signet-eval | フックの評価(デフォルト、25ms) |
signet-eval --adapter codex | Codex PreToolUse フックの評価 |
signet-eval --adapter codex-permission | Codex PermissionRequest フックの評価 |
signet-eval --adapter antigravity | Antigravity PreToolUse フックの評価 |
signet-eval --adapter cursor | Cursor preToolUse、beforeShellExecution、beforeMCPExecution、beforeReadFile フックの評価 |
signet-eval --adapter muse | Muse Code PreToolUse(およびオプションの PermissionRequest)フックの評価 |
signet-eval integration describe | JSON 標準入力から読み取り専用でポリシー/機能を検査します |
signet-eval integration adjudicate | 範囲指定およびリビジョンに紐付けられた Kindex タスクの受け入れを行い、永続的な意図レシートを作成します |
signet-eval integration record-result | Kindex タスクレシートを冪等に配信します。実行の証明ではありません |
signet-eval integration redact | 制御された出力投影のための構造化サニタイザーです |
signet-eval integration install-modern | バックアップを作成して、バイナリに埋め込まれた Claude アダプターを明示的にインストールします。強制適用の無効状態は維持されます |
signet-eval init | 自己保護のロック済みルールを含むデフォルトポリシーを書き込みます |
signet-eval rules | 現在のポリシールールを表示します(ロック済みルールにはタグが付きます) |
signet-eval validate | ポリシーにエラーがないか確認します |
signet-eval test '<json>' | ポリシーに照らしてツール呼び出しをテストします |
signet-eval setup | 暗号化 Vault を作成します |
signet-eval unlock | Vault セッションを更新します |
signet-eval status | Vault の状態と支出を表示します |
signet-eval store <name> <value> | Tier 3 認証情報を保存します |
signet-eval delete <name> | 認証情報を削除します |
signet-eval log | 最近のアクションログを表示します |
signet-eval reset-session | 支出カウンターをクリアします |
signet-eval sign | ポリシーファイルに HMAC 署名します |
signet-eval injections | 最近発生した inject ルールを表示します |
signet-eval inject-test <rule> | テスト用に inject ルールを1つ強制的に発生させます |
signet-eval serve | MCP 管理サーバー(17 個のツール) |
signet-eval proxy | 上流サーバー用の MCP プロキシ |
パフォーマンス
| 指標 | 値 |
|---|---|
| フック評価(エンドツーエンド) | 25ms — プロセスの起動、標準入力、JSON の解析、ポリシーの読み込み、評価、応答 |
| プロセス内ポリシー評価 | 14–63μs — 拒否は14μs、確認は21μs、支出チェックは63μs |
| CLI の検証/ルール表示 | 8ms |
| バイナリサイズ | 6.2MB(ストリップ済み、LTO) |
アーキテクチャ
signet-eval は、Signet のパーソナルなソブリンエージェントスタックにおける強制レイヤーです。中核となる原則は、認可レイヤーを LLM にしてはならないということです。処理するのは構造化データのみで、正規表現、比較、ボールトへのクエリを用います。自然言語も、コンテキストウィンドウも、説得を受け入れる余地もありません。ルールに一致するか、しないかのどちらかです。
Agent proposes action -> signet-eval evaluates policy -> allow / deny / ask
(deterministic, 25ms, no NLP)
セキュリティモデル
signet-eval は檻ではなくシートベルトです。何を防ぎ、何を防げないのかを理解することが重要です。
防止できること
協調的なエージェントによるミス。 Claude Code、Codex、Antigravity、Cursor、Muse Code はフックプロトコルに従い、ツールの使用前後に signet-eval を呼び出し、サポートされている応答を尊重します。これらのプロトコルの範囲内で、signet-eval はポリシーを確実に適用します。
- 破壊的なコマンド(
rm、mkfs、パイプ経由のリモート実行)をブロックします - ツール呼び出し全体にわたって支出制限を適用します
- ドメイン、目的、金額の制約によって認証情報へのアクセスを制限します
- 機密性の高い操作(
git push --force)にはユーザーの確認を必須にします - ロックされたルールと MCP ガードによって、安易なポリシー改ざんを防ぎます
これが通常の動作モードです。エージェントは逃げようとしているのではなく、役に立とうとしており、ポリシーがその範囲内にとどめます。
Codex のサポートには、重要な意味上の違いが 1 つあります。現在、適用において PreToolUse で可能なのは拒否のみです。そのため、Signet の ALLOW は出力を行わず、Signet の ASK はその段階で拒否に変換されます。PermissionRequest アダプターは、Codex が承認を求めるためにすでに送信しようとしていたリクエストを明示的に許可または拒否します。Signet の ASK は Codex の通常の承認プロンプトに委ねられます。
Antigravity はネストされた toolCall ペイロードを送信し、トップレベルの decision 応答を期待します。アダプターはネイティブのコマンドツールとファイルツールを Signet の正規ポリシー名に正規化し、call_mcp_tool を mcp__<server>__<tool> に展開します。また、ネイティブラッパーの形式が不正な場合は、フェイルクローズします。
Cursor の仕様(cursor-agent 2026.10.01 に対して検証済み):アダプターは
hook_event_name を読み取り、Cursor のフラットな permission オブジェクトで応答します。確認を求められるのは
beforeShellExecution のみで、この場合、Signet の ASK は Cursor の承認
プロンプトになります。preToolUse で適用できるのは拒否のみです。また、Cursor のドキュメントには記載されていますが、cursor-agent は
beforeMCPExecution での ask を無視します。さらに、
beforeReadFile が受け付けるのは allow または deny のみなので、これら
3 つのイベントでは Signet の ASK は拒否になります。Cursor の Shell
ツールは Bash に対応し、beforeMCPExecution は Cursor の JSON 文字列から
デコードした引数とともに mcp__<server>__<tool> に対応します。一方、
preToolUse では MCP 呼び出しはサーバー名のない MCP:<tool> としてしか認識されません。そのため、サンプルでは MCP を専用のイベントに割り当てています。
beforeReadFile が評価するのはパスであり、Cursor が添付するファイルの内容ではありません。
Cursor は空の出力をフックの失敗とみなすため、Signet は allow を明示的に出力します。Cursor は、エントリーに
failClosed: true が設定されていない限り、フックがクラッシュするか、タイムアウトするか、ゼロ以外のコードで終了するとフェイルオープンします。サンプルではこれを設定しています。無効な JSON はいずれの場合もアクションをブロックします。Cursor は Claude Code の
~/.claude/settings.json とプロジェクトの .claude/settings*.json からもフックを実行します。これらには Cursor のペイロードが渡されるため、そこにある通常の signet-eval Claude フックは、Cursor 内で正規化されていない評価をもう一度実行します。コマンドが異なるため、Cursor アダプターとの重複排除は行われません。
Muse Code の仕様(Muse 1.4.6 に対して検証済み):Muse は、独自のツール名を持つ Claude 形式の
PreToolUse ペイロードを送信します。アダプターは shell(および
bash、bash_input、exec_command、execute_command)を Bash に、
read_file/write_file/edit_file を Read/Write/Edit に対応させます(ネイティブの
path を file_path にコピーします)。また、search を Grep に、
web_fetch/web_search を WebFetch/WebSearch に対応させます。MCP ツールはすでに mcp__<server>__<tool> として届きます。
Muse の PreToolUse で適用できるのは拒否のみです。ask は無視され、単独の
allow は拒否されるため、Signet の ALLOW は出力を行わず(または注入ナッジの場合に限り additionalContext のみを出力し)、Signet の ASK は拒否になります。Muse にはフェイルクローズのフックオプションがありません。フックがクラッシュするか、タイムアウトするか、解析できない場合、ツール呼び出しは続行されます。.muse/hooks.json にあるプロジェクトフックは、ワークスペースが信頼されるまで無効のままです。Muse は Claude Code や Codex のフックを実行しません。アダプターは Codex の応答形式による
PermissionRequest も受け付けます(ASK は Muse のプロンプトに委ねられます)が、サンプルでは省略しています。デフォルトの ALLOW ポリシーでは、Muse が確認を求めようとしていた呼び出しをすべて許可してしまうためです。
保護できないもの
シェルアクセス権を持つ敵対的なエージェント。 signet-eval は、制約対象のエージェントと同じ権限レベルで実行されます。同じ UID を持つプロセスは、次の操作を実行できます。
- シェルの間接実行を使って文字列マッチングを回避する(
alias、eval、base64 -d | sh、python3 -c "...") - 保護対象のパスへのシンボリックリンクを無害な名前で作成する
- セッションキーファイルを読み取り、偽造した HMAC 署名を作成する
- signet-eval バイナリ自体を置き換える
settings.jsonのフック設定を変更するLD_PRELOAD、ptrace、プロセスインジェクションを使う
パターンマッチングをどれだけ行っても、これを解決することはできません。ln のルールを追加すれば、alias を使うようになります。alias をブロックすれば、eval を使うようになります。eval をブロックすれば、python3 -c を使うようになります。これは際限のないいたちごっこです。根本的な問題はパターンの網羅性ではなく、権限レベルにあります。
実際の封じ込めを担うもの
真に敵対的なエージェントから保護するには、エージェントの権限レベルを超えて動作するOS レベルの制御が必要です。
- 別のユーザーアカウント — ポリシーファイルへの書き込み権限を持たない制限付きユーザーとしてエージェントを実行します
- コンテナ/サンドボックス —
~/.signet/を読み取り専用でマウントした Docker、Flatpak、またはbubblewrapを使用します - 制限した
$PATH— エージェントの環境からln、aliasなどの間接実行ツールを削除します - seccomp / AppArmor / SELinux — エージェントが上書きできない強制アクセス制御を使用します
- 仮想環境 — ファイルシステムへのアクセスを制限した環境で Claude Code を実行します
signet-eval は、このような構成におけるポリシーレイヤーです。明確で監査可能なルールを使って、「このエージェントに何を許可すべきか」という問いに対応します。OS は「このエージェントがポリシーを回避できるか」という問いに対応します。どちらも、もう一方の代わりにはなりません。
多層防御
各レイヤーが連携して機能します。
| レイヤー | 保護対象 | 仕組み |
|---|---|---|
| 文字列マッチング | 明らかなミス、分かりやすい UX | 正規表現、部分文字列、単語境界条件 |
| ロックされたルール | MCP ベースのカジュアルなポリシー改ざん | 不変のルール、位置の保護 |
| HMAC 署名 | ファイルへの帯域外の変更 | 暗号学的な整合性検証 |
| OS 制御 | 権限昇格、シェルの間接実行 | サンドボックス化、RBAC、別のユーザー |
OS 制御がなければ、signet-eval は壁ではなく、ただの減速帯です。OS 制御と組み合わせれば、安全な境界内のポリシーエンジンとして機能します。
ライセンス
MIT
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。