From ee892068e11755e8c94df990c16e13f6ebe723ea Mon Sep 17 00:00:00 2001 From: learte4 Date: Tue, 11 Aug 2026 16:25:47 -0300 Subject: [PATCH] perf: skip the jq spawn on non-skill reads MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The hook is registered for every Read, but only reads under .claude/skills/ produce a log entry — in practice well under 1% of calls. The current code still spawns jq to parse the payload before it can decide that, so the subprocess is paid on every read and thrown away almost every time. Move the decision ahead of the parse with a plain shell pattern match on the raw stdin. The pattern covers both separator styles, so JSON-escaped Windows paths still match, and it is strictly wider than the file_path guard that follows — anything that used to be logged still is. Measured on Windows (Git Bash, 25 runs, non-skill read): 538 ms -> 188 ms per invocation. The remainder is bash startup, which a `type: command` hook cannot avoid. On macOS/Linux the saving is smaller in absolute terms but the spawn is removed all the same. Verified with a throwaway harness that puts a failing `jq` first on PATH: a non-skill read exits 0 without ever calling it, a skill read still logs the event, and a JSON-escaped Windows path still reaches the parser. Co-Authored-By: Claude Fable 5 --- scripts/skill-tracker.sh | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/scripts/skill-tracker.sh b/scripts/skill-tracker.sh index 2cd52a0..c5c3c48 100755 --- a/scripts/skill-tracker.sh +++ b/scripts/skill-tracker.sh @@ -59,6 +59,14 @@ log_skill_access() { main() { local input tool_name file_path session_id offset limit input=$(cat) + # Fast-exit before spawning jq: this hook fires on every Read, but only skill + # files are logged. Matched against the raw payload, where Windows paths arrive + # JSON-escaped ("\\"). Strictly wider than the file_path guard below, so no + # event is lost. + case "${input}" in + *'.claude/skills/'*|*'.claude\\skills\\'*) ;; + *) exit 0 ;; + esac { read -r tool_name; read -r file_path; read -r session_id; read -r offset; read -r limit; } < <( printf '%s' "${input}" | jq -r '(.tool_name // ""), (.tool_input.file_path // ""), (.session_id // "unknown"), (.tool_input.offset // ""), (.tool_input.limit // "")' ) || true