Plugin hooks fail on npm CLI: %PLUGIN_ROOT% not expanded in commandWindows

Open 💬 0 comments Opened Jul 22, 2026 by tydandou

What version of Codex CLI is running?

codex-cli 0.145.0

What subscription do you have?

Plus

Which model were you using?

gpt-5.6-terra medium

What platform is your computer?

Windows 10.0.26100 (Windows 11 Professional) [64-bit] x86_64

What terminal emulator and version are you using (if applicable)?

Windows Terminal (PowerShell) PSVersion: 7.6.0

Codex doctor report

{
    "schemaVersion": 1,
    "generatedAt": "1784701369s since unix epoch",
    "overallStatus": "ok",
    "codexVersion": "0.145.0",
    "checks": {
      "app_server.status": {
        "id": "app_server.status",
        "category": "app-server",
        "status": "ok",
        "summary": "background server is not running",
        "details": {
          "control socket": "C:\\Users\\<user>\\.codex\\app-server-control\\app-server-control.sock",
          "daemon state dir": "C:\\Users\\<user>\\.codex\\app-server-daemon",
          "mode": "ephemeral",
          "pid file": "C:\\Users\\<user>\\.codex\\app-server-daemon\\app-server.pid (missing)",
          "settings": "C:\\Users\\<user>\\.codex\\app-server-daemon\\settings.json (missing)",
          "status": "not running",
          "update-loop pid file": "C:\\Users\\<user>\\.codex\\app-server-daemon\\app-server-updater.pid (missing)"
        },
        "remediation": null,
        "durationMs": 0
      },
      "auth.credentials": {
        "id": "auth.credentials",
        "category": "auth",
        "status": "ok",
        "summary": "auth is configured",
        "details": {
          "auth file": "C:\\Users\\<user>\\.codex\\auth.json",
          "auth storage mode": "File",
          "stored API key": "false",
          "stored ChatGPT tokens": "true",
          "stored agent identity": "false",
          "stored auth mode": "chatgpt"
        },
        "remediation": null,
        "durationMs": 0
      },
      "config.load": {
        "id": "config.load",
        "category": "config",
        "status": "ok",
        "summary": "config loaded",
        "details": {
          "CODEX_HOME": "C:\\Users\\<user>\\.codex",
          "config.toml": "C:\\Users\\<user>\\.codex\\config.toml",
          "config.toml parse": "ok",
          "cwd": "D:\\AIWorks\\tracebook",
          "enabled feature flags": "<redacted>",
          "feature flag overrides": "none",
          "feature flags enabled": "36",
          "log dir": "C:\\Users\\<user>\\.codex\\log",
          "mcp servers": "2",
          "model": "gpt-5.6-terra",
          "model provider": "openai",
          "sqlite home": "C:\\Users\\<user>\\.codex"
        },
        "remediation": null,
        "durationMs": 0
      },
      "git.environment": {
        "id": "git.environment",
        "category": "git",
        "status": "ok",
        "summary": "git version 2.52.0.windows.1",
        "details": {
          ".git entry": "directory",
          "PATH git #1": "D:\\App\\Git\\cmd\\git.exe",
          "PATH git entries": "1",
          "git branch": "master",
          "git build options": "git version 2.52.0.windows.1",
          "git exec path": "D:/App/Git/mingw64/libexec/git-core",
          "git version": "git version 2.52.0.windows.1",
          "repo detected": "true",
          "repo root": "D:\\AIWorks\\tracebook",
          "selected git": "D:\\App\\Git\\cmd\\git.exe"
        },
        "remediation": null,
        "durationMs": 573
      },
      "installation": {
        "id": "installation",
        "category": "install",
        "status": "ok",
        "summary": "installation looks consistent",
        "details": {
          "PATH codex #1": "C:\\Users\\<user>\\AppData\\Roaming\\npm\\codex",
          "PATH codex #2": "C:\\Users\\<user>\\AppData\\Roaming\\npm\\codex.cmd",
          "PATH codex entries": "2",
          "current executable": "C:\\Users\\<user>\\AppData\\Roaming\\npm\\node_modules\\@openai\\codex\\node_modules\\@openai\\
  codex-win32-x64\\vendor\\x86_64-pc-windows-msvc\\bin\\codex.exe",
          "install context": "npm",
          "managed by bun": "false",
          "managed by npm": "true",
          "managed by pnpm": "false",
          "managed package root": "C:\\Users\\<user>\\AppData\\Roaming\\npm\\node_modules\\@openai\\codex",
          "npm update target": "C:\\Users\\<user>\\AppData\\Roaming\\npm\\node_modules\\@openai\\codex"
        },
        "remediation": null,
        "durationMs": 1227
      },
      "mcp.config": {
        "id": "mcp.config",
        "category": "mcp",
        "status": "ok",
        "summary": "MCP configuration is locally consistent",
        "details": {
          "configured servers": "2",
          "disabled servers": "0",
          "stdio servers": "2"
        },
        "remediation": null,
        "durationMs": 9
      },
      "network.env": {
        "id": "network.env",
        "category": "network",
        "status": "ok",
        "summary": "network-related environment looks readable",
        "details": {
          "proxy env vars present": "HTTP_PROXY, HTTPS_PROXY, http_proxy, https_proxy"
        },
        "remediation": null,
        "durationMs": 0
      },
      "network.provider_reachability": {
        "id": "network.provider_reachability",
        "category": "reachability",
        "status": "ok",
        "summary": "active provider endpoints are reachable over HTTP",
        "details": {
          "ChatGPT base URL": "https://chatgpt.com/backend-api/ reachable (HTTP 403)",
          "reachability mode": "ChatGPT auth"
        },
        "remediation": null,
        "durationMs": 375
      },
      "network.websocket_reachability": {
        "id": "network.websocket_reachability",
        "category": "websocket",
        "status": "ok",
        "summary": "Responses WebSocket handshake succeeded",
        "details": {
          "auth mode": "chatgpt",
          "connect timeout": "15000 ms",
          "endpoint": "wss://chatgpt.com/backend-api/<redacted>",
          "handshake result": "HTTP 101 Switching Protocols",
          "model provider": "openai",
          "supports websockets": "true",
          "wire API": "responses"
        },
        "remediation": null,
        "durationMs": 1456
      },
      "runtime.provenance": {
        "id": "runtime.provenance",
        "category": "runtime",
        "status": "ok",
        "summary": "running npm on windows-x86_64",
        "details": {
          "commit": "unknown",
          "current executable": "C:\\Users\\<user>\\AppData\\Roaming\\npm\\node_modules\\@openai\\codex\\node_modules\\@openai\\
  codex-win32-x64\\vendor\\x86_64-pc-windows-msvc\\bin\\codex.exe",
          "install method": "npm",
          "platform": "windows-x86_64",
          "version": "0.145.0"
        },
        "remediation": null,
        "durationMs": 0
      },
      "sandbox.helpers": {
        "id": "sandbox.helpers",
        "category": "sandbox",
        "status": "ok",
        "summary": "sandbox configuration is readable",
        "details": {
          "approval policy": "OnRequest",
          "filesystem sandbox": "restricted",
          "network sandbox": "restricted"
        },
        "remediation": null,
        "durationMs": 0
      },
      "system.environment": {
        "id": "system.environment",
        "category": "system",
        "status": "ok",
        "summary": "OS language zh-CN",
        "details": {
          "os": "Windows 10.0.26100 (Windows 11 Professional) [64-bit]",
          "os language": "zh-CN",
          "os type": "Windows",
          "os version": "10.0.26100"
        },
        "remediation": null,
        "durationMs": 1
      },
      "terminal.env": {
        "id": "terminal.env",
        "category": "terminal",
        "status": "ok",
        "summary": "terminal metadata was detected",
        "details": {
          "WT_SESSION": "present",
          "terminal": "Windows Terminal",
          "terminal size": "120x30"
        },
        "remediation": null,
        "durationMs": 0
      }
    }
  }

