sasacode-plugin-jev-guard
v1.0.0
Published
A second opinion on tool calls from TypeSafe's Jev before they run: stops dangerous calls that would run unasked, hands safe softDeny calls to you
Maintainers
Readme
sasacode-plugin-jev-guard
A plugin for sasacode (plugin API ^1.8.0): a second opinion on tool calls from TypeSafe's Jev before they run. It was bundled with sasacode up to 0.9.5.
sasacode plugin install sasacode-plugin-jev-guard日本語
ルールと権限モードの判定の後に、Jev の判定を重ねる。Jev は文章を返さず、型付きの質問に確率で答えるモデルで、1回あたり数百ミリ秒で済む。
TUI で /jev on と打てば、そのセッションで有効になる(/jev off で無効。/resume した後も保たれる)。いつも使うなら設定に書く:
{ "plugins": { "settings": { "jev-guard": { "enabled": true } } } }Jev への接続先は
backendで選ぶ。指定がなければ、CMD_API_KEYかTYPESAFE_API_KEYのある方を使う(どちらもキーチェーンのcommandcode/typesafeでもよい)。|
backend| 接続先 | キー | 既定のmodel| | --- | --- | --- | --- | |commandcode| Command Code の Provider API(GOAT 以上のプラン) |CMD_API_KEY|typesafe/jev| |typesafe| TypeSafe の API |TYPESAFE_API_KEY|jev-latest| |openrouter| OpenRouter の Decisions API(alpha) |OPENROUTER_API_KEY|typesafe/jev-latest| |vercel| Vercel AI Gateway |AI_GATEWAY_API_KEY|typesafe-ai/jev| |chat| sasacode の任意のモデル(modelに"<provider>/<model>"、省略で現在のモデル) | そのプロバイダーのキー | — |OpenRouter と Vercel は、チャット用にキーを持っているだけの人に判定を送らないよう、名前を指定したときだけ使う。
endpointとapiKeyEnvで接続先の URL とキーの変数を変えられる(プロキシなど)。動作を実際の API で確かめたのはcommandcodeとchatだけで、typesafe/openrouter/vercelは公開されている仕様どおりの形で送る(テストは模擬サーバー)。chatは Jev の代わりにチャットモデルへ同じ質問をし、JSON で答えさせる。確率が較正されていない代用品で、遅い。実際のコマンドで比べると、DeepSeek V4.1 Flash は止めるべき呼び出しを Jev より多く通した(docs/benchmarks.md)。ローカルモデルは1回に数十秒かかり実用的でない。Jev に接続できない環境で、判定の仕組みだけ使いたいとき向け。有効にすると、ツール呼び出しの内容(コマンド、変更されうるパスとその git の状態、ユーザーの直近の依頼)が接続先に送られる。API キーやトークンらしき文字列は、送る前に伏せる(ベストエフォート)。
判定を変えるのは次の場合だけ。
- 確認なしで実行されるはずだった呼び出し(allow ルール、
autoモード): 危険なら拒否、要確認なら確認に回す。 agentモードで確認に回るはずだった呼び出し: 安全なら確認なしで実行する(モデルによる判定の代わり)。Jev が判断を保留したときは、従来どおりモデルが判定する。- softDeny の呼び出し: 安全なら、拒否せずユーザーに確認する。
- 確認なしで実行されるはずだった呼び出し(allow ルール、
ユーザーに確認するはずの呼び出しを、Jev が拒否に変えることはない(確認ダイアログに Jev の判定を添える)。deny ルールの呼び出しは Jev に送らない。
Jev に渡すのは、ハーネスが集めた事実とユーザー自身の依頼だけで、ツールの出力やファイルの中身は渡さない(Jev は状態に紛れ込んだ誘導文に影響されうるため)。
読み取りと、作業ディレクトリ内の編集は判定しない。Jev に届かないとき(キーがない、通信エラー、タイムアウト 5 秒)は、Jev なしの判定のまま続ける。
閾値は
thresholds(allow0.8、ヘッドレスでのheadlessAllow0.9、deny0.85、confidence0.6、risk0.6、flag0.7、clear0.3)で変えられる。ほかの設定はtimeoutMs(既定 5 秒、chatは 60 秒)、skip(判定しないツール。既定todo_write、task)。/jevで状態と直近の判定を見られる。/jev on//jev offでこのセッションの有効・無効を切り替える(キーがなければ有効にせず理由を示す)。判定はセッションにも記録する。Jev はコマンドの文字列から判断するので、
ssh host 'ps aux'のような他のマシンでの読み取りは安全と見る。またbun run cleanのようにスクリプトの中身が見えない呼び出しは、中身が危険でも気づけない。他のマシンへの操作はguardプリセットが常に確認に回す。スクリプト経由の呼び出しも必ず確認したいなら、ルールで決める(例:"permissions": { "ask": ["bash(bun run *)", "bash(make *)"] })。実際のセッションログ 5,135 件での結果: 安全な呼び出しの 92% が auto で止められず、agent モードでは 71% が確認なしで通る。要確認のものが agent で確認なしに通ったのは 1%(ローカル)。詳細は docs/benchmarks.md。
English
Adds Jev's judgment after the rules and the permission mode. Jev answers typed questions with probabilities instead of text and takes a few hundred milliseconds a call.
Type /jev on in the TUI to turn it on for the session (/jev off turns it off; the choice survives /resume). To have it always, put it in the config:
{ "plugins": { "settings": { "jev-guard": { "enabled": true } } } }backendpicks where Jev is reached. Without it, whichever ofCMD_API_KEYandTYPESAFE_API_KEYis set is used (the keychain entriescommandcode/typesafework too).|
backend| Endpoint | Key | Defaultmodel| | --- | --- | --- | --- | |commandcode| Command Code's Provider API (GOAT plan or above) |CMD_API_KEY|typesafe/jev| |typesafe| TypeSafe's API |TYPESAFE_API_KEY|jev-latest| |openrouter| OpenRouter's Decisions API (alpha) |OPENROUTER_API_KEY|typesafe/jev-latest| |vercel| Vercel AI Gateway |AI_GATEWAY_API_KEY|typesafe-ai/jev| |chat| Any sasacode model (model:"<provider>/<model>", the current model if omitted) | that provider's key | — |OpenRouter and Vercel are used only when named, so people who hold those keys for chat do not start sending judgments.
endpointandapiKeyEnvchange the URL and the key variable (for proxies). Onlycommandcodeandchathave been checked against the real APIs;typesafe/openrouter/vercelsend what their published specs describe (tested against mock servers).chatasks a chat model the same questions and has it answer in JSON. It is an uncalibrated and slow stand-in: on real commands, DeepSeek V4.1 Flash let through more calls that should have been stopped than Jev (docs/benchmarks.md), and local models take tens of seconds a call. It is for when Jev cannot be reached but you want the mechanism.When enabled, the call (command, paths it may change and their git state, your latest request) is sent to the endpoint. Strings that look like API keys or tokens are masked first (best effort).
It changes a decision only in these cases:
- A call that would run without asking (allow rules,
automode): dangerous → denied, needs a look → asks. - A call that
agentmode would ask about: safe → runs without asking (instead of the model's judgment). When Jev holds back, the model judges as before. - A softDeny call: safe → asks you instead of refusing.
- A call that would run without asking (allow rules,
Jev never turns a call you would be asked about into a refusal (its verdict is added to the approval dialog). Calls denied by a rule are not sent to Jev.
Jev gets only facts the harness collected and your own request, never tool output or file contents (Jev could be steered by instructions hidden in them).
Reads and edits inside the working directory are not judged. When Jev cannot be reached (no key, network error, 5-second timeout), the decision stands without it.
Thresholds are set with
thresholds(allow0.8, headlessheadlessAllow0.9,deny0.85,confidence0.6,risk0.6,flag0.7,clear0.3). Other settings:timeoutMs(default 5 seconds, 60 forchat) andskip(tools never judged; defaulttodo_write,task)./jevshows the state and the latest judgments./jev on//jev offswitch it for this session (without a key it stays off and says why). Judgments are also recorded in the session.Jev judges by the command line, so a read on another machine such as
ssh host 'ps aux'looks safe, and a call whose script it cannot see, such asbun run clean, is judged without knowing what the script does. Theguardpreset always asks before operations on other machines. To always be asked about scripts, write a rule (e.g."permissions": { "ask": ["bash(bun run *)", "bash(make *)"] }).On 5,135 calls from real session logs: 92% of the safe calls are not stopped in
auto, 71% run without asking inagent, and 1% of the calls that need a look ran without asking inagent(locally). Details in docs/benchmarks.md.
