# Cursor-agent (Windows): imported Claude Code hooks are composed as PowerShell but executed with bash, silently blocking every tool call

**URL:** <https://forum.cursor.com/t/cursor-agent-windows-imported-claude-code-hooks-are-composed-as-powershell-but-executed-with-bash-silently-blocking-every-tool-call/168129>\
**Category:** Bug Reports\
**Tags:** cli, windows, hooks\
**Created:** [August 12, 2026, 12:04pm UTC](https://forum.cursor.com/t/cursor-agent-windows-imported-claude-code-hooks-are-composed-as-powershell-but-executed-with-bash-silently-blocking-every-tool-call/168129 "2026-08-12T12:04:47Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![lezli01](https://sea3.discourse-cdn.com/cursor1/user_avatar/forum.cursor.com/lezli01/32/117338_2.png) [@lezli01](https://forum.cursor.com/u/lezli01)\
**Post date:** [August 12, 2026, 12:04pm UTC](https://forum.cursor.com/t/cursor-agent-windows-imported-claude-code-hooks-are-composed-as-powershell-but-executed-with-bash-silently-blocking-every-tool-call/168129/1 "2026-08-12T12:04:48Z")

</div>

### Where does the bug appear (feature/product)?

Cursor CLI

### Describe the Bug

# cursor-agent (Windows): imported Claude Code hooks are composed as PowerShell but executed with bash, silently blocking every tool call

## Describe the Bug

On Windows, Cursor imports hooks from Claude Code’s config when no Cursor hook  
config exists. It then wraps each imported hook command in a **PowerShell**  
preamble, but evaluates the resulting string with **bash**. Every imported hook  
therefore dies on a bash syntax error — and because a hook that errors _blocks_  
the tool call, `cursor-agent` cannot edit files or run shell commands at all.

It still exits **0** and emits a clean `result` event, so in print mode the  
failure is completely silent. The agent reads, reasons, and reports success  
while every action it took was rejected.

## Steps to Reproduce

1. Windows 11 with Claude Code installed and at least one `PreToolUse` hook in  
`~/.claude/settings.json`.
2. No `~/.cursor/hooks.json`, no project-level `.cursor/hooks.json`.
3. In an empty git repo:

```powershell
cursor-agent -p "Create a file named hi.txt containing hello. Nothing else." `
  --output-format stream-json --trust --force --model auto > out.jsonl
Test-Path hi.txt

```

## Expected Behavior

`hi.txt` is created.

## Actual Behavior

`hi.txt` is never created. Exit code is **0** , stderr is empty, and the stream  
contains `tool_call/completed` entries carrying rejections — both  
`editToolCall` and `shellToolCall`:

```auto
"rejected": {
  "reason": "Hook blocked with message: --: eval: line 1: syntax error near unexpected token `&'
    --: eval: line 1: `$OutputEncoding = [System.Text.Encoding]::UTF8; Get-Content -LiteralPath
    'C:\\Users\\<user>\\AppData\\Local\\Temp\\cursor-hooks-GwQsZg\\payload.json' -Raw
    | & { $input | npx -y context-mode hook cursor pretooluse }'

    Agent note: Do not suggest workarounds to the blocked tool."
}

```

The command being evaluated is PowerShell (`$OutputEncoding`, `Get-Content -LiteralPath`, `| & { $input | ... }`), and the error is bash’s  
(`eval: line 1: syntax error near unexpected token`). The `cursor-hooks-XXXXXX`  
temp directory in that path is created by Cursor itself, so the PowerShell  
wrapper is Cursor’s own composition — not anything the user wrote.

## Why the hooks are Claude Code’s

Nothing was ever registered on the Cursor side. Cursor’s hook log states the  
resolution order and the outcome:

```auto
User config path: c:\Users\<user>\.cursor\hooks.json
Claude user config path: c:\Users\<user>\.claude\settings.json
No user hooks configuration found <- no Cursor hook config exists
Loaded Claude user hooks <- Claude Code's are adopted instead

```

(`%APPDATA%\Cursor\logs\<timestamp>\window1_wb1\output_<timestamp>\cursor.hooks.workspaceId-*.log`)

`cursor-agent` does the same — its bundle carries `claudeUserHooks`,  
`claudeProjectHooks` and `claudeProjectLocalHooks`.

The two hooks blocking everything on this machine were `rtk hook claude` (a  
`PreToolUse` entry in `~/.claude/settings.json`) and  
`npx -y context-mode hook cursor pretooluse` (contributed by a Claude Code  
plugin). Both are perfectly valid Claude Code hooks. Neither was written for  
Cursor.

## Impact

Any Windows user with Claude Code hooks configured has a `cursor-agent` that  
can read and reason but silently cannot act — with no error, no non-zero exit,  
and nothing in stderr. In an automated harness this is worse than a crash: the  
agent step “succeeds” and the _next_ step fails for an unrelated-looking reason  
(`nothing to commit, working tree clean`). It took two days to trace, and the  
symptom points away from the cause at every step.

There is also no obvious off-switch: `cursor-agent` has no  
`CLAUDE_CONFIG_DIR` support, and I could find no setting to disable the Claude  
hook import.

## Suggested Fix

1. Execute the PowerShell-composed command **with PowerShell** , or compose a  
bash-compatible command when executing with bash.
2. Separately: a hook that fails to _execute_ is arguably different from a hook  
that _denies_ a tool call. Right now a broken hook silently becomes a  
full-deny. A hook that cannot run at all could be surfaced as an error  
rather than as a rejection with `"Do not suggest workarounds to the blocked tool."`
3. A documented way to opt out of importing Claude Code hooks would help  
regardless.

## Workaround (for anyone who finds this)

Give `cursor-agent` a home directory containing your real `.cursor` and no  
`.claude`:

```powershell
$fh = "$env:TEMP\cursor-clean-home"
New-Item -ItemType Directory -Force $fh | Out-Null
cmd /c mklink /J "$fh\.cursor" "$env:USERPROFILE\.cursor" # no elevation needed
$env:USERPROFILE = $fh; $env:HOME = $fh

```

The junction keeps authentication working. Verified: 3 rejections and no file  
written → **0 rejections and the file created**.

⚠ If you later delete that scratch directory, remove the junction with  
`cmd /c rmdir "$fh\.cursor"` first — a recursive delete that follows junctions  
would walk into your real Cursor config.

## Environment

- **OS:** Windows 11 Enterprise 10.0.26200
- **cursor-agent:** `2026.08.11-e8db854` (also reproduced on `2026.08.04-aaa8809`)
- **Flags:** `-p --output-format stream-json --trust --force --model auto`
- **Config:** `approvalMode: allowlist`, `sandbox.mode: disabled`
- **Not shell-dependent:** reproduced from PowerShell with `SHELL` not exported,  
and with a clean Windows `PATH`. The launching shell makes no difference — I  
chased that first and it was a dead end.

## Does this stop you from using Cursor?

Yes for headless/automated use on Windows. Interactive use is affected too, but  
there a user notices the rejections; in print mode nothing surfaces at all.

### Steps to Reproduce

1. Windows 11 with Claude Code installed and at least one `PreToolUse` hook in  
`~/.claude/settings.json`.
2. No `~/.cursor/hooks.json`, no project-level `.cursor/hooks.json`.
3. In an empty git repo:

```powershell
cursor-agent -p "Create a file named hi.txt containing hello. Nothing else." `
  --output-format stream-json --trust --force --model auto > out.jsonl
Test-Path hi.txt

```

### Expected Behavior

`hi.txt` is created.

### Operating System

Windows 10/11

### Version Information

- **OS:** Windows 11 Enterprise 10.0.26200
- **cursor-agent:** `2026.08.11-e8db854` (also reproduced on `2026.08.04-aaa8809`)
- **Flags:** `-p --output-format stream-json --trust --force --model auto`
- **Config:** `approvalMode: allowlist`, `sandbox.mode: disabled`
- **Not shell-dependent:** reproduced from PowerShell with `SHELL` not exported,  
and with a clean Windows `PATH`. The launching shell makes no difference — I  
chased that first and it was a dead end.

### Does this stop you from using Cursor

Yes - Cursor is unusable

---

<div class="post-metadata">

**Author:** ![deanrie](https://sea3.discourse-cdn.com/cursor1/user_avatar/forum.cursor.com/deanrie/32/1263_2.png) [@deanrie](https://forum.cursor.com/u/deanrie)\
**Post date:** [August 12, 2026, 12:32pm UTC](https://forum.cursor.com/t/cursor-agent-windows-imported-claude-code-hooks-are-composed-as-powershell-but-executed-with-bash-silently-blocking-every-tool-call/168129/5 "2026-08-12T12:32:06Z")

</div>

Hey, thanks for the report. It’s one of the most detailed ones I’ve seen. Your diagnosis is correct, and we reproduced it: on Windows, the hook command is built as PowerShell, but it gets executed through bash when the environment has Git Bash markers. Bash crashes on the syntax, exit 2 matches the block code, so you get a quiet full-deny of all tool calls in print mode. I’ve passed this to the team.

For now, interim options:

- Your junction trick with a clean `HOME` and `USERPROFILE` (no `.claude`, with a junction pointing to the real `.cursor`) is a valid workaround, keep using it for headless.
- As an alternative, if your persistent environment has Git Bash markers like `MSYSTEM`, `EXEPATH`, or a global `SHELL` pointing to git-bash, removing them may force the CLI to pick PowerShell for execution, and imported hooks should run correctly.

On your specific points:

- The fact that a hook that fails to start turns into a full-deny with the trailer “Do not suggest workarounds” instead of a clear execution error is a good catch. I’ve sent that as feedback.
- Opting out of importing Claude Code hooks in the CLI is already being tracked here: [No way to opt out of third-party (Claude Code / Codex) config loading - the flag is hardcoded](https://forum.cursor.com/t/no-way-to-opt-out-of-third-party-claude-code-codex-config-loading-the-flag-is-hardcoded/166558) Please subscribe to the thread, updates will be posted there.

I can’t share a timeline for the main issue yet, but I’ll reply here when there’s an update. Let me know if the workaround doesn’t work in your harness.

---

<div class="post-metadata">

**Author:** ![lezli01](https://sea3.discourse-cdn.com/cursor1/user_avatar/forum.cursor.com/lezli01/32/117338_2.png) [@lezli01](https://forum.cursor.com/u/lezli01)\
**Post date:** [August 12, 2026, 1:07pm UTC](https://forum.cursor.com/t/cursor-agent-windows-imported-claude-code-hooks-are-composed-as-powershell-but-executed-with-bash-silently-blocking-every-tool-call/168129/7 "2026-08-12T13:07:42Z")

</div>

**Update: isolated the trigger — it’s `MSYSTEM`**

Follow-up to the report above, with a much smaller reproduction and one  
correction.

The hook block only happens when **`MSYSTEM`** is set in the environment. That  
variable is exported by Git Bash / MSYS2 for every process it spawns. With it  
set, Cursor executes its PowerShell-composed hook command with bash; without  
it, the very same hooks run fine.

Isolated on one machine, same `cursor-agent 2026.08.11-e8db854`, same  
`~/.claude` hooks, runs minutes apart. Each run starts from a fresh default  
(registry-derived) environment plus exactly one addition:

| Environment | `hi.txt` created | `Hook blocked` occurrences |
| --- | --- | --- |
| clean default environment | yes | 0 |
| clean + `MSYSTEM=MINGW64` | **no** | **5** |
| clean + Git Bash `\usr\bin` on `PATH` (no `MSYSTEM`) | yes | 0 |

So it is not `PATH`, and it is not the mere availability of bash — it is  
`MSYSTEM` alone.

**Minimal repro** on any Windows machine with Claude Code hooks configured in  
`~/.claude/settings.json`:

```auto
set MSYSTEM=MINGW64
cursor-agent -p "Create a file named hi.txt containing hello. Nothing else." --output-format stream-json --trust --force --model auto

```

`hi.txt` is not created, the stream carries `"rejected"` entries with the bash  
syntax error from the original post, and the exit code is still **0**.

Two things that make this worse than it first looks:

1. **`MSYSTEM` cannot be unset from inside Git Bash.** The MSYS runtime injects  
it into the environment block of every child process — both `env -u MSYSTEM`  
and `unset MSYSTEM` still leave a _native_ Windows child seeing  
`MSYSTEM=MINGW64`. So a user whose tooling launches `cursor-agent` from a  
Git Bash-parented process cannot opt out at all, short of relocating  
`HOME`/`USERPROFILE` away from `~/.claude`.

2. It reaches far past interactive use. Anything descended from Git Bash  
inherits it: shell scripts, test harnesses, and any long-running daemon or  
agent started from an MSYS shell. The same `cursor-agent` invoked from  
PowerShell, `cmd`, or a Windows Scheduled Task works perfectly — which is  
what makes it look intermittent.

**Correction to the original post:** having Claude Code hooks configured is  
necessary but _not sufficient_ — `MSYSTEM` must also be set. On a stock Windows  
shell the report will not reproduce, which is likely why it appears  
environment-specific.

---

<div class="post-metadata">

**Author:** ![deanrie](https://sea3.discourse-cdn.com/cursor1/user_avatar/forum.cursor.com/deanrie/32/1263_2.png) [@deanrie](https://forum.cursor.com/u/deanrie)\
**Post date:** [August 12, 2026, 3:23pm UTC](https://forum.cursor.com/t/cursor-agent-windows-imported-claude-code-hooks-are-composed-as-powershell-but-executed-with-bash-silently-blocking-every-tool-call/168129/9 "2026-08-12T15:23:22Z")

</div>

Hey, great follow-up. Narrowing it down to `MSYSTEM` really helps, thanks. This is super useful because it confirms it’s not about `PATH` or bash being present, it’s specifically that `MSYSTEM` makes the CLI pick bash to run a PowerShell-composed hook command. I added your comparison table, minimal repro, and the correction that Claude hooks are necessary but not sufficient to what I already sent to the team.

Also really valuable note that you can’t clear `MSYSTEM` from inside Git Bash. MSYS re-injects it into child processes, so `unset` or `env -u` won’t help for a native child. That makes the situation for a Git Bash-parented harness worse than it looks. There’s basically no opt-out except relocating `HOME` and `USERPROFILE`. I called that out too.

Your junction workaround with a clean `HOME` and `USERPROFILE` is still solid for headless runs, stick with it for now. I can’t share a timeline for the main issue yet, but I’ll post here when there’s an update. For an opt-out from importing third-party configs, keep an eye on the thread I linked above, updates will be posted there.

---

<div class="post-metadata">

**Author:** ![Joshua-Asante](https://sea3.discourse-cdn.com/cursor1/user_avatar/forum.cursor.com/joshua-asante/32/118129_2.png) [@Joshua-Asante](https://forum.cursor.com/u/Joshua-Asante)\
**Post date:** [August 20, 2026, 2:54am UTC](https://forum.cursor.com/t/cursor-agent-windows-imported-claude-code-hooks-are-composed-as-powershell-but-executed-with-bash-silently-blocking-every-tool-call/168129/10 "2026-08-20T02:54:54Z")

</div>

Independent repro today (2026-08-19), same version (2026.08.11-e8db854, already latest per `cursor-agent update`), same error signature. Adding a data point on how broad the trigger class is.

My hook source is a third one, different from `rtk hook claude` / `context-mode`: the community **hookify** Claude Code plugin (`~/.claude/plugins/cache/claude-plugins-official/hookify/.../hooks/pretooluse.py`, registered via `~/.claude/settings.json` → `"enabledPlugins": {"hookify@claude-plugins-official": true}`). Confirms it’s not specific to any one hook provider – any Claude Code PreToolUse hook plus `MSYSTEM` set (I launch from Git Bash, so that’s always true here) triggers it.

Two things to add:

- It also blocks `--mode plan` (read-only planning, no `--force`) – a plan-only session with zero intended writes still gets every shell tool call rejected the same way.
- 
  - It’s silent in a way that’s easy to miss even when looking for it: `--print --output-format json` still returns `"is_error":false,"subtype":"success"` at the top level, and the model just narrates around the failure. Mine substituted CLAUDE.md-documented text for a real `ls` and said so – but only because I’d explicitly asked it to report tool errors verbatim. Anything checking just the top-level result status reads this as a clean success.

- Exact rejection text, for the corpus:

````auto

Rejected: Hook blocked with message: --: eval: line 1: syntax error near unexpected token `&'
--: eval: line 1: `$OutputEncoding = [System.Text.Encoding]::UTF8; Get-Content -LiteralPath 'C:\Temp\cursor-hooks-wK2Lxx\payload.json' -Raw | & { $input | python3 "C:\Users\<user>\.claude\plugins\cache\claude-plugins-official\hookify\unknown/hooks/pretooluse.py" }'

Agent note: Do not suggest workarounds to the blocked tool.
```

Same PowerShell-composed-but-bash-evaluated pattern as the OP, same "Agent note" line verbatim.

Using the junction workaround for now -- appreciate the confirmation this is already with engineering. Wanted the hookify + plan-mode data points on record in case they help narrow the fix.

````

---

<div class="post-metadata">

**Author:** ![deanrie](https://sea3.discourse-cdn.com/cursor1/user_avatar/forum.cursor.com/deanrie/32/1263_2.png) [@deanrie](https://forum.cursor.com/u/deanrie)\
**Post date:** [August 28, 2026, 3:41pm UTC](https://forum.cursor.com/t/cursor-agent-windows-imported-claude-code-hooks-are-composed-as-powershell-but-executed-with-bash-silently-blocking-every-tool-call/168129/11 "2026-08-28T15:41:19Z")

</div>

Hey, thanks for the independent repro and the detailed data points. This really helps.

Three things you added are especially useful, and I passed them to the team along with the context we already collected:

- hookify as a third provider, which confirms this is not about a specific hook but about the combo of any Claude Code PreToolUse hook and `MSYSTEM`.
- The fact that `--mode plan` is also affected, even though it is not going to write anything.
- The silent behavior with `--print --output-format json` (`is_error:false`, `subtype:success` at the top level). I agree this is the trickiest part because the harness reads it as a clean success.

Like in the main thread, until there is a fix, the junction workaround with a clean `HOME` and `USERPROFILE` is still a working option for headless. You are already doing that.

I can’t share a timeline yet, but I’ll reply here when I have an update. For the opt-out from importing third-party configs, it is best to follow this thread: [No way to opt out of third-party (Claude Code / Codex) config loading - the flag is hardcoded](https://forum.cursor.com/t/no-way-to-opt-out-of-third-party-claude-code-codex-config-loading-the-flag-is-hardcoded/166558)
