Summary
On WSL2, for repos on the Windows drive (/mnt/c, 9P/drvfs), the security-guidance UserPromptSubmit hook blocks every prompt for about 4 s. It sometimes takes 10-16 s and hits the 30 s hook timeout on a cold page cache. Nearly all of that time is git stash create in capture_git_baseline. The hook is synchronous and the plugin has no option to background it, so users pay this on every prompt.
This is a different root cause from #4727. There is no state-file bloat here: the repo has 1 untracked file, so _list_untracked takes 0.2 s.
Environment
- security-guidance 2.0.16 (also reproduced on 2.0.8)
- Claude Code 2.1.308, native install, WSL2 (kernel 6.6.87.2), git 2.43.0
- Repo: 1,424 tracked files, about 17 MiB pack, on
/mnt/c/...
Evidence
- Plugin's own
log.txt: 210 UPS invocations over 3 days. I measured fromProcessing: hook_event=UserPromptSubmittoCaptured git baseline. Median 3.45 s, p90 5.4 s, max 16.3 s. Transcripts also show 3hook_cancelledentries withtimedOut: trueandtimeoutMs: 30000in 60 days. All were in/mnt/crepos. - Direct run of the hook (2.0.16, same repo): 4,127 / 4,030 / 4,019 ms. cProfile shows about 95% of the time in
capture_git_baseline→subprocess.run(git stash create). GIT_TRACE_PERFORMANCE=1 git -c core.fsmonitor=false stash create:diff-filestakes 4.0 s of 4.16 s total. Baseline costs:git diff-files --quiet1.8-2.3 s, andupdate-index --refresh2.2 s. That is the per-file lstat cost over 9P, about 1.4 ms per file, andstash createdoes it at least twice.- Windows
git.exeon the same worktree is no faster (stash create4.9 s), because the plugin forcescore.fsmonitor=false.
Impact
Every prompt in such a repo waits about 4 s before the model starts. Occasional 30 s stalls leave no baseline, so the next Stop review diffs against an older baseline. WSL users commonly keep repos on /mnt/c, which they also share with Windows IDEs.
Workaround we're using
We disabled the plugin and re-registered its hooks.json entries in user settings.json, with "async": true on the UserPromptSubmit entry. The prompt is released in about 35 ms, and the baseline is still captured in the background in about 3.7 s, verified in log.txt.
The trade-off: an edit made within the first few seconds of a turn can predate the baseline. A short turn's Stop can also run before the new baseline lands.
Possible fixes
- Ship UPS with
"async": true, or a documented opt-in. Then have Stop wait briefly for an in-flight baseline capture, for example via a marker in the session state, instead of racing it. - Defer the baseline: capture it lazily on the first PreToolUse for Edit/Write/MultiEdit/NotebookEdit/Bash. Turns without edits then pay nothing, and the capture still happens before the first modification.
- Allow
core.fsmonitor(or aSG_GIT_FSMONITORopt-in) instead of forcing it off. With a Windows-side fsmonitor daemon,diff-filesdrops sharply. - At minimum, log the UPS duration and the cwd in
log.txtso slow repos are visible.
Activity
0No activity yet.