Skip to content

fix(hooks): make the hook path work on Windows - #3619

Closed
rhishi99 wants to merge 1 commit into
rtk-ai:developfrom
rhishi99:fix/windows-hook-correctness
Closed

rhishi99 wants to merge 1 commit into
rtk-ai:developfrom
rhishi99:fix/windows-hook-correctness

Conversation

@rhishi99

Copy link
Copy Markdown

Problem

Three defects, all on the path a Windows agent actually takes.

1. Hook input rejected outright

Some Windows hosts prepend a UTF-8 BOM to the JSON they write to hook stdin. serde_json refuses it, so run_claude and run_gemini died on the first byte:

Failed to parse hook input as JSON: expected value at line 1 column 1

strip_leading_bom already exists in this file for exactly this reason (the Cursor hook), it just was not applied to the Claude and Gemini entry points. On input without a BOM it is a no-op.

2. The hook did not recognize itself

is_claude_hook_command compared the binary name against "rtk". On Windows the command reads rtk.exe hook claude, so the check failed and the hook was treated as an ordinary command.

Fixing the .exe suffix alone was not enough. shell_split applies POSIX unquoting, which consumes the separators in a Windows path — C:\Users\me\...\rtk.exe arrives as C:Usersme...rtk.exe, leaving nothing for the existing rsplit(['/', '\']) to find. The binary's name is now taken from the raw command text instead, so absolute Windows paths (quoted or not) match.

3. Audit log written somewhere unwritable

Reader and writer both hardcoded $HOME/.local/share/rtk, falling back to /tmp. On Windows HOME is frequently unset and /tmp does not exist. The two also disagreed — only the reader honoured RTK_AUDIT_DIR.

Resolution now lives in one hooks::audit_dir() that both call, so they cannot drift again.

Deliberately not dirs::data_local_dir(). That is ~/Library/Application Support on macOS, so adopting it would silently relocate an existing macOS user's audit log. Unix keeps the historic $XDG_DATA_HOME / $HOME/.local/share; only Windows gets %LOCALAPPDATA%\rtk.

Also accepts powershell, pwsh and cmd as terminal tool names alongside bash, since that is what Windows hosts report.

Testing

New test claude_hook_command_matches_windows_exe_and_backslash_path covers bare rtk.exe, uppercase RTK.EXE, and a full C:\...\rtk.exe path — the last of which failed until the raw-token fix above. Existing strip_leading_bom and is_claude_hook_command tests still pass unchanged.

Full suite on x86_64-pc-windows-gnu: 2616 passed. cargo fmt --check and cargo clippy --all-targets clean. The single unrelated failure on this toolchain is fixed in #3615.

Not included

The Gemini hook wrapper is still generated as #!/bin/bash. Making it a Windows batch file also requires renaming rtk-hook-gemini.sh and teaching hook_check the new name, and I could not verify how the Gemini CLI invokes that file. Left for a separate, properly-verified PR rather than guessing.

🤖 Generated with Claude Code

Three defects, all in the path a Windows agent actually takes.

**Hook input rejected outright.** Some Windows hosts prepend a UTF-8 BOM
to the JSON they write to hook stdin. `serde_json` refuses it, so
`run_claude` and `run_gemini` died on the first byte:

    Failed to parse hook input as JSON: expected value at line 1 column 1

Strip leading BOMs before parsing. On input without one this is a no-op.

**The hook did not recognize itself.** `is_claude_hook_command` compared
the binary name against `"rtk"`, but on Windows the command reads
`rtk.exe hook claude`, so the check failed and the hook was treated as an
ordinary command.

**Audit log written somewhere unwritable.** Both the reader and the
writer hardcoded `$HOME/.local/share/rtk`, falling back to `/tmp` -- and
`HOME` is often unset on Windows while `/tmp` does not exist. The two
also disagreed: only the reader honoured `RTK_AUDIT_DIR`.

Resolution now lives in one `hooks::audit_dir()` that both call, so they
cannot drift again. It uses `%LOCALAPPDATA%\rtk` on Windows and keeps the
historic `$XDG_DATA_HOME` / `$HOME/.local/share` on Unix -- deliberately
not `dirs::data_local_dir()`, which is `~/Library/Application Support` on
macOS and would silently relocate an existing user's log.

Also accepts `powershell`, `pwsh` and `cmd` as terminal tool names
alongside `bash`, since that is what Windows hosts report.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@CLAassistant

CLAassistant commented Aug 20, 2026 •

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@KuSh

KuSh commented Sep 27, 2026

Copy link
Copy Markdown
Collaborator

BOM stripping landed for Gemini in #3751 (merged 2026-08-30) and for the Claude hook in #3008 (merged 2026-09-19), and #3552 (merged 2026-09-13) added rtk.exe matching through is_rtk_binary in src/hooks/mod.rs. What develop still lacks from this branch: a shared audit directory (RTK_AUDIT_DIR, XDG_DATA_HOME, %LOCALAPPDATA% on Windows) used by both the writer in hook_cmd.rs and the reader in hook_audit_cmd.rs, which still disagree; powershell, pwsh and cmd accepted as terminal tool names in detect_format and run_vibe_inner; and matching the raw leading token so uppercase RTK.EXE and unquoted C:...\rtk.exe paths are recognised, which would now go into the shared is_rtk_hook_command in src/hooks/mod.rs. Could you rebase onto current develop and narrow the PR to those three parts? It conflicts with develop in the hook files. Thanks for all the Windows testing behind this.

@KuSh

KuSh commented Oct 10, 2026

Copy link
Copy Markdown
Collaborator

Thank you for this work. BOM stripping on the Claude and Gemini hook inputs landed in #3751 (merged 2026-08-30), rtk.exe is recognised through the shared hook command check from #3552 (merged 2026-09-13), and Copilot on Windows already reaches the hook as Bash per #3212 (merged 2026-08-02); since #3758 (merged 2026-10-01) user paths must resolve through src/core/user_dirs.rs, so the audit_dir helper here would need to be redone on that model. Develop still does not match an unquoted C:...\rtk.exe path or an uppercase RTK.EXE in the hook command (src/hooks/mod.rs:21), and an issue or a narrow PR against is_rtk_hook_command would be welcome; the audit log writer and reader disagreeing on RTK_AUDIT_DIR is tracked in #1681. If I missed a part of this, please comment and we can reopen.

@KuSh KuSh closed this Oct 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants