feat(guard-pack): all six guards in one Node process - #45
Merged
Conversation
Installing the guards individually costs six Node startups per matching tool call; the pack pays one. Measured on the bench: 38 ms median for the pack vs 199 ms for the six guards separately. The runner mirrors each guard's own main(): same tool filters, same env vars (HOOK_SAFETY_LEVEL uniformly, HOOK_ASK_*, CONFIG_GUARD_ALLOW), same reason format with a (via guard-pack) suffix, first blocking verdict wins, and a guard that throws is logged and skipped so one broken guard cannot switch off the other five. lib/ copies are pinned byte-identical to the individual plugin scripts by a test. Bench grows rows for config-guard, the instructions-audit PreToolUse arm, and guard-pack; RESULTS regenerated. Marketplace and README go to 20 plugins; badge synced to 1570.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #41 (the last open item from it; #43 shipped the pluginization).
Why
Installing the six guard plugins individually costs six Node startups per matching tool call, about 35 ms each. Measured on the bench, that stack is 199 ms of guard latency per Bash call. The pack runs all six checks in one process for 38 ms median: 5.2x less, same protection.
How it works
One PreToolUse registration on
Bash|Read|Edit|MultiEdit|Write. The runner requires the six guard modules and evaluates them in cheap-first order (config-guard, block-dangerous-commands, protect-secrets, protect-tests, git-safety, case-insensitive-guard; the filesystem-touching and git-spawning guards go last). It mirrors each guard's ownmain(): same tool filters, same escape hatches (CONFIG_GUARD_ALLOWskips only config-guard), same ask-mode semantics per guard (protect-tests and git-safety stay deny-only), and the winning verdict is emitted in that guard's exact output format, suffixed(via guard-pack). A guard that throws is logged and skipped, so one broken guard can never switch off the other five.lib/holds byte-identical copies of the six plugin scripts (a plugin install caches only its own directory, so the pack must carry its copies); a test pins every copy againstplugins/<name>/<name>.js, same pattern as the bouncer fix, so they cannot drift.Env passthrough is inherent, not reimplemented: the modules read
HOOK_SAFETY_LEVEL(uniform across the pack; per-guard levels need individual installs, the README says so),HOOK_ASK_*, andCONFIG_GUARD_ALLOWthemselves.Bench
The bench also gains the two tool-call-path rows it was missing since #43 (config-guard, and the instructions-audit PreToolUse enforcement arm measured with no lockdown flag), plus guard-pack. RESULTS regenerated on the same machine:
Tests
26 new tests (drift pins for all six lib copies, verdict format and ordering through the pack, env passthrough including ask-mode and the escape hatch, a case-collision test that adapts to whether the volume folds case so it holds on Linux CI, robustness on malformed payloads). Suite: 1570 pass, 0 fail.
claude plugin validatepasses for the plugin and the marketplace. Marketplace and README move to 20 plugins with a do-not-double-install warning.Note: this branch will need a trivial rebase if #44 (dash stragglers) merges first; both touch
.claude-plugin/marketplace.json.