E5: feed every Codex prompt on stdin instead of argv

Prompts went to Codex as one argv string ('codex exec "$(cat file)"'), which
fails over 32 KB on Windows (and over 128 KB on Linux, E2BIG) and mangles
quotes. Every codex exec site (outside-voice resolver, /codex review custom
instructions, challenge, consult new and resume) now runs 'codex exec -'
with the prepared prompt file on stdin; challenge and consult write the
prompt with a quoted heredoc so it is never shell-parsed. The bash-native
timeout watchdog (stock macOS) started the command in the background, which
gives it /dev/null as stdin; it now passes the caller's stdin through.

The 'byte for byte' dispatch test drops its old argv trailing-LF exception,
the consultation and autoplan fixtures follow the stdin form, and the static
site test requires stdin at every rendered codex exec.
This commit is contained in:
garrytan committed 2026-10-03 21:11:38 +00:00
1 parent ebab87bb11
commit e2f9e144c0
11 files changed
+77 -22

No files matched your search

+8 -2
View File
@@ -18,6 +18,7 @@ With focus (e.g., "security"):
Review the changes on this branch against the base branch. Run `git diff origin/<base>` to see the diff. Focus specifically on SECURITY. Your job is to find every way an attacker could exploit this code. Think about injection vectors, auth bypasses, privilege escalation, data exposure, and timing attacks. Be adversarial."
2. Run codex exec with **JSONL output** to capture reasoning traces and tool calls.
Replace `<prompt>` with the full prompt from step 1, verbatim and unescaped; Codex reads it on stdin.
Use `timeout: 600000` on the Bash call (the tool's maximum) — the gate sits ABOVE the
540s wrapper so the wrapper fires first, ends Codex, and prints its explicit stall message:
@@ -36,7 +37,12 @@ fi
TMPRESP=$(mktemp "$TMP_ROOT/codex-resp-XXXXXX") || { echo "ERROR: mktemp failed in TMP_ROOT=$TMP_ROOT; not running codex without its temp file" >&2; exit 1; }
source ~/.claude/skills/gstack/bin/gstack-codex-probe || exit 1
_gstack_codex_select_model exec || exit 1
_gstack_codex_timeout_wrapper 540 codex exec "<prompt>" -C "$_REPO_ROOT" -s "${_GSTACK_CODEX_SANDBOX:?}" {{CODEX_MODEL_CONFIG_FLAG}} -c 'model_reasoning_effort="high"' {{CODEX_WEB_SEARCH_FLAG}} --json -o "$TMPRESP" < /dev/null 2>"$TMPERR" | tee "$TMPRESP.events" | PYTHONUNBUFFERED=1 "$PYTHON_CMD" -u -c "
_PROMPT_FILE=$(mktemp "$TMP_ROOT/codex-prompt-XXXXXX") || { echo "ERROR: mktemp failed in TMP_ROOT=$TMP_ROOT; not running codex without its temp file" >&2; exit 1; }
# The prompt goes to Codex on stdin (codex exec -), verbatim: no shell quoting, no argv size limit.
cat > "$_PROMPT_FILE" <<'CODEX_PROMPT_END'
<prompt>
CODEX_PROMPT_END
_gstack_codex_timeout_wrapper 540 codex exec - -C "$_REPO_ROOT" -s "${_GSTACK_CODEX_SANDBOX:?}" {{CODEX_MODEL_CONFIG_FLAG}} -c 'model_reasoning_effort="high"' {{CODEX_WEB_SEARCH_FLAG}} --json -o "$TMPRESP" < "$_PROMPT_FILE" 2>"$TMPERR" | tee "$TMPRESP.events" | PYTHONUNBUFFERED=1 "$PYTHON_CMD" -u -c "
import sys, json
turn_completed_count = 0
turn_failed = False
@@ -94,7 +100,7 @@ if grep -qiE "auth|login|unauthorized" "$TMPERR" 2>/dev/null; then
_gstack_codex_log_event "codex_auth_failed"
fi
bun ~/.claude/skills/gstack/lib/outside-review-result.ts --label 'Codex challenge' --exit "$_CODEX_EXIT" --stderr "$TMPERR" --events "$TMPRESP.events" execution "$TMPRESP"
rm -f "$TMPRESP" "$TMPRESP.events"
rm -f "$TMPRESP" "$TMPRESP.events" "$_PROMPT_FILE"
```
`VERDICT: unavailable` means the challenge did not run (its line names why, such as a
+16 -3
View File
@@ -60,7 +60,8 @@ For non-plan consult prompts (user typed `/codex <question>`), still prepend the
<user's question>"
4. Run codex exec with **JSONL output** to capture reasoning traces. Use
4. Run codex exec with **JSONL output** to capture reasoning traces. Replace `<prompt>`
with the full prompt, verbatim and unescaped; Codex reads it on stdin. Use
`timeout: 600000` on the Bash call (the tool's maximum; for both new and resumed
sessions) — the gate sits ABOVE the 540s wrapper so the wrapper fires first, ends Codex,
and prints its explicit stall message:
@@ -78,7 +79,12 @@ fi
source ~/.claude/skills/gstack/bin/gstack-codex-probe || exit 1
_gstack_codex_select_model exec || exit 1
# Fix 1: wrap with timeout (gtimeout/timeout fallback chain via probe helper)
_gstack_codex_timeout_wrapper 540 codex exec "<prompt>" -C "$_REPO_ROOT" -s "${_GSTACK_CODEX_SANDBOX:?}" {{CODEX_MODEL_CONFIG_FLAG}} -c 'model_reasoning_effort="medium"' {{CODEX_WEB_SEARCH_FLAG}} --json -o "$TMPRESP" < /dev/null 2>"$TMPERR" | tee "$TMPRESP.events" | PYTHONUNBUFFERED=1 "$PYTHON_CMD" -u -c "
_PROMPT_FILE=$(mktemp "$TMP_ROOT/codex-prompt-XXXXXX") || { echo "ERROR: mktemp failed in TMP_ROOT=$TMP_ROOT; not running codex without its temp file" >&2; exit 1; }
# The prompt goes to Codex on stdin (codex exec -), verbatim: no shell quoting, no argv size limit.
cat > "$_PROMPT_FILE" <<'CODEX_PROMPT_END'
<prompt>
CODEX_PROMPT_END
_gstack_codex_timeout_wrapper 540 codex exec - -C "$_REPO_ROOT" -s "${_GSTACK_CODEX_SANDBOX:?}" {{CODEX_MODEL_CONFIG_FLAG}} -c 'model_reasoning_effort="medium"' {{CODEX_WEB_SEARCH_FLAG}} --json -o "$TMPRESP" < "$_PROMPT_FILE" 2>"$TMPERR" | tee "$TMPRESP.events" | PYTHONUNBUFFERED=1 "$PYTHON_CMD" -u -c "
import sys, json
turn_completed_count = 0
turn_failed = False
@@ -134,6 +140,7 @@ elif [ "$_CODEX_EXIT" != "0" ]; then
_gstack_codex_log_event "codex_nonzero_exit" "consult:$_CODEX_EXIT"
fi
bun ~/.claude/skills/gstack/lib/outside-review-result.ts --label 'Codex consult' --exit "$_CODEX_EXIT" --stderr "$TMPERR" --events "$TMPRESP.events" execution "$TMPRESP"
rm -f "$_PROMPT_FILE"
```
**Session-cost reality (#2387, measured):** every `codex exec` call — resumed
@@ -156,7 +163,12 @@ cd "$_REPO_ROOT" || exit 1
source ~/.claude/skills/gstack/bin/gstack-codex-probe || exit 1
_gstack_codex_select_model exec || exit 1
# Fix 1: wrap with timeout (gtimeout/timeout fallback chain via probe helper)
_gstack_codex_timeout_wrapper 540 codex exec resume <session-id> "<prompt>" -c "sandbox_mode=\"${_GSTACK_CODEX_SANDBOX:?}\"" {{CODEX_MODEL_CONFIG_FLAG}} -c 'model_reasoning_effort="medium"' {{CODEX_WEB_SEARCH_FLAG}} --json -o "$TMPRESP" < /dev/null 2>"$TMPERR" | tee "$TMPRESP.events" | PYTHONUNBUFFERED=1 "$PYTHON_CMD" -u -c "
_PROMPT_FILE=$(mktemp "$TMP_ROOT/codex-prompt-XXXXXX") || { echo "ERROR: mktemp failed in TMP_ROOT=$TMP_ROOT; not running codex without its temp file" >&2; exit 1; }
# The prompt goes to Codex on stdin (codex exec -), verbatim: no shell quoting, no argv size limit.
cat > "$_PROMPT_FILE" <<'CODEX_PROMPT_END'
<prompt>
CODEX_PROMPT_END
_gstack_codex_timeout_wrapper 540 codex exec resume <session-id> - -c "sandbox_mode=\"${_GSTACK_CODEX_SANDBOX:?}\"" {{CODEX_MODEL_CONFIG_FLAG}} -c 'model_reasoning_effort="medium"' {{CODEX_WEB_SEARCH_FLAG}} --json -o "$TMPRESP" < "$_PROMPT_FILE" 2>"$TMPERR" | tee "$TMPRESP.events" | PYTHONUNBUFFERED=1 "$PYTHON_CMD" -u -c "
<same python streaming parser as above, with flush=True on all print() calls>
"
# Fix 1: same hang detection pattern as new-session block
@@ -173,6 +185,7 @@ elif [ "$_CODEX_EXIT" != "0" ]; then
_gstack_codex_log_event "codex_nonzero_exit" "consult-resume:$_CODEX_EXIT"
fi
bun ~/.claude/skills/gstack/lib/outside-review-result.ts --label 'Codex consult' --exit "$_CODEX_EXIT" --stderr "$TMPERR" --events "$TMPRESP.events" execution "$TMPRESP"
rm -f "$_PROMPT_FILE"
```
`VERDICT: unavailable` from either block means Codex did not answer from a working
+1 -1
View File
@@ -96,7 +96,7 @@ _PROMPT_FILE=$(mktemp "$TMP_ROOT/codex-prompt-XXXXXX") || { echo "ERROR: mktemp
git diff "<base>...HEAD" 2>/dev/null
printf '\nDIFF_END\n'
} > "$_PROMPT_FILE"
_gstack_codex_timeout_wrapper 330 codex exec -s "${_GSTACK_CODEX_SANDBOX:?}" "$(cat "$_PROMPT_FILE")" {{CODEX_MODEL_CONFIG_FLAG}} -c 'model_reasoning_effort="high"' {{CODEX_WEB_SEARCH_FLAG}} --json -o "$TMPOUT" < /dev/null >"$TMPOUT.events" 2>"$TMPERR"
_gstack_codex_timeout_wrapper 330 codex exec - -s "${_GSTACK_CODEX_SANDBOX:?}" {{CODEX_MODEL_CONFIG_FLAG}} -c 'model_reasoning_effort="high"' {{CODEX_WEB_SEARCH_FLAG}} --json -o "$TMPOUT" < "$_PROMPT_FILE" >"$TMPOUT.events" 2>"$TMPERR"
_CODEX_EXIT=$?
rm -f "$_PROMPT_FILE"
cat "$TMPOUT"