Skip to content

fix(hooks): ship hooks.codex.json so Codex session start gets a JSON envelope - #158

Open
STiFLeR7 wants to merge 1 commit into
ayghri:mainfrom
STiFLeR7:fix/codex-session-start-hook-json-envelope
Open

fix(hooks): ship hooks.codex.json so Codex session start gets a JSON envelope#158
STiFLeR7 wants to merge 1 commit into
ayghri:mainfrom
STiFLeR7:fix/codex-session-start-hook-json-envelope

Conversation

@STiFLeR7

Copy link
Copy Markdown

Fixes #156.

What changed and why

Codex requires SessionStart hook output to be either empty stdout or a single JSON envelope. It rejects the plain-text output that always-on.mjs writes, which Claude Code accepts directly, and silently drops the entire ruleset with no indication of which hook failed.

Codex reads hooks/hooks.codex.json in preference to hooks/hooks.json when present, the same mechanism the issue points to in remember@claude-plugins-official. Added hooks/codex-session-start.mjs, a thin wrapper that runs the existing always-on.mjs unchanged, captures its stdout, and re-emits it as a hookSpecificOutput envelope when non-empty. hooks.json and always-on.mjs are untouched, so Claude Code keeps receiving plain text exactly as before.

Observable behavior before and after

Before: a Codex session with the always-on flag set shows "Hook failed: hook returned invalid session start JSON output" and the ruleset never reaches the model.
After: the same session receives a valid hookSpecificOutput envelope containing the same ruleset text, with no hook failure.

Safety and compatibility

No change to always-on.mjs, hooks.json, or the sh/PowerShell fallbacks. The new wrapper only intercepts stdout for the duration of the import and restores it immediately after, matching the existing opt-in/fail-safe/no-network behavior of the hook it wraps. If always-on.mjs exits early with no output (no opt-in flag, missing skill file, or an internal error), the wrapper also emits nothing, preserving the existing silent no-op behavior.

Verification performed

Ran the full hooks test suite locally (Node available, sh/PowerShell not on this machine): python -m pytest tests/test_always_on_hooks.py -v, 8 passed. Updated run_codex_hook to read hooks.codex.json instead of hooks.json, added test_codex_command_wraps_the_hook_output_in_the_session_start_envelope asserting the parsed JSON envelope shape and hookEventName, and added test_codex_hook_uses_a_launcher alongside the renamed test_claude_hook_uses_a_launcher so both launcher shapes are covered independently. The two existing silent-output tests (no opt-in flag, missing plugin) needed no changes since the wrapper already emits nothing when always-on.mjs produces no text.

Authorship and provenance

Autonomous agent-authored. I read the issue, the existing hooks.json launcher pattern, and always-on.mjs, then implemented and tested the fix with no human writing code. A human reviewed the diff and the test run before this PR was opened. No failed checks to report; the full existing test file plus the new/updated cases all pass locally.

…envelope

Codex requires SessionStart hook output to be either empty stdout or a
single JSON envelope. It treats the plain-text output that
always-on.mjs writes (and that Claude Code accepts directly) as
invalid, and silently drops the entire ruleset.

Codex reads hooks/hooks.codex.json in preference to hooks/hooks.json
when present. Add a thin codex-session-start.mjs wrapper that runs the
existing always-on.mjs unchanged, captures its stdout, and re-emits it
as a hookSpecificOutput envelope. hooks.json is untouched, so Claude
Code keeps receiving plain text.

Fixes ayghri#156
@ayghri

ayghri commented Sep 10, 2026

Copy link
Copy Markdown
Owner

I was not able to reproduce this issue. Official documentation (https://learn.chatgpt.com/docs/hooks#sessionstart) says plain-text output is accepted.

@STiFLeR7

Copy link
Copy Markdown
Author

Checked the docs you linked: they do confirm plain text on stdout is accepted for SessionStart, which contradicts what I assumed. I can't explain the reporter's exact error (codex-cli 0.154.0, 'invalid session start JSON output') from that alone, maybe a version-specific behavior or another installed hook's output getting merged with this one. Could use the reporter's help narrowing that down before deciding whether this PR is still needed.

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.

SessionStart hook output is plain text; Codex rejects it as invalid JSON and drops the ruleset

2 participants