What issue are you seeing?

Third-party plugin hooks defined with commandWindows in hooks.json always fail with exit code 1 when run from the
npm-installed CLI (@openai/codex@0.145.0).

The same hooks work perfectly in the Codex Desktop App (0.145.0-alpha.30).

Error displayed in CLI:

• UserPromptSubmit hook (failed)
error: hook exited with code 1
• Stop hook (failed)
error: hook exited with code 1

Root cause: The npm CLI binary does not expand %PLUGIN_ROOT% in the commandWindows field before spawning the process.
PowerShell receives the literal string %PLUGIN_ROOT%\hooks\tracebook_hook.ps1 as a file path, cannot find the file, and exits
with code 1.

I verified this by manually running the command:

```powershell
# With %PLUGIN_ROOT% unexpanded — FAILS (same as npm CLI behavior):
echo '{}' | powershell.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "%PLUGIN_ROOT%\hooks\tracebook_hook.ps1"
# Error: file not found, exit code 1

# With the actual path — WORKS (same as Desktop App behavior):
echo '{"hook_event_name":"UserPromptSubmit","cwd":"D:\\AIWorks\\tracebook"}' | powershell.exe -NoProfile -NonInteractive
-ExecutionPolicy Bypass -File "C:\Users\<user>\.codex\plugins\cache\tracebook\tracebook\2.0.1\hooks\tracebook_hook.ps1"
# exit code 0, outputs correct JSON

Affected plugin: tracebook v2.0.1 — a durable project knowledge plugin that provides lifecycle hooks via hooks.json for both Claude
Code and Codex.

What steps can reproduce the bug?

  1. Install the [tracebook](https://github.com/tydandou/tracebook) plugin (or any plugin with `commandWindows` hooks that reference
  `%PLUGIN_ROOT%`):
     - Add marketplace to `config.toml`:
       ```toml
       [marketplaces.tracebook]
       source_type = "git"
       source = "https://github.com/tydandou/tracebook.git"
       ref = "v2.0.1"
       ```
     - Enable the plugin:
       ```toml
       [plugins."tracebook@tracebook"]
       enabled = true
       ```
  2. Trust the hooks when prompted
  3. Run `codex` from terminal (npm CLI) and submit any prompt
  4. Observe: `UserPromptSubmit hook (failed) error: hook exited with code 1`
  5. End the session — observe: `Stop hook (failed) error: hook exited with code 1`

  **Contrast:** Open the same project in Codex Desktop App → hooks execute successfully.

### What is the expected behavior?

The npm CLI binary should expand `%PLUGIN_ROOT%` (and `$PLUGIN_ROOT` on Unix) in hook command strings to the plugin's cached
  directory before spawning the process, consistent with the Desktop App behavior.

  Expected `%PLUGIN_ROOT%` resolution for this plugin:
  `C:\Users\<user>\.codex\plugins\cache\tracebook\tracebook\2.0.1`

  The hooks.json `commandWindows` field:
  ```json
  "%SystemRoot%\\System32\\WindowsPowerShell\\v1.0\\powershell.exe -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -File
  \"%PLUGIN_ROOT%\\hooks\\tracebook_hook.ps1\""

  Should be expanded at runtime to:
  C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass -File
  "C:\Users\<user>\.codex\plugins\cache\tracebook\tracebook\2.0.1\hooks\tracebook_hook.ps1"

### Additional information

```markdown
  - The Desktop App binary (`~/.codex/plugins/.plugin-appserver/codex.exe`, version 0.145.0-alpha.30) correctly expands
  `%PLUGIN_ROOT%` — the same hooks work there without any issue.
  - The npm CLI binary is at:
  `~\AppData\Roaming\npm\node_modules\@openai\codex\node_modules\@openai\codex-win32-x64\vendor\x86_64-pc-windows-msvc\bin\codex.exe`
  - This likely affects ALL third-party plugins that use `commandWindows` with `%PLUGIN_ROOT%` on the npm CLI.
  - The tracebook plugin ([github.com/tydandou/tracebook](https://github.com/tydandou/tracebook)) is a cross-platform plugin designed
  for both Claude Code and Codex. Its hooks work correctly on Claude Code and Codex Desktop, only failing on the npm CLI
  distribution.
  - `config.toml` shows the hooks are trusted (have `trusted_hash` entries), confirming Codex did parse and register them — the issue
  is purely at execution time.

View original on GitHub ↗