fix(hooks): force bash shell for WorktreeCreate hook on Windows#442
Conversation
The WorktreeCreate hook in .claude/settings.json is a POSIX shell script ($(...), [ -z ], &&, ;) but had no explicit "shell" field. On at least one Windows setup, the hook runner's shell-detection fell back to cmd.exe instead of Git Bash -- even though the interactive Bash tool on the same machine correctly detected and used Git Bash -- so the hook failed with cmd.exe's "'name' is not recognized as an internal or external command" error. Add "shell": "bash" to force Git Bash execution regardless of the platform default, and document the gotcha (plus the CLAUDE_CODE_GIT_BASH_PATH escape hatch) in CLAUDE.md and the persistent hook-contract memory, since this hook has already needed several rounds of Windows-specific fixes. Verified end-to-end via EnterWorktree/ExitWorktree: worktree created with a real checkout and correct branch registration. Signed-off-by: Rhuan Barreto <rhuan@barreto.work>
Deploying archgate-cli with
|
| Latest commit: |
0028cd4
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://3a84bc34.archgate-cli.pages.dev |
| Branch Preview URL: | https://fix-worktree-hook-windows-sh.archgate-cli.pages.dev |
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (3)
📜 Recent review details⏰ Context from checks skipped due to timeout. (3)
|
| File | Change Summary |
|---|---|
.claude/settings.json |
Added "shell": "bash" to the WorktreeCreate command hook configuration. |
CLAUDE.md |
Documented requirement that command-type hooks set "shell": "bash", including failure symptoms and bash path resolution order. |
.claude/agent-memory/archgate-developer/project_worktree_create_hook_contract.md |
Added an incident record describing the cmd.exe fallback bug, the fix, and verification via EnterWorktree/ExitWorktree. |
Sequence Diagram(s)
Not applicable — this change consists of a configuration field addition and documentation updates with no new control flow.
Estimated code review effort: 1 (Low) — a single-line configuration addition accompanied by documentation.
Related issues: None specified.
Related PRs: None specified.
Suggested labels: documentation, configuration
Suggested reviewers: None specified.
🐰 A shell once ran in cmd's disguise,
"name not recognized" — a bash surprise.
One line was set, "shell": "bash" so true,
Now worktrees create as they ought to do.
Hop, commit, and cleanup too!
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
| Check name | Status | Explanation |
|---|---|---|
| Title check | ✅ Passed | It clearly summarizes the main change: forcing Bash for the Windows WorktreeCreate hook. |
| Description check | ✅ Passed | It directly describes the hook shell fix and the documentation updates. |
| Docstring Coverage | ✅ Passed | No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. |
| Linked Issues check | ✅ Passed | Check skipped because no linked issues were found for this pull request. |
| Out of Scope Changes check | ✅ Passed | Check skipped because no linked issues were found for this pull request. |
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.
Comment @coderabbitai help to get the list of available commands.
|
@cursor approve |
|
Approved. Evaluated PR #442 against
Change review: The one-line Verdict: Approve. Ready to merge once remaining non-blocking checks (Coverage Report, CodeRabbit) finish. Note: This environment’s GitHub token cannot submit a formal |
Code Coverage
Full HTML report available in workflow artifacts. Per-directory breakdown
|
There was a problem hiding this comment.
Approved. Cursor Bugbot passed with no findings, and all required CI checks (Lint/Test, Windows and Linux smoke tests, Coverage) are green. This is a focused harness config fix adding explicit "shell": "bash" to the WorktreeCreate hook plus documentation; no additional reviewers assigned.
Sent by Cursor Approval Agent: Archgate CLI Approver
# archgate ## [0.46.0](v0.45.7...v0.46.0) (2026-07-02) ### ⚠ BREAKING CHANGES * **session-context:** per-editor list/show subcommands; remove --skip and its false premise (#446) ### Features * **session-context:** per-editor list/show subcommands; remove --skip and its false premise ([#446](#446)) ([dd96230](dd96230)) ### Bug Fixes * **ci:** read POSTHOG_PROJECT_ID from secrets, not vars, in release annotation ([#443](#443)) ([a53b305](a53b305)) * detect opencode Desktop app installs, not just the CLI ([#439](#439)) ([ed92b2b](ed92b2b)) * **hooks:** force bash shell for WorktreeCreate hook on Windows ([#442](#442)) ([9da86cf](9da86cf)) * **release:** cap breaking-change bumps to minor while pre-1.0 ([#447](#447)) ([3df6c91](3df6c91)), closes [#446](#446) [#440](#440) [#440](#440) [#440](#440) * repair broken WorktreeCreate hook and add PR approval policy ([#441](#441)) ([de5e97d](de5e97d)) * **session-context:** select top-level opencode sessions, add --root flag ([#445](#445)) ([29b13f4](29b13f4)) --- This PR was generated with [simple-release](https://github.com/TrigenSoftware/simple-release). <details> <summary>📄 Cheatsheet</summary> <br> You can configure the bot's behavior through a pull request comment using the `!simple-release/set-options` command. ### Command Format ````md !simple-release/set-options ```json { "bump": {}, "publish": {} } ``` ```` ### Useful Parameters #### Bump | Parameter | Type | Description | |-----------|------|-------------| | `version` | `string` | Force set specific version | | `as` | `'major' \| 'minor' \| 'patch' \| 'prerelease'` | Release type | | `prerelease` | `string` | Pre-release identifier (e.g., "alpha", "beta") | | `firstRelease` | `boolean` | Whether this is the first release | | `skip` | `boolean` | Skip version bump | | `byProject` | `Record<string, object>` | Per-project bump options for monorepos | #### Publish | Parameter | Type | Description | |-----------|------|-------------| | `skip` | `boolean` | Skip publishing | | `access` | `'public' \| 'restricted'` | Package access level | | `tag` | `string` | Tag for npm publication | ### Usage Examples #### Force specific version ````md !simple-release/set-options ```json { "bump": { "version": "2.0.0" } } ``` ```` #### Force major bump ````md !simple-release/set-options ```json { "bump": { "as": "major" } } ``` ```` #### Create alpha pre-release ````md !simple-release/set-options ```json { "bump": { "prerelease": "alpha" } } ``` ```` #### Publish with specific access and tag ````md !simple-release/set-options ```json { "bump": { "prerelease": "beta" }, "publish": { "access": "public", "tag": "beta" } } ``` ```` ### Access Restrictions The command can only be used by users with permissions: - repository owner - organization member - collaborator ### Notes - The last comment with `!simple-release/set-options` command takes priority - JSON must be valid, otherwise the command will be ignored - Parameters apply only to the current release execution - The command can be updated by editing the comment or adding a new one </details> <!-- Please do not edit this comment. simple-release-pull-request: true simple-release-branch-from: release simple-release-branch-to: main --> Signed-off-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>



