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
A no-op Bash tool call (ls -la) costs 90 ms in the PreToolUse(Bash) dispatch group at 9a75c74. That is acceptable, and far better than the pre-#613 ~35 cold starts — this issue records where the remaining fixed cost sits so it is a known quantity rather than an assumption.
cProfile of hooks/_lib/_dispatch.py PreToolUse Bash claude with a trivial command:
Python's re cache is per process, and every dispatch is a fresh process, so all 188 module-level patterns across the 55 members are recompiled on every Bash tool call, whether or not the member's cheap discriminator would have returned early.
Options (none urgent)
Lazy compile: wrap the heavy patterns in a functools.lru_cache'd accessor so a member that returns at its cheap gate (tool_name != "Bash", no trigger token in the command) never compiles them. The shared ones in _hook_utils are the biggest single block.
Precompiled cache: not available for re without pickling tricks; not recommended.
Suggest deferring unless the baseline drifts past ~150 ms; the two transcript-scanning members (#1277, #1278) dominate real-world latency by an order of magnitude.
Symptom
A no-op Bash tool call (
ls -la) costs 90 ms in the PreToolUse(Bash) dispatch group at9a75c74. That is acceptable, and far better than the pre-#613 ~35 cold starts — this issue records where the remaining fixed cost sits so it is a known quantity rather than an assumption.cProfile of
hooks/_lib/_dispatch.py PreToolUse Bash claudewith a trivial command:python3 -c pass_hook_utilsalone_hook_utils + _transcript + _git + _fire_ledger + _paths_load_main× 55 members (exec of eachimpl.py)re.compile× 188ls -laPython's
recache is per process, and every dispatch is a fresh process, so all 188 module-level patterns across the 55 members are recompiled on every Bash tool call, whether or not the member's cheap discriminator would have returned early.Options (none urgent)
functools.lru_cache'd accessor so a member that returns at its cheap gate (tool_name != "Bash", no trigger token in the command) never compiles them. The shared ones in_hook_utilsare the biggest single block.rewithout pickling tricks; not recommended.docs/hook-prune-audit.md, chore(hooks): evidence-based hook prune audit #713) is the structural lever — every dropped member is one less exec + compile.Suggest deferring unless the baseline drifts past ~150 ms; the two transcript-scanning members (#1277, #1278) dominate real-world latency by an order of magnitude.
References