fix(hooks): ship hooks.codex.json so Codex session start gets a JSON envelope - #158
Open
STiFLeR7 wants to merge 1 commit into
Open
fix(hooks): ship hooks.codex.json so Codex session start gets a JSON envelope#158STiFLeR7 wants to merge 1 commit into
STiFLeR7 wants to merge 1 commit into
Conversation
…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
Owner
|
I was not able to reproduce this issue. Official documentation (https://learn.chatgpt.com/docs/hooks#sessionstart) says plain-text output is accepted. |
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. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.