anthropics / anthropics/claude-plugins-official
security-guidance: every Bash tool call spawns 5 Python processes; ~94% match none of the 5 git if-conditions
- Vorherrschende Sprache
- Python
- Sterne
- 36.3k
- Forks
- 4.1k
- Ø Merge
- 2 T. 14 Std.
- Gemergte PRs (30 T.)
- 539
Beschreibung
### Summary
`hooks/hooks.json` registers **five separate `PostToolUse` entries under `"matcher": "Bash"`**, each gated by a different `if` condition (`Bash(git commit:*)`, `Bash(git push:*)`, `Bash(gt create:*)`, `Bash(gt modify:*)`, `Bash(gt submit:*)`).
In practice **all five spawn a Python process on every single Bash tool call**, whatever the command is. The `if` condition does not prevent the spawn — the interpreter starts, `sg-python.sh` runs its probe sequence, `security_reminder_hook.py` loads, and only then does the command fail to match. Four of the five can never match on the same call, since the conditions are mutually exclusive.
Over a 16-day window on one machine this was **3,889 Python spawns from ~778 Bash tool calls**, of which **~94% matched none of the five conditions**. Bash alone accounted for **50.1% of all hook spawns** from the plugin.
### Reproduction
1. Enable `security-guidance` (2.0.6).
2. Run any Bash tool call with no git in it — e.g. `date`.
3. Read `~/.claude/security/log.txt`.
Observed for a single `date` call, no git anywhere in the command:
```
[2026-08-14 11:20:30.658] Processing: hook_event=PostToolUse, tool=Bash
[2026-08-14 11:20:30.658] Processing: hook_event=PostToolUse, tool=Bash
[2026-08-14 11:20:30.745] Processing: hook_event=PostToolUse, tool=Bash
[2026-08-14 11:20:30.772] Processing: hook_event=PostToolUse, tool=Bash
[2026-08-14 11:20:30.772] Processing: hook_event=PostToolUse, tool=Bash
```
Five spawns, zero `detected git commit` lines in the same window.
### Evidence at scale
From this machine's own `~/.claude/security/log.txt` + `log.txt.1`, covering 2026-07-29 → 2026-08-14 (16 days, 46 working sessions):
| Metric | Value | How |
|---|---|---|
| Total hook spawns | ~7,758 | `grep -c 'Hook called with args'` |
| Spawns from `tool=Bash` | 3,889 (50.1%) | `grep -c 'Processing: hook_event=PostToolUse, tool=Bash'` |
| Implied Bash tool calls | ~778 | 3,889 / 5 |
| Bash spawns matching a git condition | 227 (~6%) | `grep -c 'Commit review: detected git commit in command'` |
| Wasted spawns | ~3,660 (~94%) | difference |
Clustering the Bash timestamps at a 5-second window gives **607 clusters of exactly 5**, versus 150 of size 1 and 94 of size 2 — consistent with one spawn group per Bash call.
### Impact
These five bindings carry `asyncRewake: true`, so **they do not block the user's turn** — the cost is CPU, battery, and process pressure rather than perceived latency. That keeps severity moderate, but the volume is large: ~243 wasted interpreter starts per day on a normal working machine.
Cost per spawn measured here (Windows 11, Git Bash):
- **~1,360 ms** end-to-end for `sg-python.sh` running a no-op script, when `python3.12` resolves through a Chocolatey shim
- **~726 ms** after making `python3.12` resolve directly to `python.exe`
Most of that is `sg-python.sh`'s interpreter probe, which is paid **twice** per fire — once for the version probe (`v=$(probe "$cmd")`) and once for the `exec`. So the four never-matching spawns cost roughly 3–5 seconds of CPU per Bash call on this setup.
### Suggested fix
Either would resolve it:
1. **Plugin side (smaller change):** collapse the five `Bash` entries into **one** binding with no `if`, and dispatch to the right review internally — the hook already parses the command, and `security_reminder_hook.py` already contains the git-detection logic. This cuts Bash spawns by 80% with no behaviour change.
2. **Harness side:** have Claude Code evaluate a hook entry's `if` condition *before* spawning the process. That would fix this class of problem for every plugin, not just this one — but I can't tell from outside whether `if` is documented as a pre-spawn gate or a post-spawn filter, so this may be working as designed.
If (2) is the intended semantics, it would be worth documenting, because the current `hooks.json` reads as though the conditions gate execution.
### Environment
- `security-guidance` 2.0.6
- Claude Code 2.1.232, native install
- Windows 11 Pro 26200, Git Bash
- Python 3.12.3
### Note on a related cost
Unrelated to the amplification but found alongside it: on a machine with no `ANTHROPIC_API_KEY` / `ANTHROPIC_AUTH_TOKEN`, every Stop and commit review logs `LLM review disabled or no API credentials` (315/315 and 224/227 here) — yet `ensure_agent_sdk.py` had still built a **304 MB** `agent-sdk-venv`, and `security_reminder_hook.py` re-spawns a detached bootstrap every 300 s because the SDK is not importable from system Python. Skipping the bootstrap when no credentials are present would avoid that entirely. Happy to open that separately if you'd prefer it tracked on its own.
Beitragsleitfaden
Für dieses Repository ist kein Beitragsleitfaden indexiert
Rechercherichtung
Start with hooks/hooks.json and compare the five PostToolUse Bash entries, then read security_reminder_hook.py and sg-python.sh to understand the existing dispatch and process startup. Reproduce the behavior with a Bash date call and inspect ~/.claude/security/log.txt. Done means irrelevant Bash calls no longer cause five hook spawns while the existing git review detections still work.
Vom Indexierungsmodell aus dem Issue-Text verfasst.
Bewertung
- Tech-Stack
- bash, python
- Bereich
- performance, tooling
- Issue-Typ
- Bug
- Schwierigkeit
- 3/5
- Geschätzter Aufwand
- 1-2 Tage
- Aktivitätsstatus
- Ruhig
- Klarheit
- Größtenteils klar
- Anfängerfreundlichkeit
- 58/100