Skip to content

fix: prevent codex exec stdin deadlock with </dev/null redirect#972

Open
loning wants to merge 1 commit intogarrytan:mainfrom
loning:fix/codex-exec-stdin-deadlock
Open

fix: prevent codex exec stdin deadlock with </dev/null redirect#972
loning wants to merge 1 commit intogarrytan:mainfrom
loning:fix/codex-exec-stdin-deadlock

Conversation

@loning
Copy link
Copy Markdown

@loning loning commented Apr 11, 2026

Summary

Why

`codex exec --help` (0.120.0):

[PROMPT]
Initial instructions for the agent. If not provided as an argument (or if - is used), instructions are read from stdin. If stdin is piped and a prompt is also provided, stdin is appended as a <stdin> block.

When skill bash blocks invoke `codex exec "$PROMPT" ...`, the parent shell's stdin is inherited. In Claude Code's Bash tool (and any background or non-TTY context), stdin is not a TTY but also not closed. Codex sees this as "stdin is piped, append it as `` block" and blocks waiting for an EOF that never comes. The positional `$PROMPT` arg is silently followed by an indefinite stdin wait.

Symptom: stderr shows `Reading additional input from stdin...`, process sits at 0% CPU, stdout empty. Skill workflow times out or hangs.

For users running gstack from a real interactive terminal, stdin is a TTY and codex 0.120.0 takes the fast path. The bug only surfaces in non-TTY contexts, which is why nobody caught it earlier in interactive testing.

Repro (against current main, codex CLI 0.120.0)

```bash
codex --version

codex-cli 0.120.0

Hangs forever (no stdin redirect):

codex exec "say hi" -s read-only > out 2> err &
sleep 10
cat err

Reading additional input from stdin...

ps -o pcpu -p $!

0.0

Works:

codex exec "say hi" -s read-only < /dev/null > out 2> err
echo $?

0

```

I hit this today running `/plan-eng-review` on a Voice Avatar design doc — first invocation sat at 0% CPU for 13 minutes, no stdout. After adding `< /dev/null` the same prompt completed in 2:25.

Fix scope (minimal, line-level only)

Source-of-truth files (the only files I hand-edited):

File Invocations fixed
`scripts/resolvers/review.ts` 4 (office-hours, ship/review adversarial, codex review fallback, plan review)
`scripts/resolvers/design.ts` 3 (design-review-lite, design-consultation sketch, plan-design-review)
`codex/SKILL.md.tmpl` 5 (review modes + resume)
`autoplan/SKILL.md.tmpl` 4 (CEO/design/eng/devex phases)

Regenerated SKILL.md (via `bun run gen:skill-docs --host all`):
`autoplan`, `codex`, `design-consultation`, `design-review`, `office-hours`, `plan-ceo-review`, `plan-design-review`, `plan-devex-review`, `plan-eng-review`, `review`, `ship`.

Diff is symmetric: 38 insertions / 38 deletions, every change is just `+ < /dev/null ` inserted right before the existing stderr redirect (or at end-of-line for autoplan markdown blocks that had no redirect).

What I deliberately did NOT change

  • `--enable web_search_cached` is left untouched. I observed that flag also seems suspicious in 0.120.0 (the first hang I hit in my repro included it, and removing it didn't stop the deadlock — only `< /dev/null` did). But since the verified bug is the stdin one, I kept this PR scoped to that single fix. If you want, a follow-up can audit web_search_cached behavior in current codex CLI versions.
  • The Cursor mirror skills under `.cursor/skills/` were not regenerated (gen:skill-docs --host all does not appear to touch them, and they were already not in sync with the .tmpl files in the upstream main branch).

Verification

```bash
bun run skill:check

✅ All Claude Code generated files are fresh

✅ All OpenAI Codex CLI generated files are fresh

✅ All Factory Droid generated files are fresh

✅ All Kiro / OpenCode / Slate / Cursor / OpenClaw generated files are fresh

Total: 36 skills, 0 missing

```

End-to-end verified by re-running `/plan-eng-review` against my own design doc with the patched skills — Codex returned a clean plan review in ~2.5 minutes, full output as expected.

Test plan

  • `bun run skill:check` passes (freshness for all 8 hosts)
  • Manual `codex exec ... < /dev/null` repro returns 0
  • End-to-end `/plan-eng-review` outside voice completes
  • CI green
  • Maintainer reviews diff symmetry (38/38)

🤖 Generated with Claude Code

codex CLI 0.120.0+ blocks indefinitely when stdin is a non-TTY pipe
(Claude Code Bash tool, background bash, CI). The CLI sees a non-TTY
stdin and waits for EOF to append it as a `<stdin>` block, even when
the prompt is passed as a positional argument. Symptom: `Reading
additional input from stdin...` in stderr, 0% CPU, no output.

Fix: add `< /dev/null` to every `codex exec` and `codex review`
invocation in the source-of-truth files (scripts/resolvers/*.ts and
*.md.tmpl), then regenerate via `bun run gen:skill-docs --host all`.

The prompt is passed as the positional arg, so no real stdin input is
needed. This is the minimal fix for the deadlock. Web search flag
behavior is left untouched.

Affected source files:
- scripts/resolvers/review.ts (4 invocations: office-hours, ship/review
  adversarial, codex review fallback, plan review)
- scripts/resolvers/design.ts (3 invocations: design-review-lite,
  design-consultation sketch, plan-design-review)
- codex/SKILL.md.tmpl (5 invocations: review modes + resume)
- autoplan/SKILL.md.tmpl (4 invocations: CEO/design/eng/devex phases)

Regenerated SKILL.md files: autoplan, codex, design-consultation,
design-review, office-hours, plan-ceo-review, plan-design-review,
plan-devex-review, plan-eng-review, review, ship.

Verified: `bun run skill:check` passes; freshness checks green for all
hosts (Claude Code, Codex CLI, Factory Droid, Kiro, OpenCode, Slate,
Cursor, OpenClaw).

Fixes garrytan#971

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.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.

codex exec hangs in skill bash blocks: missing </dev/null causes 'Reading additional input from stdin' deadlock (codex CLI 0.120.0+)

1 participant