Port evaluated and greenlit 2026-07-17 (capability from mattpocock/skills misc/git-guardrails-claude-code; implementation rejected — rewrite on our argv-grammar parser).
Scope: one new guard block-dangerous-git in the EXISTING guardrails plugin (PreToolUse on Bash), not a new plugin and not source-control (guardrails owns silent-always-on hooks).
Decisions from the evaluation:
- Default block-list is irreversible-only:
push --force/-f (not --force-with-lease), reset --hard, clean -f*, checkout ./restore ..
branch -D stays OUT of defaults: repo-hygiene's /clean issues inline git branch -D for squash-merged branches (verified collision), and it's reflog-recoverable.
- Upstream's substring matching is defective (blocks ALL
git push; checkout \. fires on checkout .github/...) — reuse the house tokenizer: lift parse_and_check/resolve_git_index from block-no-verify into lib/hook-utils.sh (SSOT via scripts/sync-hook-utils.sh) so both git guards share one parser.
- Per-repo/per-user allow-list via env var (
HOOK_BLOCK_DANGEROUS_GIT_ALLOW=...) in settings env, matching the plugin's HOOK_CLI_FLAG_VERIFY_BINS precedent. userConfig is structurally wrong here: project-level pluginConfigs are ignored since Claude Code 2.1.207.
- Prompt-injection note: inline
HOOK_..._ENABLED=false git push does NOT disable the hook (env prefix reaches only the git process). Residual risk = settings.json write access, the marketplace-wide hook trust boundary.
Scale: ~half day; new guard + .test.sh, hooks.json/README edits, guardrails 0.4.0 → 0.5.0. Hook plugins skip evals.
🤖 Generated with Claude Code
Port evaluated and greenlit 2026-07-17 (capability from mattpocock/skills misc/git-guardrails-claude-code; implementation rejected — rewrite on our argv-grammar parser).
Scope: one new guard
block-dangerous-gitin the EXISTING guardrails plugin (PreToolUse on Bash), not a new plugin and not source-control (guardrails owns silent-always-on hooks).Decisions from the evaluation:
push --force/-f(not--force-with-lease),reset --hard,clean -f*,checkout ./restore ..branch -Dstays OUT of defaults: repo-hygiene's /clean issues inlinegit branch -Dfor squash-merged branches (verified collision), and it's reflog-recoverable.git push;checkout \.fires oncheckout .github/...) — reuse the house tokenizer: liftparse_and_check/resolve_git_indexfrom block-no-verify intolib/hook-utils.sh(SSOT via scripts/sync-hook-utils.sh) so both git guards share one parser.HOOK_BLOCK_DANGEROUS_GIT_ALLOW=...) in settingsenv, matching the plugin'sHOOK_CLI_FLAG_VERIFY_BINSprecedent. userConfig is structurally wrong here: project-level pluginConfigs are ignored since Claude Code 2.1.207.HOOK_..._ENABLED=false git pushdoes NOT disable the hook (env prefix reaches only the git process). Residual risk = settings.json write access, the marketplace-wide hook trust boundary.Scale: ~half day; new guard +
.test.sh, hooks.json/README edits, guardrails 0.4.0 → 0.5.0. Hook plugins skip evals.🤖 Generated with Claude Code