Windows wrapper for Claude Code with EPERM crash fix and Git Bash integration
npm install wclaude/fork to branch your conversation into a new Windows Terminal tab - perfect for exploring different approaches without losing your original session! 🎉
blocklist.js is super useful 🎉 And the toast notifications when Claude needs attention (with click-to-focus!) 🎉
--dangerously-skip-permissions. You are responsible for reviewing Claude's actions. We take no responsibility for outcomes when running Claude Code this way.
--dangerously-skip-permissions with this wrapper. That flag bypasses Claude Code's permission system entirely, which means our auto-approve hooks and blocklist won't see requests at all. The wrapper already handles permissions just as fast and safer.
powershell
Install Claude Code and this wrapper
npm install -g @anthropic-ai/claude-code --ignore-scripts
npm install -g wclaude
Run!
wclaude
`
That's it! All features are built-in - no separate launcher needed.
Features
$3
| Feature | What it does |
|---------|--------------|
| /fork Conversation | Branch your session into a new Windows Terminal tab |
| Ctrl+Break Unfreeze | Kill stuck child processes without closing your session |
| Hook Interception | Auto-approve tools with configurable blocklist (blocklist.js) |
| Toast Notifications | Persistent Windows alerts with click-to-focus (requires PowerShell 7.1+) |
$3
| Feature | Description | Details |
|---------|-------------|---------|
| EPERM Crash Fix | Prevents crashes on command termination | → |
| Cygpath Fix | Intercepts cygpath for Git Bash/MSYS | → |
| Auto-Restart | Restarts on crash (max 3/min) | → |
| Network Auto-Restart | Waits for internet with backoff | → |
| Dynamic Heap | 75% of RAM, max 32GB | → |
| API Token Loading | Loads from Windows Registry | → |
| Git Bash Integration | Enables Unix commands (grep, find, etc.) | → |
| WSL Detection | Auto-redirects \\wsl$\... paths | → |
| Git PATH Fix | Prefers Program Files Git over Scoop | → |
| MCP Module Junction | Links ~/.mcp-modules to npm global | → |
| /fork Slash Command | Auto-installed to ~/.claude/commands/ | → |
Why This Wrapper?
Claude Code on Windows experiences several issues:
1. EPERM Crashes - process.kill() fails with ACCESS_DENIED, crashing the session
2. Cygpath Crashes - Claude Code calls cygpath internally, which doesn't exist on Git Bash/MSYS (#9883, #7528)
3. Missing Bash - Claude Code checks for /bin/bash which doesn't exist on Windows
4. Path Issues - Windows paths don't work with Unix-style tools
5. Memory Issues - Large projects need more heap than the default
This wrapper hooks into Node.js to fix these issues automatically.
Installation
$3
`powershell
1. Install Claude Code (skip postinstall scripts that assume Unix)
npm install -g @anthropic-ai/claude-code --ignore-scripts
2. Install this wrapper
npm install -g wclaude
3. Run!
wclaude
`
$3
`powershell
git clone https://github.com/johanclawson/wclaude.git
cd wclaude
npm link
wclaude
`
Usage
`powershell
Run Claude Code
wclaude
Run in specific directory
wclaude /path/to/project
Continue last session
wclaude --continue
Run with debug logging (writes to ~/.claude/debug.log)
wclaude --windebug
`
Keyboard Shortcuts
| Shortcut | Action | Description |
|----------|--------|-------------|
| Ctrl+C | Clean exit | Kills all child processes and exits the wrapper |
| Ctrl+Break | Unfreeze | Kills stuck child processes but keeps the session running |
$3
If Claude Code gets stuck (e.g., a long-running command hangs), press Ctrl+Break to kill all child processes without closing your session. This is useful when:
- A bash command times out but doesn't terminate
- A subprocess becomes unresponsive
- You want to interrupt a stuck operation without losing your conversation
Note: On Windows, Ctrl+Break always works even if Ctrl+C is disabled or being caught by a subprocess. The Break key is typically located near Scroll Lock on full keyboards, or accessed via Fn+B or Fn+Pause on laptops.
$3
Type /fork in wclaude to branch your current conversation into a new Windows Terminal tab. Both sessions share the same history up to the fork point but can then diverge independently.
Use cases:
- Explore an alternative approach without losing your current progress
- Test a risky change in a separate session
- Work on multiple aspects of a problem in parallel
- Keep a "checkpoint" of your conversation before a major change
How it works:
1. Type /fork in your wclaude session
2. A new Windows Terminal tab opens with the forked conversation
3. The new session uses --continue --fork-session flags
4. Both sessions can now proceed independently
Features:
- Opens in a new Windows Terminal tab (preserves your color scheme)
- Falls back to cmd.exe if Windows Terminal is unavailable
- Uses PowerShell to maintain your default terminal profile settings
- The forked session gets a new session ID but retains all conversation context
Requirements:
- Windows Terminal (recommended) or cmd.exe as fallback
- PowerShell 7+ (pwsh) for Windows Terminal integration
Configuration
$3
Store API tokens in Windows Registry (User environment variables):
`powershell
[Environment]::SetEnvironmentVariable("ANTHROPIC_API_KEY", "your-key", "User")
[Environment]::SetEnvironmentVariable("GITHUB_TOKEN", "your-token", "User")
`
The wrapper automatically loads these tokens on startup.
$3
Add to ~/.claude/settings.json:
`json
{
"env": {
"BASH_DEFAULT_TIMEOUT_MS": "1800000",
"BASH_MAX_TIMEOUT_MS": "7200000"
}
}
`
How It Works
$3
| Function | Purpose |
|----------|---------|
| setupEnvironment() | Sets MSYS env vars (prevents path mangling), NODE_OPTIONS (dynamic heap: 75% RAM, max 32GB) |
| setupGitPath() | Prefers Program Files Git over Scoop Git |
| loadApiTokensFromRegistry() | Loads API tokens from Windows Registry |
| setupMcpModules() | Creates junction for MCP servers (see MCP Module Junction) |
| handleWslPath() | Redirects WSL paths to WSL |
| runWithAutoRestart() | Auto-restarts on crash (max 3/minute) |
$3
| Hook | Purpose |
|------|---------|
| fs.accessSync | Returns true for /bin/bash checks |
| child_process.spawn | Redirects /bin/bash to Git Bash, intercepts hook commands |
| process.kill | Catches EPERM, uses taskkill fallback, preserves return semantics |
| ChildProcess.prototype.kill | Catches EPERM on child processes, preserves return semantics |
| child_process.execSync | Intercepts cygpath calls, uses built-in path conversion |
| fs.readFileSync | Injects PermissionRequest hook into settings.json dynamically |
$3
The wrapper has two separate restart mechanisms:
Regular Crashes:
- Max 3 restarts within a 1-minute window
- If crashes are spaced > 1 minute apart, counter resets
- 1 second delay between restarts
- Clear error message when giving up
Network Disconnections:
- Detects network-related errors (ENOTFOUND, ETIMEDOUT, ECONNRESET, etc.)
- Uses DNS lookup to api.anthropic.com to check connectivity
- Exponential backoff: 5s → 10s → 20s → 40s → 60s (max)
- Up to 10 retries (~5 minutes total wait time)
- Automatically resumes when connection is restored
- Network retries don't count against the crash limit
$3
The wrapper implements auto-approve permissions entirely in JavaScript - no external PowerShell scripts or settings.json configuration needed:
How it works:
1. fs.readFileSync hook injects a PermissionRequest hook into settings.json when Claude Code reads it
2. spawn hook intercepts the injected hook command and handles it natively
3. Auto-approves all tools except AskUserQuestion and ExitPlanMode
4. Shows Windows toast notification when user action is required
Benefits:
- No external script dependencies
- No hooks needed in ~/.claude/settings.json
- ~400-800ms faster than PowerShell-based hooks
- Falls-open on errors to avoid blocking sessions
$3
MCP (Model Context Protocol) servers expect to find Claude Code modules at ~/.mcp-modules/node_modules/@anthropic-ai/claude-code. However, npm installs global packages to %APPDATA%\npm\node_modules.
The wrapper creates a Windows directory junction to bridge this gap:
`
~/.mcp-modules/node_modules/@anthropic-ai/claude-code → %APPDATA%/npm/node_modules/@anthropic-ai/claude-code
`
Safety:
- Never deletes existing files or directories
- Skips if path already exists (even if not a junction)
- Non-fatal: MCP still works if junction creation fails
Debug: Use --windebug to see junction status in ~/.claude/debug.log
Context Menu Integration
Add "Open with Claude Code" to folder right-click menu:
1. Run .\registry\install-context-menu.reg
2. Confirm the registry modification
3. Right-click any folder to see the option
To remove: Run .\registry\uninstall-context-menu.reg
Troubleshooting
$3
Install Git for Windows. The wrapper checks:
- C:\Program Files\Git\usr\bin\bash.exe
- C:\Program Files (x86)\Git\usr\bin\bash.exe
Note: Scoop-installed Git may have issues. Prefer the official installer.
$3
If you see errors like Command failed: cygpath -u '...', this wrapper fixes them automatically by intercepting cygpath calls. The fix:
- Intercepts all cygpath -u calls before they execute
- Sanitizes paths (removes carriage returns, malformed quotes)
- Converts Windows paths to POSIX using built-in windowsToPosix()
This is a known Claude Code bug on Windows (#9883, #7528).
To debug cygpath interceptions, run with --windebug and check ~/.claude/debug.log for "cygpath intercepted" entries.
$3
1. Check timeout settings in ~/.claude/settings.json
2. Update to latest version: npm update -g wclaude
3. Check for errors in console output
Requirements
- Windows 10/11
- Node.js 18+
- npm
- Git for Windows (optional but recommended)
- PowerShell 7.1+ (optional, for toast notifications with click-to-focus)
$3
Toast notifications with click-to-focus require PowerShell 7.1 or later. Without it, wclaude still works but won't show notifications.
`powershell
Option 1: winget (recommended)
winget install Microsoft.PowerShell
Option 2: Microsoft Store
Search for "PowerShell" in the Microsoft Store
Option 3: Direct download
https://github.com/PowerShell/PowerShell/releases
`
After installation, verify with:
`powershell
pwsh --version
Should show: PowerShell 7.x.x
`
Contributing
$3
`powershell
Clone the repository
git clone https://github.com/johanclawson/wclaude.git
cd wclaude
Install dependencies
npm install
Link for local development
npm link
`
$3
Use the --windebug flag to enable debug logging. Logs are written to ~/.claude/debug.log:
`powershell
Run with debug logging enabled
wclaude --windebug
View the debug log after running
Get-Content ~/.claude/debug.log
Or tail the log in real-time (in a separate terminal)
Get-Content ~/.claude/debug.log -Wait
`
Debug log shows:
- Environment configuration status
- Git PATH modifications
- API tokens loaded from registry
- MCP modules directory setup
- Signal handlers installed
- Hooks applied
Each log entry includes a timestamp for troubleshooting timing issues.
Example hook interception log:
`
[timestamp] Intercepting injected PermissionRequest hook
[timestamp] Hook stdout.setEncoding called: utf8
[timestamp] Hook stderr.setEncoding called: utf8
[timestamp] Hook stdin.write called, chunk length: 585
[timestamp] Hook stdin.end called, total data length: 585
[timestamp] PermissionRequest for tool: Bash
[timestamp] Auto-approving tool: Bash
[timestamp] Hook response: {"hookSpecificOutput":{"hookEventName":"PermissionRequest","decision":{"behavior":"allow"}}}
`
$3
The project uses Jest for testing with ES Modules support:
`powershell
Run all tests
npm test
Run tests with coverage
npm run test:coverage
Run tests in watch mode
npm run test:watch
`
$3
`
tests/
utils.test.js - Tests for windowsToPosix, calculateBackoff, parseArgs, CONFIG
network.test.js - Tests for isNetworkError detection
signals.test.js - Tests for signal handler configuration
validation.test.js - Tests for validateBashCommand and blocklist.js exports
hooks.test.js - Tests for hook interception (PermissionRequest, StopHook)
`
$3
The project is split across two main files:
runner.js - Main wrapper with hooks and auto-restart logic:
- CONFIG - Configuration constants
- windowsToPosix() - Path conversion
- calculateBackoff() - Exponential backoff calculation
- isNetworkError() - Network error detection
- parseArgs() - Argument parsing
- handlePermissionRequest() / handleStopHook() - Hook handlers
- Node.js hooks (fs.accessSync, spawn, process.kill, etc.)
- Auto-restart and signal handling
blocklist.js - Command validation rules (easy to update):
- cygpathRules - Patterns that crash cygpath (nested quotes, shell expansion, UNC paths)
- safetyRules - Patterns that hang sessions (dir /s, find, tree, git --all without limits)
- config - Constants (maxPathLength: 260)
- validateCommand() / validateBashCommand() - Main validation function
$3
1. Fork the repository
2. Create a feature branch: git checkout -b feature/my-feature
3. Run tests: npm test`