SessionStart hook does not fire when bare `codex` auto-restores the previous thread (0.130.0)
Summary
On Codex CLI 0.130.0, bare codex launch in a terminal where a residual Codex process is present (for example after closing the TUI without quitting, or relaunching from the same shell) auto-restores the previous thread and does not emit any of the documented SessionStart source values (startup, resume, clear, compact). As a result, configured SessionStart hooks never fire on this "soft restart" path.
Environment
- Codex CLI:
codex-cli 0.130.0(Homebrew formula;@openai/codex@0.130.0npm package) - OS: macOS 15.x (Darwin 25.3.0)
- Shell: zsh
- Codex hooks docs: https://developers.openai.com/codex/hooks
Reproduction
- Configure a SessionStart hook in
~/.codex/hooks.json:
{
"hooks": {
"SessionStart": [
{
"matcher": "startup|resume|clear",
"hooks": [
{
"type": "command",
"command": "$HOME/path/to/hook.sh",
"timeout": 60,
"statusMessage": "running"
}
]
}
]
}
}
Have the hook print a unique marker to stderr or emit a systemMessage so its firing is observable.
- Trust the hook via
/hooksin the Codex TUI.
- Launch
codexonce. The hook fires (cold start). A new rollout file appears under~/.codex/sessions/<date>/.
- Without fully quitting the prior session (close terminal window, or leave the TUI in the background, or relaunch from the same shell), launch
codexagain. The hook does NOT fire. NostatusMessageappears.
- Confirm a residual Codex process is present:
pgrep -f "@openai/codex"
Inspect ~/.codex/log/codex-tui.log: the new TUI continues using the previous thread_id without emitting any new SessionStart event.
Workaround
Fully kill all Codex processes before launching:
pkill -f "@openai/codex"
sleep 1
pgrep -f "@openai/codex" && echo "still running" || codex
After a true cold start, the SessionStart hook fires and the configured additionalContext and systemMessage surface as expected. A shell wrapper that wraps codex to perform this kill-before-launch automatically restores the contract.
Expected behaviour
Bare codex launch that picks up the previous thread should emit one of the documented source values (most naturally resume) so a SessionStart matcher fires the hook. The current behaviour is a fourth, implicit "soft restart" path that bypasses the documented contract.
Why this matters
For installations that use SessionStart hooks to render a startup dashboard, enforce a posture gate, or load context, the soft-restart path silently bypasses those guarantees. The hook contract documented at https://developers.openai.com/codex/hooks lists startup|resume|clear|compact; auto-restore on bare launch does not match any of them.
Suggested fix
Have Codex emit source: "resume" when bare launch restores a previous thread, so the existing matcher pattern fires the hook. Alternatively, document the soft-restart path as an intentional bypass so users can configure a complementary mechanism.
Investigation reference
Full investigation (sources, evidence, ruled-out hypotheses, durable workaround) is documented internally at Experience-Innovation/00_exi-foundation/docs/governance/codex-0130-soft-restart-hook-gap-2026-05-23.md (private repo). Key findings:
- Hook script integrity verified: direct invocation produces correct JSON output.
- Trust state verified: re-trusting in
/hooksdid not change the symptom. - Cold-start test verified: after a clean kill of all Codex processes, the hook fires correctly on next launch.
- The same Codex installation correctly renders
systemMessage(TUI warning) andhookSpecificOutput.additionalContext(developer message) when the hook fires; only the firing itself is missing on soft restart.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