You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Deferred third tier from #1579, which landed the pre-computed probe and the shipped exec-bit-check.sh but deliberately stopped short of a hook.
What this tier would cover that the landed tiers do not
The probe and the script both require the skill to be invoked. The failure mode that motivated #1579 was a run of memory-following commits that never invoked the skill at all — exactly the
case neither landed tier reaches. A PreToolUse hook is the only tier that covers it, because it
fires on the tool call regardless of whether any skill is in play.
Mechanism (verified against current docs, fetched 2026-07-26)
A PreToolUse entry with "matcher": "Bash" receives the tool input on stdin as JSON with tool_name and tool_input, so the command string is readable via .tool_input.command.
Narrower filtering is available per handler via the if field using permission-rule syntax, e.g. "if": "Bash(git commit *)".
Blocking has two documented forms: exit 2 with the message on stderr, or exit 0 with hookSpecificOutput.permissionDecision: "deny" plus permissionDecisionReason (the richer,
user-visible form).
source-control ships zero hooks today. Adding one changes the install footprint for every
consumer of the plugin, not just users of /commit.
A Bash-matching hook is evaluated on every Bash tool call. Even with an if filter, this is a
new always-on surface and belongs behind its own security review per the repo's plugin-acceptance
process.
There is prior art and prior caution to reconcile: the guardrails plugin already ships PreToolUse on Bash|PowerShell with block-noncanonical-commit.sh and block-convention-violation.sh. That is proof the pattern works in-repo — but it lives in a different plugin, so a consumer installing only source-control inherits none of it. Whether
this check belongs in source-control's own hooks or as an addition to guardrails is the actual
design question, and it was not settled by source-control:commit: exec-bit check is advisory prose with no deterministic tier #1579.
Open design questions
Which plugin owns it — source-control (cohesive with the skill, but a new hook surface for
that plugin) or guardrails (already the hook home for git-commit gating, but then the check is
absent for source-control-only consumers).
Block or warn. An exec-bit miss is a correctness defect, not a safety one. deny may be too
strong; ask, or a non-blocking warning, may fit better.
Deferred third tier from #1579, which landed the pre-computed probe and the shipped
exec-bit-check.shbut deliberately stopped short of a hook.What this tier would cover that the landed tiers do not
The probe and the script both require the skill to be invoked. The failure mode that motivated
#1579 was a run of memory-following commits that never invoked the skill at all — exactly the
case neither landed tier reaches. A
PreToolUsehook is the only tier that covers it, because itfires on the tool call regardless of whether any skill is in play.
Mechanism (verified against current docs, fetched 2026-07-26)
From https://code.claude.com/docs/en/hooks:
hooks/hooks.jsonin the plugin root and are auto-discovered — noplugin.jsondeclaration needed (https://code.claude.com/docs/en/plugins-reference).PreToolUseentry with"matcher": "Bash"receives the tool input on stdin as JSON withtool_nameandtool_input, so the command string is readable via.tool_input.command.iffield using permission-rule syntax, e.g."if": "Bash(git commit *)".hookSpecificOutput.permissionDecision: "deny"pluspermissionDecisionReason(the richer,user-visible form).
Why it was NOT landed with #1579
source-controlships zero hooks today. Adding one changes the install footprint for everyconsumer of the plugin, not just users of
/commit.Bash-matching hook is evaluated on every Bash tool call. Even with aniffilter, this is anew always-on surface and belongs behind its own security review per the repo's plugin-acceptance
process.
guardrailsplugin already shipsPreToolUseonBash|PowerShellwithblock-noncanonical-commit.shandblock-convention-violation.sh. That is proof the pattern works in-repo — but it lives in adifferent plugin, so a consumer installing only
source-controlinherits none of it. Whetherthis check belongs in
source-control's own hooks or as an addition toguardrailsis the actualdesign question, and it was not settled by source-control:commit: exec-bit check is advisory prose with no deterministic tier #1579.
Open design questions
source-control(cohesive with the skill, but a new hook surface forthat plugin) or
guardrails(already the hook home for git-commit gating, but then the check isabsent for
source-control-only consumers).denymay be toostrong;
ask, or a non-blocking warning, may fit better.A new hook needs its own fixtures before shipping. Note that during source-control:commit: exec-bit check is advisory prose with no deterministic tier #1579's implementation the
existing
block-noncanonical-commit.shfalse-fired on agh issue createwhose body textmerely mentioned the guarded command — worth folding into the precision work either way.
core.filemode=falseinteraction. Under the Windows default, staged mode is the onlymeaningful signal; a hook reasoning about worktree bits would be wrong there. See source-control:commit: exec-bit check is advisory prose with no deterministic tier #1579 for the
verified behavior.