openai / openai/codex

Windows: all Claude-marketplace plugin hooks fail — hook bash resolves to the WSL shim; async hook protocol unsupported; failures report only 'Failed' with no diagnostics

Open
#38,295 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug CLI exec hooks windows-os
Dominant language
Rust
Stars
125k
Forks
19.5k
PR merge metrics
PR metrics pending

Description

Environment

  • Codex CLI 0.144.1, 0.146.0, 0.147.0 (identical behavior on all three), npm install
  • Windows 11 Pro 10.0.26200
  • Plugins from the claude-plugins-official marketplace: security-guidance 2.0.7, superpowers 6.3.0, ralph-loop 1.0.0
  • WSL installed (Ubuntu default distro), Git for Windows installed

Summary

On Windows, every hook declared by Claude-marketplace plugins reports Failed on every fresh codex exec run — all four phases (SessionStart, UserPromptSubmit, PostToolUse, Stop). The root cause is that Codex resolves the hook interpreter bash via PATH. On a default Windows setup, PATH bash is the WindowsApps WSL shim (%LOCALAPPDATA%\Microsoft\WindowsApps\bash.exe), and WSL bash cannot execute Windows-style script paths:

$ bash "C:\Users\<user>\.codex\plugins\cache\claude-plugins-official\security-guidance\2.0.7\hooks\sg-python.sh"
/bin/bash: C:UsersAJCam.codexpluginscacheclaude-plugins-officialsecurity-guidance2.0.7hookssg-python.sh: No such file or directory
(exit 127)

Since effectively all Claude-marketplace plugin hooks are bash <script> commands, every hook fails out of the box on Windows. Claude Code runs these same hooks successfully on the same machine because it resolves bash to Git Bash rather than PATH-first.

Workaround / proof: prepending C:\Program Files\Git\bin to PATH (so bash = Git Bash) immediately fixes most phases with unmodified plugin files: UserPromptSubmit Completed, all PostToolUse Completed, security-guidance Stop Completed.

Requests

1. Resolve hook bash like Claude Code does on Windows

PATH-first resolution lands on the WSL shim and breaks every Claude-marketplace hook. Suggested: prefer Git Bash (git --exec-path discovery or the standard install locations) for bash hook commands on Windows, falling back to PATH.

2. Support (or gracefully degrade) the async hook protocol

security-guidance's SessionStart hook (ensure_agent_sdk.py) replies with Claude's async hook protocol:

{"async": true, "asyncTimeout": 180000}

and exits 0. Codex marks the phase Failed. Expected: either honor the async contract or treat a well-formed async reply as success.

3. Hook failures surface as the bare word Failed with no diagnostics
  • The transcript prints only hook: <Phase> Failed.
  • RUST_LOG=trace surfaces exec-policy and websocket telemetry but no hook error reason.
  • The app log DB records hook/started / hook/completed events with no failure detail.
  • Additionally, a hook whose hooks.json hash is not in the trusted set is silently skipped with no output at all, which is indistinguishable from "did not fire" and cost us several rounds of misdiagnosis (an edited hook file gets a new hash and simply vanishes from the run).

Expected: print or log the exit code / stderr / spawn error of a failed hook, and indicate when a hook was skipped as untrusted.

4. Remaining divergence (unresolved)

ralph-loop's Stop hook (stop-hook.sh) exits 0 when run by hand under Git Bash with CLAUDE_PLUGIN_ROOT set and JSON on stdin, yet still reports Failed inside Codex's hook runtime even after the bash fix. Without failure diagnostics (point 3) we could not determine why; likely stdin/env shape divergence from Claude's hook contract.

Reproduction

  1. Windows machine with WSL installed (so PATH bash = WSL shim) and any claude-plugins-official plugin with hooks installed and trusted (e.g. security-guidance).
  2. codex exec any prompt in any workspace.
  3. Observe hook: SessionStart Failed, hook: UserPromptSubmit Failed, hook: PostToolUse Failed (per tool call), hook: Stop Failed.
  4. Prepend Git Bash to PATH and re-run: UserPromptSubmit / PostToolUse / security-guidance Stop complete; SessionStart still fails on the async reply (point 2).

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the failures with codex exec on Windows using a trusted Claude marketplace plugin, first comparing PATH bash resolution with Git Bash. Then trace the hook runtime, hooks.json trust handling, async response processing, and failure logging; done means the reported hook phases behave correctly and failures or skipped hooks include actionable diagnostics.

Written by the indexing model from the issue text.

Assessment

Tech stack
bash, rust
Domain
cli, devtools, operating-systems
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.