openai / openai/codex-plugin-cc
Stop-review gate: review timeout equals the hook's own 900s timeout, so a slow review ends the turn with no message
Nobody has claimed this yet.
- Dominant language
- JavaScript
- Stars
- 33.3k
- Forks
- 2.3k
- PR merge metrics
- No merged PRs in 30d
Description
We use the Codex plugin from Claude Code on a number of machines, and an automated audit of our
hooks flagged the Stop hook for how long it can hold a turn open. Reading
stop-review-gate-hook.mjs, the review's internal timeout and the hook's own declared timeout are
the same number, which I think makes the "review timed out" path unreachable. We don't have the gate
enabled anywhere, so this is from reading the code, not from hitting it. Setup: plugin v1.0.6
(byte-identical to main today), macOS, Node 26.7.0, ChatGPT auth.
What happens
plugins/codex/hooks/hooks.json gives the Stop hook "timeout": 900, and the hook spawns the
review with a timeout of the same 900 seconds:
// plugins/codex/hooks/hooks.json
"command": "node \"${CLAUDE_PLUGIN_ROOT}/scripts/stop-review-gate-hook.mjs\"",
"timeout": 900
// plugins/codex/scripts/stop-review-gate-hook.mjs
const STOP_REVIEW_TIMEOUT_MS = 15 * 60 * 1000;
...
const result = spawnSync(process.execPath, [scriptPath, "task", "--json", prompt], {
cwd, env: childEnv, encoding: "utf8", timeout: STOP_REVIEW_TIMEOUT_MS
});
if (result.error?.code === "ETIMEDOUT") {
return {
ok: false,
reason:
"The stop-time Codex review task timed out after 15 minutes. Run /codex:review --wait manually or bypass the gate."
};
}
The hook starts first and spawns the child a few milliseconds later, so the child's deadline is
always the later of the two, and Claude Code kills the hook while the child is still inside its own
window. The hook's only write to stdout happens after spawnSync returns, so at that point it has
emitted nothing at all. A review that genuinely runs long therefore leaves the user with a turn that
appears to hang for fifteen minutes and then ends with no reason given, instead of the
"run /codex:review --wait manually or bypass the gate" note the code is trying to deliver. The
branch itself is correct — spawnSync does set error.code === "ETIMEDOUT" on Node 26 — it just
doesn't look reachable.
What we ruled out
Not our configuration: stopReviewGate is false in every workspace here, so nothing we set touches
this path. Not a stale copy: the shipped stop-review-gate-hook.mjs is byte-identical to main, and
main's hooks.json still declares 900. I searched open and closed issues for "stop review gate",
"hook timeout", "ETIMEDOUT", "900" and "15 minutes"; #248 and #530 sit next to this one but neither
is about the two timeouts being equal, so I opened it separately rather than commenting there.
Reproduction
I haven't sat through a real 900s review, and by inspection it's only these two constants. To see it
quickly, set STOP_REVIEW_TIMEOUT_MS and the hooks.json timeout to the same small value, enable
the gate, and make the review hang.
One guess, and I may be reading this wrong: if the hook is meant to report its own timeout, the inner
deadline needs headroom under the outer one. Which number should move is your call, so I haven't sent
a PR picking one. Happy to test a patch.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Compare the timeout in plugins/codex/hooks/hooks.json with STOP_REVIEW_TIMEOUT_MS and the spawnSync call in plugins/codex/scripts/stop-review-gate-hook.mjs. Reproduce the condition with matching short timeouts and a hanging review. Done means the hook's timeout outcome is observable and the documented manual-review or bypass message is emitted.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- javascript
- Domain
- cli, tooling
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 78/100