Skip to content

fix(codex): surface hook blocks and empty turns instead of silent idle - #81

Merged
qiankunli merged 2 commits into
mainfrom
fix/surface-hook-blocks-and-empty-turns
Jul 13, 2026
Merged

fix(codex): surface hook blocks and empty turns instead of silent idle#81
qiankunli merged 2 commits into
mainfrom
fix/surface-hook-blocks-and-empty-turns

Conversation

@qiankunli

@qiankunli qiankunli commented Jul 13, 2026

Copy link
Copy Markdown
Collaborator

codex core silently ends a turn when a UserPromptSubmit/SessionStart hook
blocks the prompt: turn/completed reports status=completed with no items,
no error event, and the prompt never enters the native thread history.
baton dropped hook/* notifications and treated the zero-output completion
as a normal end_turn, so the user saw their message swallowed
(incident bs_01KXCNW0WVA11NZH2F8FKTCJ5E, misread as "codex stuck").

  • handle hook/completed: blocked/stopped userPromptSubmit/sessionStart
    hooks emit a warning _baton_notice with source path and block reason,
    and stash the reason on the active turn
  • finishTurn: a completed driven turn with zero visible output emits an
    empty-turn warning notice, attributed to the hook block when known;
    interrupted turns and pure-compaction turns are exempt
  • wire shapes verified against a live codex 0.144.1 app-server session
    (inject_items + turn/start repro also disproved the earlier theory that
    cross-provider context injection caused the empty turns)

Documents the normalization semantics introduced by the empty-turn fix:
codex hook/completed notifications (blocked/stopped userPromptSubmit or
sessionStart — the paths that make codex end a turn silently with the
prompt never entering native history) and zero-output completed turns
normalize to a warning _baton_notice; lifecycle is unchanged, terminal
state still flows through state_update. Claude has no wire counterpart
(in-process SDK hook failures surface on the error stream).

codex core silently ends a turn when a UserPromptSubmit/SessionStart hook
blocks the prompt: turn/completed reports status=completed with no items,
no error event, and the prompt never enters the native thread history.
baton dropped hook/* notifications and treated the zero-output completion
as a normal end_turn, so the user saw their message swallowed
(incident bs_01KXCNW0WVA11NZH2F8FKTCJ5E, misread as "codex stuck").

- handle hook/completed: blocked/stopped userPromptSubmit/sessionStart
  hooks emit a warning _baton_notice with source path and block reason,
  and stash the reason on the active turn
- finishTurn: a completed driven turn with zero visible output emits an
  empty-turn warning notice, attributed to the hook block when known;
  interrupted turns and pure-compaction turns are exempt
- wire shapes verified against a live codex 0.144.1 app-server session
  (inject_items + turn/start repro also disproved the earlier theory that
  cross-provider context injection caused the empty turns)
Documents the normalization semantics introduced by the empty-turn fix:
codex hook/completed notifications (blocked/stopped userPromptSubmit or
sessionStart — the paths that make codex end a turn silently with the
prompt never entering native history) and zero-output completed turns
normalize to a warning _baton_notice; lifecycle is unchanged, terminal
state still flows through state_update. Claude has no wire counterpart
(in-process SDK hook failures surface on the error stream).
@qiankunli
qiankunli merged commit c6f2567 into main Jul 13, 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.

2 participants