myaji35/GH_Harness/tree/main/mods/harness-guard
この mod について
harness-guard mod
5 つの既存 PreToolUse shell フックを関数フックに置き換える Claude Code 2.1.289 版です。tool.call ハンドラーを 1 つ登録します。デフォルトの shadow モードでは呼び出しごとに判定し、判定結果、理由、経過ミリ秒を ~/.claude/harness-core/logs/mod-guard-shadow.jsonl に書き込んでから next(e) を呼びます。enforce は拒否判定に対して { deny: message } を返し、それ以外では next(e) を呼びます。このモードでは RTK の書き換えも next に渡されます。
| 既存フック | 移植されたルール |
| --- | --- |
| freeze-guard.sh | Write/Edit の際、凍結ファイルが存在している間は FREEZE_DIR 外のパスをブロックします。レジストリに issue を持つ凍結は、IN_PROGRESS または BACKGROUND_RUNNING の場合だけ有効です。 |
| sandbox-enforce.sh | 危険な削除、破壊的なデバイス書き込み、安全でない chmod、shell へのパイプ、sudo rm を Bash でブロックします。強制 push、hard reset、クリーンアップ、SQL 削除、デプロイ削除、公開には警告/T2 パターンを使います。HARNESS_SANDBOX_BYPASS=1/2 では shell の意味を保ちます。 |
| secret-guard.sh | git commit または git push を含む Bash コマンドでは、まずステージ済みファイル名を確認し、次に追加された diff 行を確認します。テスト/spec のパスとプレースホルダー値は除外します。Write/Edit 完了後は、編集したファイルに secret があれば警告します。 |
| rtk-guard.sh | 対応している可能性のあるコマンドの書き換えを rtk hook claude に依頼します。RTK がない、または失敗した場合はそのまま通します。 |
| health-gate.sh | レジストリを伴う commit で、利用可能な typecheck、tsc、lint、Rubocop、TODO チェックを実行し、スコア履歴を記録します。スコアが少なくとも 5 点下がった場合だけ警告します。 |
設定
claude --plugin-dir mods/harness-guard で読み込みます。デフォルトは shadow です。強制実行するには、ユーザー設定(~/.claude/settings.json)に設定を追加するか、/config で Guard mode → enforce を選びます。
{"pluginConfigs":{"harness-guard":{"options":{"mode":"enforce"}}}}
シャドーログを比較している間は既存の shell フックをインストールしたままにします。シャドーのヘルススコアと回帰比較には .claude/knowledge-db/health-history.mod-shadow.jsonl を使い、shell health-gate は .claude/knowledge-db/health-history.jsonl を使い続けます。enforce に切り替えるときは、enforce モードが共有履歴ファイルを使うため、shell の health-gate.sh フックも同時に無効にします。戻すにはこの mod を無効にするか --plugin-dir を削除し、無効にしていた shell health-gate を再び有効にします。
検証
test/capture-expected.sh は一時 git リポジトリを作成し、stdin JSON で各実際の shell フックを実行して、test/fixtures.json(source: shell)に 38 件の fixture 判定を記録します。test/fixtures.ts は同じキャプチャーから生成されます。JSON モジュールを import できない Claude Code テストランナー向けです。テストは各 fixture と mod 対応の判定関数を比較します。CLI が ._* AppleDouble ファイルをテストと誤認するため、テストコマンドの前にそれらを無視して削除します。
既知の相違点
- 従来の sandbox フックはトップレベルの
commandフィールドを想定しますが、他のフックはtool_inputエンベロープを読みます。Sandbox fixture はスクリプトのトップレベル形式を使います。mod はe.commandを直接見るため危険なコマンドを一貫して検出しますが、エンベロープ付きの従来の呼び出しでは見逃す可能性があります。 - 完全な判定を 10 秒未満に収めるため、mod はヘルスチェックに 5 秒のサブ予算を使い、プロセスごとに 1.2 秒の上限を設けます。shell worker は全体で 45 秒、各チェックで 20 秒を許可します。そのため、遅いチェックはスキップまたはタイムアウトになり、異なるスコアになることがあります。
- 提供されている Claude Code API 型は
$.fs.readと$.fs.writeを公開していますが、append メソッドはありません。シャドーログとヘルス履歴は$.fs.writeで読み書きし直すため、同時に動く Claude セッションでは追加した行が失われる可能性があります。Shell append はファイルディスクリプター単位でアトミックです。シャドーのヘルス履歴は shell ファイルとは別で、shell ファイルを読み書きするのは enforce モードだけです。 - enforce モードでは拒否する前に
request-user-confirm.shを WARN+T2 に対して呼び出します。Shell sandbox も block/warn イベントでdecision-trace.shを呼びますが、mod は代わりに JSONL の判定記録を使うため、従来の trace 行は追加しません。shell と mod の両方が有効だと、T2 ヘルパーが 2 回呼ばれることがあります。 - Shell の
sourceは凍結ファイル内の任意コードを受け付けます。mod はリテラルのFREEZE_DIRとFREEZE_ISSUEの代入を読むため、生成された凍結ファイルをカバーしつつ任意の shell コードは実行しません。 - Write/Edit の
tool.call完了後に、ツール後の secret 警告を再現します。既存のPostToolUseshell フックも有効なままだと、警告が 2 回表示されることがあります。
内部エラーは警告として記録され、そのまま通ります。元の freeze、secret、health フックも解析/チェック失敗時には通します。sandbox の set -e は一部のホストコマンド失敗で非ゼロ終了することがあります。mod の狭いファイルシステム/プロセス呼び出しは、想定されるファイル不足やコマンド不足のエラーを捕捉し、それらの失敗でブロックしません。
インストール
まず作者の README で marketplace とプラグイン名を確認してください。コマンドはリポジトリの構成によって変わる場合があります。
claude plugin marketplace add myaji35/GH_Harness claude plugin install harness-guard
原文 / README
harness-guard mod
Claude Code 2.1.289 function-hook version of five existing PreToolUse shell hooks. It registers one tool.call handler. The default shadow mode evaluates each call, writes its verdict, reasons, and elapsed milliseconds to ~/.claude/harness-core/logs/mod-guard-shadow.jsonl, then calls next(e). enforce returns { deny: message } for deny decisions and otherwise calls next(e); RTK rewrites are passed to next in that mode.
| Existing hook | Ported rule |
| --- | --- |
| freeze-guard.sh | On Write/Edit, block a path outside FREEZE_DIR while the freeze file exists. A freeze with an issue in the registry is active only for IN_PROGRESS or BACKGROUND_RUNNING. |
| sandbox-enforce.sh | Bash block patterns for dangerous deletion, destructive device writes, unsafe chmod, pipe-to-shell, and sudo rm; warning/T2 patterns for force push, hard reset, cleanup, SQL deletion, deployment deletion, and publishing. HARNESS_SANDBOX_BYPASS=1/2 keeps the shell semantics. |
| secret-guard.sh | On Bash commands containing git commit or git push, inspect staged filenames first, then added diff lines, excluding test/spec paths and placeholder values. After Write/Edit completes, warn about a secret in the edited file. |
| rtk-guard.sh | Ask rtk hook claude for a rewrite of likely supported commands; pass through if RTK is absent or fails. |
| health-gate.sh | On commit with a registry, run available typecheck, tsc, lint, Rubocop, and TODO checks, record score history, and warn only if the score drops at least five points. |
Configuration
Load with claude --plugin-dir mods/harness-guard. The default is shadow. To enforce, put this in user settings (~/.claude/settings.json), or choose Guard mode → enforce in /config:
{"pluginConfigs":{"harness-guard":{"options":{"mode":"enforce"}}}}
Keep the existing shell hooks installed while comparing shadow logs. Shadow health scores and regression comparisons use .claude/knowledge-db/health-history.mod-shadow.jsonl; the shell health-gate continues using .claude/knowledge-db/health-history.jsonl. When switching to enforce, disable the shell health-gate.sh hook at the same time, since enforce mode uses the shared history file. To roll back, disable this mod or remove its --plugin-dir, then re-enable the shell health-gate if it was disabled.
Verification
test/capture-expected.sh creates a temporary git repository, executes each real shell hook with stdin JSON, and records 38 fixture verdicts in test/fixtures.json (source: shell). test/fixtures.ts is generated from the same capture for the Claude Code test runner, which cannot import JSON modules. The test compares every fixture with the mod's corresponding decision function. ._* AppleDouble files are ignored and removed before test commands because the CLI otherwise mistakes them for tests.
Known differences
- The classic sandbox hook expects a top-level
commandfield while the other hooks read atool_inputenvelope. Sandbox fixtures use the script's top-level shape. The mod seese.commanddirectly, so it detects dangerous commands consistently; a classic call with an envelope can miss them. - The mod uses a 5-second sub-budget for health checks and 1.2-second per-process caps to keep the complete decision below 10 seconds. The shell worker allows 45 seconds overall and 20 seconds per check. A slow check can therefore be skipped or timed out and yield a different score.
- The supplied Claude Code API type exposes
$.fs.readand$.fs.write, but no append method. Shadow logs and health history are read and rewritten with$.fs.write; simultaneous Claude sessions can lose an appended line. Shell append is atomic at the file descriptor level. Shadow health history is separate from the shell file; only enforce mode reads and writes the shell file. - In enforce mode the mod calls
request-user-confirm.shfor WARN+T2 before denying. The shell sandbox also callsdecision-trace.shfor block/warn events; the mod uses its JSONL decision record instead, so it does not add a legacy trace line. While both shell and mod are enabled, the T2 helper can be called twice. - Shell
sourceaccepts arbitrary code in freeze files. The mod reads literalFREEZE_DIRandFREEZE_ISSUEassignments, which covers generated freeze files without executing arbitrary shell code. - The post-tool secret warning is reproduced after a Write/Edit
tool.callcompletes. While the existingPostToolUseshell hook remains enabled, the warning can appear twice.
An internal error is recorded as a warning and passed through. The original freeze, secret, and health hooks also pass on parse/check failures; sandbox's set -e can exit nonzero for some host command failures. The mod's narrow filesystem/process calls catch expected missing-file or missing-command errors and do not block on those failures.
