PreToolUse hook `if` pattern does not match commands chained with `&&` or `;`

Resolved 💬 1 comment Opened Apr 10, 2026 by yoon-yoo-sang Closed May 14, 2026

Summary

PreToolUse hook's if pattern matching (e.g., Bash(git commit*)) only matches the beginning of the full Bash command string. When the model chains commands with && or ;, the pattern fails to match and the hook is silently skipped.

Reproduction

Hook configuration in .claude/settings.json:

{
  "type": "command",
  "if": "Bash(git commit*)",
  "command": "bash .claude/hooks/guard-commit-lint.sh",
  "statusMessage": "Running pre-commit checks..."
}
  • git commit -m "msg" — hook fires correctly
  • git checkout -b branch && git add . && git commit -m "msg" — hook does not fire

The if pattern matches against the full command string, which starts with git checkout, not git commit.

Impact

Users set up PreToolUse hooks to enforce quality gates (linting, tests, branch protection) before specific commands. The model frequently chains commands with && for efficiency, which inadvertently bypasses all hook-based guardrails. This is especially problematic because:

  1. There is no warning or log when a hook is skipped due to pattern mismatch
  2. The user has no way to express "match if git commit appears anywhere in the command" with the current if syntax

Possible solutions

  • Match the if pattern against each individual command in a &&/;/|| chain, not just the full string
  • Support substring or regex matching in if patterns (e.g., Bash(*git commit*))
  • Warn when a Bash call contains a command that would match a hook pattern but is skipped due to chaining

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