MCP, plugins, skills, and hooks changedthird-party/claude-desktop/extensions
Nearest release: v2.1.318, published 4 hours after upstream edited the page. Shown because the two are within 24 hours of each other. Nothing here says the release caused the edit.
Upstream edited this page at 3 Nov 2026 17:52 UTC, give or take a minute or two: the time comes from Anthropic’s own sitemap rather than from a commit. This site recorded the change at 3 Nov 2026 18:07 UTC.
Upstream edited
Recorded here
Lines+4added
Lines−3removed
From line
439
where the diff opens
First seen
14 Aug 2026
this site's first read of the page
Recorded edits38to this page, all time
The whole hunk
from line 439, old and new numbered
/
from line 439
439439
440440When a hook blocks tool calls on such a device, check for each of these causes:
441441
442* **The hook fails or times out**: on a Windows device without Git for Windows, a [`PreToolUse`](https://code.claude.com/docs/en/hooks#pretooluse) or [`PermissionRequest`](https://code.claude.com/docs/en/hooks#permissionrequest) command hook that has no `args` and no `onFailure` field blocks the tool call when it fails or times out, whatever `shell` it sets. A hook written for Bash that was given `"shell": "powershell"` can block every tool call that it matches. Under Windows PowerShell 5.1, which Claude Code uses when PowerShell 7 isn't installed, a program that writes to stderr under a redirect in the command, such as `2>&1`, can make the hook count as failed although the program exits with 0. The hook error that Claude receives includes `blocking because Git Bash wasn't found`.
442* **The hook fails or times out**: a [`PreToolUse`](https://code.claude.com/docs/en/hooks#pretooluse) or [`PermissionRequest`](https://code.claude.com/docs/en/hooks#permissionrequest) command hook that has no `args` and no `onFailure` field blocks the tool call when it fails or times out, whatever `shell` it sets. A hook written for Bash that was given `"shell": "powershell"` can block every tool call that it matches. Under Windows PowerShell 5.1, which Claude Code uses when PowerShell 7 isn't installed, a program that writes to stderr under a redirect in the command, such as `2>&1`, can make the hook count as failed although the program exits with 0. The hook error that Claude receives includes `blocking because Git Bash wasn't found`.
443* **The command is only a quoted path**: a `PreToolUse` or `PermissionRequest` hook that sets none of `shell`, `args`, and `"onFailure": "continue"` blocks the tool call when its command is only a quoted path, as in `"command": "\"C:\\path\\guard.exe\""`. Bash runs that program, but PowerShell only prints the path. Adding `"onFailure": "continue"` or `"shell": "powershell"` stops the blocking, but the program still doesn't start, so the hook checks nothing.
443444* **The hook ends with exit code 2**: a `PreToolUse` hook that ends with exit code 2 blocks the tool call whatever `onFailure` says, and the error that Claude then receives is the hook's own error output. In PowerShell a `PreToolUse` hook ends with 2 when its command ends with a program that exits with 2. That reaches a hook written for Bash such as `python $CLAUDE_PROJECT_DIR/check.py`, even with `"onFailure": "continue"`. A bare `$CLAUDE_PROJECT_DIR` is empty in PowerShell, so Python can't open its script and exits with 2.
444445
445446If your Windows devices have hooks, in a plugin or in Claude Code [managed settings](https://claude.com/docs/third-party/claude-desktop/code.md#interaction-with-claude-code%E2%80%99s-own-managed-settings), make one of these changes:
446447
447448* **Keep a hook written for Bash**: install Git for Windows in its default location (`C:\Program Files\Git`) on each device, remove `"shell": "powershell"` from the hook if it has it, then quit and reopen Claude Desktop
448* **Run the hook without a shell**: write the hook in [exec form](https://code.claude.com/docs/en/hooks#exec-form-and-shell-form), with an executable such as an `.exe` (not a `.cmd` or `.bat` file) in `command` and its arguments in `args` (`"args": []` if it has none). Write the project folder as `${CLAUDE_PROJECT_DIR}`, braces included, since no shell expands `$CLAUDE_PROJECT_DIR` there. A Bash script can't run this way without Git.
449* **Keep a hook written for PowerShell**: set `"shell": "powershell"` and `"onFailure": "block"` on it, and start its program with the call operator, as in `& "C:\path\guard.exe"`, since a quoted path alone starts nothing. Make the program the last thing that the command runs, and in a `PreToolUse` hook have it exit with 0 to let the tool call go on and with 2 to block it. A `.ps1` script does so through its own `exit 0` or `exit 2`. A script whose last line runs a program ends with 0 even when that program exits with 2, so start the program from the command and not from inside a script. Don't redirect the program's stderr in the command, and don't end the command with `exit $LASTEXITCODE`. If the program can't start, `exit $LASTEXITCODE` exits with 0 and the tool call goes ahead, even with `"onFailure": "block"`.
449* **Run the hook without a shell**: write the hook in [exec form](https://code.claude.com/docs/en/hooks#exec-form-and-shell-form), with an executable such as an `.exe` (not a `.cmd` or `.bat` file) in `command` and its arguments in `args` (`"args": []` if it has none). Write the path without quotes of its own, even when it has spaces, as in `"command": "C:\\Program Files\\Guard\\guard.exe"`. Write the project folder as `${CLAUDE_PROJECT_DIR}`, braces included, since no shell expands `$CLAUDE_PROJECT_DIR` there. A Bash script can't run this way without Git.
450* **Keep a hook written for PowerShell**: set `"shell": "powershell"` and `"onFailure": "block"` on it, and start its program with the call operator, as in `"command": "& \"C:\\path\\guard.exe\""`. Make the program the last thing that the command runs, and in a `PreToolUse` hook have it exit with 0 to let the tool call go on and with 2 to block it. A `.ps1` script does so through its own `exit 0` or `exit 2`. A script whose last line runs a program ends with 0 even when that program exits with 2, so start the program from the command and not from inside a script. Don't redirect the program's stderr in the command, and don't end the command with `exit $LASTEXITCODE`. If the program can't start, `exit $LASTEXITCODE` exits with 0 and the tool call goes ahead, even with `"onFailure": "block"`.
450451
451452After either of the first two changes, a hook that fails or times out lets the tool call go ahead. To stop the tool call instead, add [`"onFailure": "block"`](https://code.claude.com/docs/en/hooks#block-the-action-when-a-hook-fails) to the hook.
452453
No line in this hunk matches that.