Skip to content

fix(init): enable hook installation on Windows - #1123

Closed
splusk2006 wants to merge 1 commit into
rtk-ai:developfrom
AccelixGames:fix/windows-hook-support
Closed

fix(init): enable hook installation on Windows#1123
splusk2006 wants to merge 1 commit into
rtk-ai:developfrom
AccelixGames:fix/windows-hook-support

Conversation

@splusk2006

Copy link
Copy Markdown

Summary

Enable rtk init -g hook installation on Windows by removing the #[cfg(not(unix))] blockers in src/hooks/init.rs, applying the same inline chmod guard pattern already used by the Cursor and Gemini installers in this file.

Net diff: +25 / −33 lines, one file touched.

Problem

On Windows, rtk init -g currently bails with:

[warn] Hook-based mode requires Unix (macOS/Linux).
    Windows: use --claude-md mode for full injection.
    Falling back to --claude-md mode.

Related user reports: #682 (persistent "No hook installed" warning, stuck on Windows), #913.

The block is compile-time: run_default_mode, run_hook_only_mode, and ensure_hook_installed are each gated with #[cfg(unix)], and the #[cfg(not(unix))] variants either warn-and-fallback or bail!().

Root cause

Only one line actually needs Unix:

use std::os::unix::fs::PermissionsExt;
fs::set_permissions(hook_path, fs::Permissions::from_mode(0o755))?;

PermissionsExt is std::os::unix::fs::PermissionsExt. Everything else compiles and runs fine on Windows.

The hook script itself (rtk-rewrite.sh) is pure bash + jq, which Claude Code already executes via git-bash on Windows — no execute bit is required to invoke a script as bash /path/to/script.sh.

Fix

Mirror the pattern already used by install_cursor_hooks (line 1622) and the Gemini hook installer (line 2152) in this same file: one unified function body, with only the chmod call wrapped in an inline #[cfg(unix)] block.

