Kills the flashing terminal windows that AI-agent hooks spawn on Windows - and keeps them dead through plugin auto-updates.
If Claude Code (or a plugin like claude-mem, superpowers, or your own hooks) makes a console window flash on your screen every few seconds, you have hook commands being launched through a visible shell. It is a whole class of bug, reported across at least three ecosystems (claude-code#14828, claude-code#66540, claude-mem#681, claude-mem#748, superpowers#292) - and the fix everyone recommends in those threads does not actually work.
powershell -WindowStyle Hidden does NOT stop the flash on Windows 11 with
Windows Terminal as the default host. A console-subsystem process gets its
window created visible before it can hide it - you see the flash, then it
hides. Proven by isolation test: a detached powershell -WindowStyle Hidden
still flashed a Terminal window.
The only construction that cannot flash is a GUI-subsystem (winexe)
launcher - it has no console to show, by definition. This tool compiles one
locally from 12 lines of C# you can read, using the
csc.exe that ships with every stock Windows. No downloaded binaries.
# 1. What is flashing, and why - scans Claude Code / Codex / Cursor plugin
# hook configs for the known flash-causing shapes:
.\bin\hooks-doctor.ps1 doctor
# 2. Fix them - wraps offenders in the no-flash launcher (backup: .prebak,
# async/timeout/matcher preserved, idempotent):
.\bin\hooks-doctor.ps1 fix
# 3. Keep them fixed - plugin auto-updates LOVE to reintroduce this bug in
# new formats. Installs a scheduled task that re-runs fix every 10 min
# (via a wscript shim, so the watchdog itself cannot flash):
.\bin\hooks-doctor.ps1 watch
# Bonus: not sure what is flashing? Run the window sampler and reproduce it -
# every new visible window gets logged with its class, process and command line:
.\bin\hooks-doctor.ps1 sample -Seconds 60Fixes take effect on new agent sessions (runtimes load hooks at session start).
| Shape | Where seen in the wild |
|---|---|
"shell": "bash" key + inline script |
claude-mem 13.11.0+ hook format |
bash -lc "..." / bash.exe direct commands |
claude-mem 13.7-13.10 regressions |
login-shell -l flags in cmd/bash wrappers |
superpowers run-hook.cmd class |
| already-wrapped launcher commands | reported healthy, never re-patched |
CLAUDE_CODE_GIT_BASH_PATH -> git-bash.exe (mintty GUI launcher - windowed by design, unhideable) |
reported in claude-code#14828, credit ayer-ribeiro |
Unknown flashing shapes are logged loudly (~/.agent-hooks-doctor/doctor.log)
and left untouched - this tool never guess-patches a config it does not
understand. (Both of those rules are scar tissue: a silent catch once hid a
broken patch cycle for a week, and a format change no-opped a watchdog that
only knew the previous shape.)
The launcher preserves the full hook contract: stdin JSON reaches the script,
stdout/stderr and the exit code come back to the runtime, async/timeout/
matcher fields are untouched, and the original file is backed up as
.prebak next to it. The test suite pins all of that, including a live
stdio round-trip through the compiled launcher.
- Windows-only, by design - this bug class does not exist elsewhere.
- Fixes hook configs. The one flash it cannot fix is Claude Code's own
Bash-tool console (#14828) -
that spawn happens inside Claude Code itself and only Anthropic can add the
missing
windowsHide. Thesamplecommand will at least prove to you that is the one you are seeing.
MIT © Maciej Lewandowski