Skip to content

fix(hooks): force bash shell for WorktreeCreate hook on Windows#442

Merged
rhuanbarreto merged 1 commit into
mainfrom
fix/worktree-hook-windows-shell
Jul 1, 2026
Merged

fix(hooks): force bash shell for WorktreeCreate hook on Windows#442
rhuanbarreto merged 1 commit into
mainfrom
fix/worktree-hook-windows-shell

Conversation

@rhuanbarreto

Copy link
Copy Markdown
Contributor

Summary

  • Adds "shell": "bash" to the hooks.WorktreeCreate command in .claude/settings.json so the hook is always executed via Git Bash, never the platform-default shell.
  • Documents the gotcha in CLAUDE.md ("Claude Code Harness Config" section) and in the persistent project_worktree_create_hook_contract.md agent memory (Round 5 of this hook's history).

Why

On at least one Windows machine, the WorktreeCreate hook — which is pure POSIX shell ($(...), [ -z ... ], &&, ;) — was silently executed via cmd.exe instead of Git Bash, even though Git Bash is installed and the interactive Bash tool on the same machine correctly detects and uses it. The failure surfaced as:

WorktreeCreate hook failed: name=$(jq -r '.name // empty' | tr -d '\r'); ...: 'name' is not recognized as an internal or external command, operable program or batch file.

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 bare name. Root cause, confirmed by extracting source strings from the shipped claude.exe binary: the hooks runner and the interactive Bash tool 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

  • Reproduced the failure mode via static/binary analysis of the installed claude.exe (confirmed a documented shell field on command hooks, and the CLAUDE_CODE_GIT_BASH_PATH / hardcoded-path / PATH-derived Git Bash resolution order).
  • Applied the fix locally and verified end-to-end by actually triggering the hook: EnterWorktree({name: "hook-shell-fix-test"}) created a real worktree (.git file, package.json, correct git worktree list / branch registration), then cleaned up via ExitWorktree({action: "remove", discard_changes: true}) + git branch -D.
  • bun run format (config/markdown only change; no source code touched, so bun 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).

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>
@cloudflare-workers-and-pages

Copy link
Copy Markdown

Deploying archgate-cli with  Cloudflare Pages  Cloudflare Pages

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

View logs

@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: e2fb499c-71df-4e78-98ac-928c2a28f2e7

📥 Commits

Reviewing files that changed from the base of the PR and between de5e97d and 0028cd4.

📒 Files selected for processing (3)
  • .claude/agent-memory/archgate-developer/project_worktree_create_hook_contract.md
  • .claude/settings.json
  • CLAUDE.md
📜 Recent review details
⏰ Context from checks skipped due to timeout. (3)
  • GitHub Check: Cursor Approval Agent: Archgate CLI Approver
  • GitHub Check: Smoke Test (Windows) / Windows
  • GitHub Check: Cloudflare Pages
⚠️ CI failures not shown inline (4)

GitHub Actions: DCO / 0_DCO Sign-off Check.txt: fix(hooks): force bash shell for WorktreeCreate hook on Windows

Conclusion: failure

View job details

##[group]Run base="de5e97dcbd3b0f3d0d4e3a5b36ec0feb7bcd395c"
 �[36;1mbase="de5e97dcbd3b0f3d0d4e3a5b36ec0feb7bcd395c"�[0m
 �[36;1mhead="0028cd440aa1d6d134a8fa6fcfefa70431eec1e7"�[0m
 �[36;1mfailed=0�[0m
 �[36;1m�[0m
 �[36;1mfor sha in $(git rev-list --no-merges "$base".."$head"); do�[0m
 �[36;1m  if ! git log -1 --format='%B' "$sha" | grep -qiE '^Signed-off-by: .+ <.+>'; then�[0m
 �[36;1m    echo "::error::Commit $sha is missing a DCO Signed-off-by line."�[0m

GitHub Actions: DCO / DCO Sign-off Check: fix(hooks): force bash shell for WorktreeCreate hook on Windows

Conclusion: failure

View job details

##[group]Run base="de5e97dcbd3b0f3d0d4e3a5b36ec0feb7bcd395c"
 �[36;1mbase="de5e97dcbd3b0f3d0d4e3a5b36ec0feb7bcd395c"�[0m
 �[36;1mhead="0028cd440aa1d6d134a8fa6fcfefa70431eec1e7"�[0m
 �[36;1mfailed=0�[0m
 �[36;1m�[0m
 �[36;1mfor sha in $(git rev-list --no-merges "$base".."$head"); do�[0m
 �[36;1m  if ! git log -1 --format='%B' "$sha" | grep -qiE '^Signed-off-by: .+ <.+>'; then�[0m
 �[36;1m    echo "::error::Commit $sha is missing a DCO Signed-off-by line."�[0m

GitHub Actions: Code Quality: PR #442 / Analyze (go): Code Quality: PR #442

Conclusion: failure

View job details

,"bundleSupportsIncludeLogs":true,"bundleSupportsOverlay":true,"databaseInterpretResultsSupportsSarifRunProperty":true,"featuresInVersionResult":true,"indirectTracingSupportsStaticBinaries":false,"informsAboutUnsupportedPathFilters":true,"supportsPython312":true,"mrvaPackCreate":true,"threatModelOption":true,"traceCommandUseBuildMode":true,"v2ramSizing":true,"mrvaPackCreateMultipleQueries":true,"setsCodeqlRunnerEnvVar":true,"sarifMergeRunsFromEqualCategory":true,"forceOverwrite":true,"generateSummarySymbolMap":true,"pythonDefaultIsToNotExtractStdlib":true,"queryServerRunQueries":true,"queryServerTrimCacheWithMode":true,"builtinExtractorsSpecifyDefaultQueries":true,"bqrsDiffResultSets":true,"bundleSupportsIncludeOption":true,"suppressesMissingFileBaselineWarning":true}}}
   CODEQL_ACTION_GO_BINARY: /home/runner/work/_temp/codeql-action-go-tracing/bin/go
   CODEQL_RAM: 14575
   CODEQL_THREADS: 4
   CODEQL_PROXY_HOST:
   CODEQL_PROXY_PORT:
   CODEQL_PROXY_CA_CERTIFICATE:
   CODEQL_PROXY_URLS:
 ##[endgroup]
 ##[group]Attempting to automatically build go code
 [command]/opt/hostedtoolcache/CodeQL/2.25.6/x64/codeql/codeql database trace-command --use-build-mode --working-dir /home/runner/work/cli/cli /home/runner/work/_temp/codeql_databases/go
 Picked up JAVA_TOOL_OPTIONS:  -Dhttp.keepAlive=false -Dmaven.wagon.http.pool=false
 Running command in /home/runner/work/cli/cli: [/opt/hostedtoolcache/CodeQL/2.25.6/x64/codeql/go/tools/autobuild.sh]
 [] [build-stderr] 2026/07/01 15:20:45 Autobuilder was built with go1.26.0, environment has go1.24.13
 [] [build-stderr] 2026/07/01 15:20:45 LGTM_SRC is /home/runner/work/cli/cli
 [] [build-stderr] 2026/07/01 15:20:45 Found no go.work files in the workspace; looking for go.mod files...
 [] [build-stderr] 2026/07/01 15:20:45 Found 1 go.mod files in: shims/go/go.mod.
 [] [build-stderr] 2026/07/01 15:20:45 Found 1 go.mod file(s).
 [] [build-stderr] 2026/07/01 15:20:45 Import path is 'github.com/archgate/cli'
 [] [build-stderr] 2026/07/...

GitHub Actions: Code Quality: PR #442 / 0_Analyze (go).txt: Code Quality: PR #442

Conclusion: failure

View job details

20:53 Extracting types for package crypto/aes.
 [] [build-stderr] 2026/07/01 15:20:53 Done extracting types for package crypto/aes.
 [] [build-stderr] 2026/07/01 15:20:53 Processing package crypto/des.
 [] [build-stderr] 2026/07/01 15:20:53 Extracting types for package crypto/des.
 [] [build-stderr] 2026/07/01 15:20:53 Done extracting types for package crypto/des.
 [] [build-stderr] 2026/07/01 15:20:53 Processing package crypto/internal/fips140/nistec/fiat.
 [] [build-stderr] 2026/07/01 15:20:53 Extracting types for package crypto/internal/fips140/nistec/fiat.
 [] [build-stderr] 2026/07/01 15:20:53 Done extracting types for package crypto/internal/fips140/nistec/fiat.
 [] [build-stderr] 2026/07/01 15:20:53 Processing package crypto/internal/fips140/nistec.
 [] [build-stderr] 2026/07/01 15:20:53 Extracting types for package crypto/internal/fips140/nistec.
 [] [build-stderr] 2026/07/01 15:20:53 Done extracting types for package crypto/internal/fips140/nistec.
 [] [build-stderr] 2026/07/01 15:20:53 Processing package crypto/internal/fips140/ecdh.
 [] [build-stderr] 2026/07/01 15:20:53 Extracting types for package crypto/internal/fips140/ecdh.
 [] [build-stderr] 2026/07/01 15:20:53 Done extracting types for package crypto/internal/fips140/ecdh.
 [] [build-stderr] 2026/07/01 15:20:53 Processing package crypto/internal/fips140/edwards25519/field.
 [] [build-stderr] 2026/07/01 15:20:53 Extracting types for package crypto/internal/fips140/edwards25519/field.
 [] [build-stderr] 2026/07/01 15:20:53 Done extracting types for package crypto/internal/fips140/edwards25519/field.
 [] [build-stderr] 2026/07/01 15:20:53 Processing package crypto/ecdh.
 [] [build-stderr] 2026/07/01 15:20:53 Extracting types for package crypto/ecdh.
 [] [build-stderr] 2026/07/01 15:20:53 Done extracting types for package crypto/ecdh.
 [] [build-stderr] 2026/07/01 15:20:53 Processing package crypto/elliptic.
 [] [build-stderr] 2026/07/01 15:20:53 Extracting types for package crypto/elliptic.
 [] [bu...
🧰 Additional context used
📓 Path-based instructions (2)
**

⚙️ CodeRabbit configuration file

**: # CLAUDE.md

Archgate is a CLI tool for AI governance via Architecture Decision Records (ADRs) — combining human-readable docs with machine-checkable rules. The CLI dogfoods itself via ADRs in .archgate/adrs/. AI features are delivered as a Claude Code plugin (../plugins/claude-code), not via direct API calls.

Technology Stack

  • Runtime: Bun (>=1.2.21) — not Node.js compatible
  • Language: TypeScript (strict mode, ESNext, ES modules)
  • CLI framework: Commander.js (@commander-js/extra-typings)
  • Linter: Oxlint | Formatter: Oxfmt | Dead exports: Knip | Commits: Conventional Commits

Commands

bun run src/cli.ts <command>  # run CLI locally
bun run lint                  # oxlint
bun run typecheck             # tsc --build
bun run format                # oxfmt --write
bun run format:check          # oxfmt --check
bun run test                  # all tests (not bare `bun test` — picks up --timeout; see GEN-003)
bun run knip                  # dead export detection
bun run validate              # MANDATORY: lint + typecheck + format + test + ADR check + knip + build check
bun run build:check            # verify build compiles (CI builds binaries via release workflow)
bun run commit                # conventional commit wizard

Validation Gate

bun run validate must pass before any task is considered complete. Fail-fast pipeline: lint → typecheck → format → test → ADR check → knip → build check. Mirrors CI in .github/workflows/code-pull-request.yml.

Git Hooks (Git 2.54+)

Config-based hooks in .githooks run validation locally before commits and pushes:

  • pre-commit: lint + typecheck + format:check (~15s)
  • pre-push: full bun run validate (~60s, mirrors CI)

Activate once per clone:

git config --local include.path ../.githooks

Opt out of a specific hook: git config --local hook.<name>.enabled false. Skip all hooks for a single commit: git commit --no-verify.

Claude Cod...

Files:

  • CLAUDE.md

⚙️ CodeRabbit configuration file

**: This project uses Archgate — an AI governance framework based on
Architecture Decision Records (ADRs). The ADRs in .archgate/adrs/
are the authoritative rules for this codebase. Each ADR has a companion
.rules.ts file with automated checks that run via archgate check.

When reviewing, you must:

  1. Treat ADR violations as blocking issues, not suggestions.
  2. Cite the specific ADR ID when flagging a violation (e.g., "Violates ARCH-006").
  3. Focus on semantic and contextual violations that automated rules cannot catch —
    the .rules.ts files already cover syntactic/structural patterns.
  4. If you are unsure whether something violates an ADR, flag it as a question
    rather than approving it.

Files:

  • CLAUDE.md
.claude/settings.json

📄 CodeRabbit inference engine (CLAUDE.md)

.claude/settings.json: For command-type hooks that use POSIX shell syntax, set hooks.WorktreeCreate` must create the worktree itself, redirect setup-command output to stderr, and print only the resulting absolute path on its final stdout line.

Files:

  • .claude/settings.json
🧠 Learnings (2)
📓 Common learnings
Learnt from: CR
Repo: archgate/cli

Timestamp: 2026-07-01T15:21:47.251Z
Learning: When adding a new editor target, update all required editor-detection, init, plugin-install, URL, and test call sites together so detection, initialization, installation, and tests stay in sync.
📚 Learning: 2026-06-11T12:50:28.661Z
Learnt from: rhuanbarreto
Repo: archgate/cli PR: 406
File: .claude/agent-memory/archgate-developer/feedback_prefer_tests_over_adr_rules.md:8-18
Timestamp: 2026-06-11T12:50:28.661Z
Learning: In `archgate/cli`, for markdown files under `.claude/agent-memory/`, follow the established convention: use YAML frontmatter (with a `name:` field used as the document title) and do not require a top-level `#` (H1) heading. During code review, do not flag missing first-line/first-top-level H1 headings (e.g., MD041) for these agent-memory files since markdownlint is not part of the repo’s `bun run validate` lint pipeline (oxlint/oxfmt only).

Applied to files:

  • .claude/agent-memory/archgate-developer/project_worktree_create_hook_contract.md
🔇 Additional comments (3)
.claude/settings.json (1)

45-45: LGTM!

CLAUDE.md (1)

50-51: LGTM!

.claude/agent-memory/archgate-developer/project_worktree_create_hook_contract.md (1)

30-35: LGTM!


📝 Walkthrough

Walkthrough

This change adds an explicit "shell": "bash" field to the WorktreeCreate command hook in .claude/settings.json to prevent the hook from falling back to cmd.exe on Windows, which caused shell syntax errors. Corresponding documentation updates were made in CLAUDE.md describing the requirement and failure mode for command-type hooks, and in the agent-memory contract file recording the incident, root cause, fix, and verification steps.

Changes

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@rhuanbarreto

Copy link
Copy Markdown
Contributor Author

@cursor approve

@cursor

cursor Bot commented Jul 1, 2026

Copy link
Copy Markdown

Approved.

Evaluated PR #442 against APPROVAL_POLICY.md:

Signal Status
Cursor Bugbot success — no issues; no review comment required per policy
Lint, Test & Check Pass
Smoke Test (Linux + Windows) Pass
CodeQL, DCO, Cloudflare Pages Pass
Scope Focused harness-config fix — no application code changes

Change review: The one-line "shell": "bash" addition in .claude/settings.json is the correct fix for the Windows cmd.exe tokenization failure on POSIX shell syntax. Documentation in CLAUDE.md and the agent memory Round 5 entry accurately capture the root cause and verification steps.

Verdict: Approve. Ready to merge once remaining non-blocking checks (Coverage Report, CodeRabbit) finish.

Note: This environment’s GitHub token cannot submit a formal APPROVE review or PR comment via the API (Resource not accessible by integration), so the approval is recorded here. @rhuanbarreto’s @cursor approve request is satisfied on substance.

Open in Web Open in Cursor 

@github-actions

github-actions Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Code Coverage

Metric Value
Lines 90.0% (6936 / 7709)
Threshold 90% minimum — met
Platforms Linux + Windows

Full HTML report available in workflow artifacts.

Per-directory breakdown
Directory Coverage Lines
src/commands/ 88.1% 1874 / 2128
src/engine/ 90.9% 1463 / 1610
src/formats/ 100.0% 142 / 142
src/helpers/ 90.3% 3457 / 3829

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Open in Web View Automation 

Sent by Cursor Approval Agent: Archgate CLI Approver

@rhuanbarreto rhuanbarreto merged commit 9da86cf into main Jul 1, 2026
21 checks passed
@rhuanbarreto rhuanbarreto deleted the fix/worktree-hook-windows-shell branch July 1, 2026 15:26
@archgatebot archgatebot Bot mentioned this pull request Jul 1, 2026
rhuanbarreto pushed a commit that referenced this pull request Jul 3, 2026
# 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>
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.

1 participant