Stop hooks need host-level aggregation across plugins
What happened?
When multiple plugins register Stop hooks, Codex does not appear to expose a clear host-level aggregation contract for their results.
In a real setup I had at least two independent plugin Stop hooks enabled:
- a review gate hook that can block finalization when changes are requested
- a task/acceptance hook that can block finalization when required task closeout is incomplete
The failure mode I am trying to avoid is: one Stop hook requests continuation, but another independent Stop blocker is not preserved or presented in the same effective continuation decision. Individual plugins should not have to know about each other to coordinate this.
Expected behavior
The Codex hook runner / plugin manager should treat plugin Stop hooks as leaf policies and aggregate them generically:
- run all registered
Stophooks for the event - preserve hook identity/source for attribution
- return a single aggregate block if any child hook blocks
- include all blocking reasons in deterministic order
- keep advisory/system messages on their non-blocking channel unless a separate model-visible advisory channel is explicitly defined
- distinguish policy blocks from execution failures such as invalid JSON, nonzero exit, and timeout
- respect each child hook's declared timeout
- propagate recursion signals such as
stop_hook_active - provide enough diagnostics to answer which hooks ran and what each decided
Why this should be host-level
This should not be fixed by hardcoding one plugin to know about another plugin. Plugins should remain independent leaf policies. The host/plugin-manager Stop execution layer is the only layer that can correctly own ordering, aggregation, timeout handling, failure handling, and diagnostics across all registered hooks.
Environment / evidence
- Codex CLI:
codex-cli 0.144.1 - Platform: macOS arm64
- Plugin manifests declare Stop hooks independently
- Installed hook state expands to per-plugin Stop hook entries such as:
review-loop@review-loop:hooks/codex-hooks.json:stop:0:0kernel@agent-kernel-local:hooks/hooks.json:stop:0:0
I have not captured a minimal two-hook runtime trace yet, so I am not claiming a specific internal short-circuit implementation. The actionable request is to define and enforce the aggregation contract for multiple independent Stop hooks so blockers cannot be hidden or dropped by ordering/runner behavior.
Related but not the same: #27052 asks for better hook diagnostics. This issue is specifically about multi-Stop-hook aggregation semantics.