Skip to content

fix(agents): make the codex timeout wrapper zsh-safe - #19

Closed
anderson-spider wants to merge 1 commit into
DannyMac180:mainfrom
anderson-spider:fix/zsh-safe-timeout-wrapper
Closed

fix(agents): make the codex timeout wrapper zsh-safe#19
anderson-spider wants to merge 1 commit into
DannyMac180:mainfrom
anderson-spider:fix/zsh-safe-timeout-wrapper

Conversation

@anderson-spider

Copy link
Copy Markdown

The bug

Both implementer lanes told the agent to invoke codex as:

T=$(command -v gtimeout || command -v timeout || true)
${T:+$T 600} codex exec \

${T:+$T 600} relies on bash word-splitting an unquoted parameter expansion. zsh does not split by default, and Claude Code's Bash tool runs zsh on macOS, so the prefix reaches execve as one argv word and the run dies before codex starts:

(eval):1: no such file or directory: /opt/homebrew/bin/gtimeout 600

Every invocation of codex-implementer and sol-implementer failed on such machines. Because the failure surfaces as a missing binary, it is easy to misread as a codex install/auth problem. Same root cause as #12 and #17.

The fix

  • Build the timeout prefix as positional parameters: if [ -n "$T" ]; then set -- "$T" 600; else set --; fi then "$@" codex exec. "$@" expands to zero words when nothing is set — in bash, zsh and sh — so the uncapped fallback needs no special-casing.
  • Probe by running each candidate ("$c" 1 true) instead of trusting command -v, which still returns a hit for a stale hash-cache entry or a dangling symlink.
  • Same family, two lines down: ${EFFORT:+-c model_reasoning_effort=$EFFORT} is also a single word under zsh. Split into ${EFFORT:+-c} ${EFFORT:+model_reasoning_effort=$EFFORT} so each expansion yields exactly one argv word or vanishes. On codex-cli 0.153.0 the override still applied because codex trims the key, so this is hardening against an undocumented behaviour, not a live effort-misrouting bug.
  • Flag-discipline table rows updated to match. Applied identically to both lanes (600s / 1800s).

Docs-only; no behavioural change on bash.

Verification

Extracted the new snippet into a script and ran it on macOS (coreutils gtimeout installed):

Shell Result
zsh picks gtimeout, two clean argv words, exit 0
bash same
sh same
zsh, PATH=/usr/bin:/bin (no timeout binary) warns once, runs uncapped, exit 0
exit-status propagation through the prefix (exit 127) 127 preserved
${EFFORT:+-c} ${EFFORT:+…} under zsh argc=2 with EFFORT set, argc=0 with EFFORT empty

claude plugin validate . passes.

`${T:+$T 600}` relies on bash word-splitting; under zsh (Claude Code's
shell on macOS) it reaches execve as one argv word and every lane run
dies with "no such file or directory". Build the prefix as positional
parameters and probe the timeout binary by running it. Split the EFFORT
override the same way so each expansion is exactly one argv word.
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 3, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-03T17:35:43.721729Z 04c5b52 PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@anderson-spider anderson-spider closed this by deleting the head repository Sep 9, 2026
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