Windows: statusline cancellation (taskkill /T) and cross-session liveness probes overload WMI - WmiPrvSE pinned at 300-550% CPU with ~10 concurrent sessions
Environment
- Claude Code v2.1.199, native Windows build (
claude.exe) - Windows 11 Education 10.0.22631, AMD Ryzen 5 7535U (6c/12t), 32 GB RAM
- Git for Windows installed, so statusline commands run through the documented Git-Bash wrapper
- ~9-12 concurrent interactive sessions across several projects
- Custom statusline in
settings.json:"statusLine": { "type": "command", "command": "powershell.exe -NoProfile -ExecutionPolicy Bypass -File .../statusline-command.ps1", "refreshInterval": 3 }- the script takes ~480 ms end to end (PowerShell cold start dominates) - Possibly relevant config:
CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS=1and"remoteControlAtStartup": truewere enabled; unclear which subsystem owns the liveness probing described below
Summary
Two undocumented Windows behaviours - (1) statusline cancellation killing process trees via taskkill /T, and (2) cross-session liveness probes implemented as spawned PowerShell + WMI one-liners - combine into a feedback loop that pinned the shared WMI Provider Host (WmiPrvSE.exe hosting CIMWin32) at 300-550% CPU for a full day (~124,000 CPU-seconds accumulated over 21 h), flooded the WMI-Activity log with errors, made other WMI clients on the machine time out, and left every session's statusline permanently blank.
Defect 1: statusline cancellation = taskkill /T = full WMI process-table scan per cancel
The statusline docs say in-flight executions are cancelled when a new update fires (300 ms debounce), but not how. Observed on Windows: cancellation runs taskkill /PID <pid> /T /F against the render's process tree. taskkill /T builds the tree by querying WMI - a 12 s ETW trace of Microsoft-Windows-WMI-Activity captured 40 of these full enumerations in 12 seconds:
Provider::ExecQuery - CIMWin32 : select __RELPATH, __PATH, ProcessId, CSName, Caption, SessionId,
ThreadCount, WorkingSetSize, KernelModeTime, UserModeTime, ParentProcessId from Win32_Process
One full Win32_Process enumeration costs ~533 ms of provider CPU on this machine (measured with Measure-Command { Get-CimInstance Win32_Process }).
With N concurrent sessions and a statusline slower than the 300 ms debounce, cancellations fire several times per second, so the WMI provider does 1.5-2+ core-seconds of scan work per wall-clock second, which slows the next renders, which causes more cancellations. Observed effects:
WmiPrvSE.exe(shared CIMWin32 host) pinned at 300-550% CPU; killing it is whack-a-mole - a fresh host re-wedges within seconds because the sources immediately reconnect- WMI-Activity/Operational floods with event 5858 /
0x800706BA"Could not send status to client" (~470/hour) - the killed render/probe clients vanish mid-operation - All statuslines permanently blank (renders killed before they print; docs: no output = blank line)
- Every render also spawns a
bash.exechain (Git\bin\bash.exere-execsusr\bin\bash.exe) +conhost.exe+powershell.exe: 543 process creations measured in 10 seconds across ~9 idle-ish sessions
Defect 2: cross-session liveness probes via spawned PowerShell + WMI
claude.exe checks whether other Claude Code processes are alive by spawning (command template found embedded in the claude.exe binary):
powershell.exe -NoProfile -Command "(Get-CimInstance Win32_Process -Filter \"ProcessId=<pid>\").CreationDate.Ticks"
Observed:
- periodic sweeps probing each registered session PID (one spawned PowerShell per peer)
- a failure mode where one session probed a single peer PID 2-3 times per second for hours; after that peer process was killed, the sweeps re-aimed at the remaining sessions
- when WMI is overloaded, probes time out or hang - one probe process hung for 4.5 h and survived repeated kill attempts; every timeout logs another 5858 error
- undocumented; no setting or env var found to tune or disable it
Each probe is a full PowerShell cold start (~450 ms CPU) plus a WMI round-trip, for a value (process creation time) obtainable in microseconds via GetProcessTimes / NtQueryInformationProcess, or Node's own process APIs.
Reproduction
- Windows 11 with Git for Windows installed; set a custom statusline command that takes >300 ms (any
powershell.exe -File ...script qualifies - cold start alone is ~400 ms) with"refreshInterval": 3 - Open ~8-10 interactive sessions and let them sit
- Watch
WmiPrvSE.exeCPU climb in Task Manager; watchMicrosoft-Windows-WMI-Activity/Operationalfill with 5858 /0x800706BA; statuslines go blank logman create trace wmiact -p Microsoft-Windows-WMI-Activity 0xffffffffffffffff 0xff -o wmiact.etl -ets, wait ~12 s,logman stop wmiact -ets, decode withtracerpt- the trace shows thetaskkill-signature fullWin32_Processenumerations and the per-peer probe queries
Expected behaviour
- Read process start/liveness via native APIs instead of spawning
powershell.exe+ WMI per check - Cancel statusline renders without
taskkill /T's WMI tree walk (native process enumeration such asCreateToolhelp32Snapshot, or spawn renders into a Job Object so the tree can be killed directly) - Ideally: let
statusLineaccept a"shell"field like hooks do, so the Git-Bash wrapper (two extra bash processes + conhost per render) can be avoided on machines where MSYS2 bash is unreliable
Workaround that resolved it here
- Ported the statusline script to Node (80 ms vs 481 ms, output identical) so renders finish inside the 300 ms debounce window - cancellations and their
taskkillWMI scans stopped - Raised
refreshIntervalfrom 3 to 10 - WMI provider CPU dropped from ~550% sustained to idle; statuslines render again