-#[cfg(unix)]
 fn ensure_hook_installed(hook_path: &Path, verbose: u8) -> Result<bool> {
     // ... write file ...

-    // Set executable permissions
-    use std::os::unix::fs::PermissionsExt;
-    fs::set_permissions(hook_path, fs::Permissions::from_mode(0o755))
-        .with_context(|| format!("Failed to set hook permissions: {}", hook_path.display()))?;
+    // Set executable permissions (Unix only; Windows invokes via `bash script.sh`)
+    #[cfg(unix)]
+    {
+        use std::os::unix::fs::PermissionsExt;
+        fs::set_permissions(hook_path, fs::Permissions::from_mode(0o755))
+            .with_context(|| format!("Failed to set hook permissions: {}", hook_path.display()))?;
+    }

The #[cfg(not(unix))] warn/bail fallback variants of run_default_mode and run_hook_only_mode are deleted, and the #[cfg(unix)] attribute is removed from the remaining unified bodies. Doc comments are extended to explain the cross-platform rationale for future maintainers.

Verification

Verified manually on Windows 11 + Claude Code CLI + git-bash by hand-installing the equivalent hook setup (hook script at ~/.claude/hooks/rtk-rewrite.sh + PreToolUse entry in ~/.claude/settings.json) before writing this PR:

Check Result
rtk init --show [ok] Hook: ... (exists) + [ok] settings.json: RTK hook configured
git status (no rtk prefix) Rewritten to rtk git status; compressed output (* master...origin/master, ~ Modified:, ? Untracked:)
ls -la (no rtk prefix) Rewritten to rtk ls, -la columns stripped as expected
git log --oneline -3 Rewritten, compressed output
Chain: pwd && git branch Each &&-segment rewritten individually
echo "test" Pass-through (no rewrite for rtk-unrelated commands)
Idempotency: rtk git status as input No-op rewrite, correct output
rtk gain counter 1137 → 1234 (+97 commands auto-rewritten via hook)
[rtk] /!\ No hook installed warning Gone from rtk gain, rtk ls, rtk init --show
Subagent session (Claude Code Agent tool) Inherits the hook, commands transparently rewritten in the child session
Existing unrelated PostToolUse hook Intact after settings.json merge
Claude Code settings watcher Reloads immediately after settings.json edit — no session restart required

Independently verified on multiple Windows 11 machines (team members, rtk v0.35.0 + Claude Code CLI, hand-installed the same hook setup). All reported successful installation, hook fire, and no No hook installed warning.

Scope

  • Touched: src/hooks/init.rs (one file)
  • Not touched:
    • Tests module (line 2410+) — its #[cfg(unix)] blocks are test-only and out of scope
    • Cursor / Gemini installers — already cross-platform, serve as the pattern reference
    • rtk init --show Claude hook status display code (line 1839+) — currently uses #[cfg(unix)] for executable / is_thin_delegator checks. Left for a follow-up PR to keep this change minimal; the existing behavior already produces a usable [ok] Hook: exists on Windows.

Related

Draft status

Marked draft pending CI confirmation (Windows/Linux/macOS build matrix). Will flip to ready-for-review once CI is green.

Remove #[cfg(not(unix))] bail/fallback from run_default_mode and
run_hook_only_mode. Guard the chmod(0o755) call inside
ensure_hook_installed with an inline #[cfg(unix)] block instead of
gating the entire function.

This matches the existing cross-platform pattern already used by
install_cursor_hooks (line 1622) and the Gemini hook installer
(line 2152) in this same file.

Verified on Windows 11 + Claude Code CLI + git-bash:
- rtk init --show: [ok] Hook + [ok] settings.json
- PreToolUse hook fires for git/ls/grep commands
- rtk gain counter: 1137 → 1234 (+97 auto-rewritten commands)
- Subagent sessions inherit the hook
- No "No hook installed" warning

Closes rtk-ai#682, rtk-ai#913

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@CLAassistant

CLAassistant commented Apr 10, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@splusk2006
splusk2006 marked this pull request as ready for review April 10, 2026 01:57
@splusk2006

Copy link
Copy Markdown
Author

Relationship to #1090

Heads-up that @ayoub-khemissi already has #1090 open addressing the same Windows gap via a different approach: a new --native-hook flag that registers rtk hook copilot (the compiled binary subcommand) as the PreToolUse command, eliminating the bash/jq dependency entirely.

The two PRs look orthogonal, not competing:

Aspect #1090 #1123 (this)
Mechanism rtk hook copilot native binary bash ~/.claude/hooks/rtk-rewrite.sh
Runtime deps on Windows none bash + jq (present in any git-bash install)
How invoked opt-in via --native-hook flag default behavior of rtk init -g
Default UX on Windows (no flag) still falls back to --claude-md hook installed automatically when git-bash/jq present
Files touched src/hooks/{init.rs, constants.rs}, src/main.rs (+500/−19) src/hooks/init.rs only (+25/−33)

Non-conflicting at the code level

#1090 adds new functions (run_native_hook_mode, is_rtk_hook_command, replace_other_rtk_hook_in_json) and threads a native_hook: bool parameter through run() / run_default_mode / run_hook_only_mode. It does not modify ensure_hook_installed and keeps the #[cfg(not(unix))] bail/fallback variants, only improving their message.

This PR does the opposite: removes the #[cfg(not(unix))] variants entirely, unifies the function bodies, and wraps the single chmod call in an inline #[cfg(unix)] guard — matching the pattern already used by install_cursor_hooks (line 1622) and the Gemini installer (line 2152). Happy to rebase if #1090 lands first.

Why both can coexist

With both merged, Windows users get a tiered experience:

  1. git-bash present (standard Claude Code Windows install path) → rtk init -g installs the bash hook automatically, zero flags needed.
  2. no git-bash / no jqrtk init -g --native-hook installs the native binary hook.

With only #1090 merged, every Windows user needs to remember the --native-hook flag or hit the --claude-md fallback. This PR fills that default-UX gap for the common case.

Deferring to the maintainers. Closing this PR in favor of #1090 is also fine — the AccelixGames team has already verified the bash hook path works end-to-end on Windows 11 via hand-install (evidence in the PR description), so users can work around until either approach lands.

cc @ayoub-khemissi

aeppling added a commit that referenced this pull request Apr 19, 2026
Removing old guards, windows can now just use the binary hook engine from 0.37

Related issues:
- Fixes #502 : rtk init --global falls back to --claude-md on Windows
- Fixes #1353 : Feature request: hook-based mode on Windows
- Partially addresses #330 : Add hooks support for Windows
- Partially addresses #913 :  Persistent "No hook installed" warning on Windows
- Partially addresses #1373 : Suppress "No hook installed" warning on Windows
- Partially addresses #682 : Config to suppress hook warning
- Related to #1248 : Windows PowerShell compatibility gaps

Supersedes community PRs:
- #1123 fix(init): enable hook installation on Windows
- #1027 fix(init): enable hook-based mode on Windows
- #809 feat: enable hook-based mode on Windows
- #452 feat: add Windows hook support for rtk init --global
- #551 feat: native cross-platform hook for Windows support
- #150 feat(hook): native cross-platform hook-rewrite command
- #1063 Feat/windows hooks
@aeppling

Copy link
Copy Markdown
Contributor

Hey, solved on latest releases 0.37.x

Thanks for contributing and trying to address this issue.

Closing this for clean up

@aeppling aeppling closed this Apr 24, 2026
thehoff pushed a commit to thehoff/contextcrawler that referenced this pull request May 14, 2026
Removing old guards, windows can now just use the binary hook engine from 0.37

Related issues:
- Fixes rtk-ai#502 : rtk init --global falls back to --claude-md on Windows
- Fixes rtk-ai#1353 : Feature request: hook-based mode on Windows
- Partially addresses rtk-ai#330 : Add hooks support for Windows
- Partially addresses rtk-ai#913 :  Persistent "No hook installed" warning on Windows
- Partially addresses rtk-ai#1373 : Suppress "No hook installed" warning on Windows
- Partially addresses rtk-ai#682 : Config to suppress hook warning
- Related to rtk-ai#1248 : Windows PowerShell compatibility gaps

Supersedes community PRs:
- rtk-ai#1123 fix(init): enable hook installation on Windows
- rtk-ai#1027 fix(init): enable hook-based mode on Windows
- rtk-ai#809 feat: enable hook-based mode on Windows
- rtk-ai#452 feat: add Windows hook support for rtk init --global
- rtk-ai#551 feat: native cross-platform hook for Windows support
- #150 feat(hook): native cross-platform hook-rewrite command
- rtk-ai#1063 Feat/windows hooks
thehoff pushed a commit to thehoff/contextcrawler that referenced this pull request May 14, 2026
Removing old guards, windows can now just use the binary hook engine from 0.37

Related issues:
- Fixes rtk-ai#502 : rtk init --global falls back to --claude-md on Windows
- Fixes rtk-ai#1353 : Feature request: hook-based mode on Windows
- Partially addresses rtk-ai#330 : Add hooks support for Windows
- Partially addresses rtk-ai#913 :  Persistent "No hook installed" warning on Windows
- Partially addresses rtk-ai#1373 : Suppress "No hook installed" warning on Windows
- Partially addresses rtk-ai#682 : Config to suppress hook warning
- Related to rtk-ai#1248 : Windows PowerShell compatibility gaps

Supersedes community PRs:
- rtk-ai#1123 fix(init): enable hook installation on Windows
- rtk-ai#1027 fix(init): enable hook-based mode on Windows
- rtk-ai#809 feat: enable hook-based mode on Windows
- rtk-ai#452 feat: add Windows hook support for rtk init --global
- rtk-ai#551 feat: native cross-platform hook for Windows support
- #150 feat(hook): native cross-platform hook-rewrite command
- rtk-ai#1063 Feat/windows hooks
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