Summary
"shell": "bash"to thehooks.WorktreeCreatecommand in.claude/settings.jsonso the hook is always executed via Git Bash, never the platform-default shell.CLAUDE.md("Claude Code Harness Config" section) and in the persistentproject_worktree_create_hook_contract.mdagent memory (Round 5 of this hook's history).Why
On at least one Windows machine, the
WorktreeCreatehook — which is pure POSIX shell ($(...),[ -z ... ],&&,;) — was silently executed viacmd.exeinstead of Git Bash, even though Git Bash is installed and the interactiveBashtool on the same machine correctly detects and uses it. The failure surfaced as:That exact phrasing is cmd.exe's own stderr text (distinct from PowerShell's wording), and cmd.exe tokenizes on
=, which is why it complained about barename. Root cause, confirmed by extracting source strings from the shippedclaude.exebinary: the hooks runner and the interactiveBashtool have independent Windows-shell detection paths in the CLI, and only one of them resolved Git Bash correctly here when no"shell"field was set on the hook.Test plan
claude.exe(confirmed a documentedshellfield on command hooks, and theCLAUDE_CODE_GIT_BASH_PATH/ hardcoded-path /PATH-derived Git Bash resolution order).EnterWorktree({name: "hook-shell-fix-test"})created a real worktree (.gitfile,package.json, correctgit worktree list/ branch registration), then cleaned up viaExitWorktree({action: "remove", discard_changes: true})+git branch -D.bun run format(config/markdown only change; no source code touched, sobun run validate/ ADR checks are not applicable to this change per the repo's own follow-up-tweak vs. initial-implementation distinction — this is a harness config + doc fix, not application code).