Skip to content

[failproofai-473] Fix Codex hooks.json: drop invalid top-level version field#473

Open
NiveditJain wants to merge 1 commit into
mainfrom
luv-473
Open

[failproofai-473] Fix Codex hooks.json: drop invalid top-level version field#473
NiveditJain wants to merge 1 commit into
mainfrom
luv-473

Conversation

@NiveditJain

@NiveditJain NiveditJain commented Jul 3, 2026

Copy link
Copy Markdown
Member

Problem

Installing failproofai hooks for OpenAI Codex wrote a top-level "version": 1 into
~/.codex/hooks.json. Codex CLI v0.142+ then refuses to start any session:

failed to parse hooks config /home/.../.codex/hooks.json: unknown field `version`, expected `hooks` at line 2 column 11

Root cause (confirmed against Codex's Rust source, codex-rs/config/src/hook_config.rs):
the top-level HooksFile struct is #[serde(deny_unknown_fields)] and permits only
hooks (plus an optional description). The version field was an unverified assumption —
Codex never wanted it.

Fix (Codex-only)

  • Stop writing version, and strip any leftover version on the next
    install/uninstall — so a previously-broken hooks.json self-heals on reinstall (not just
    "stop adding it": upgraders already have version: 1 on disk).
  • Correct the timeout unit: Codex reads timeout in seconds (its timeout_sec
    field, default 600), so the old 60000 meant ~16.7h, not 60s. Now 60.
  • Keep the __failproofai_hook__ marker: Codex's internally-tagged
    HookHandlerConfig::Command has no deny_unknown_fields, so the marker is tolerated; it
    stays as the primary install-detection key shared with every other integration.
  • Regenerated the dogfood .codex/hooks.json; corrected stale schema comments and the
    CLAUDE.md Codex section.

Copilot and Cursor legitimately carry version: 1 in their own schemas and are not touched.

Verification

Tested against real Codex CLI v0.142.5:

  • Old config (version: 1) → reproduces the exact parse error above.
  • New config (no version, marker present) → parses cleanly and Codex runs the hooks
    (SessionStart / UserPromptSubmit fire).
  • Config generated by the real writeHookEntries code path → parses cleanly.

Plus: unit 1907 passed, e2e 298 passed, tsc --noEmit clean, eslint 0 errors,
bun run build green, and the Docker clean-install smoke test exits 0.

🤖 Generated with Claude Code

https://claude.ai/code/session_01X6cq77Ku4Zg7Dx6z57hNzr

Summary by CodeRabbit

  • Bug Fixes

    • Corrected Codex hooks setup so configuration files no longer include an invalid top-level version field.
    • Fixed hook timeout values to use 60 seconds, improving compatibility and preventing rejected configurations.
    • Existing installs are now automatically cleaned up if they contain older invalid settings.
  • Documentation

    • Updated setup guidance to reflect the current Codex hook configuration format.
  • Tests

    • Expanded end-to-end and integration coverage for Codex hook configuration and timeout behavior.

…on` field

Codex CLI v0.142+ refuses to start a session when ~/.codex/hooks.json carries
a top-level `version` field. Codex's HooksFile config struct is
#[serde(deny_unknown_fields)] and only permits `hooks` (plus an optional
`description`), so the `version: 1` marker our Codex integration wrote — an
unverified assumption — produced:

  failed to parse hooks config: unknown field `version`, expected `hooks`
  at line 2 column 11

The `codex` integration now writes only `hooks`, and strips any leftover
`version` on the next install/uninstall so a previously-broken config
self-heals. Also correct the hook `timeout` from 60000 to 60: Codex reads
`timeout` in seconds (its `timeout_sec` field, default 600), so the old value
meant ~16.7h instead of 60s. The `__failproofai_hook__` marker is kept — Codex's
internally-tagged HookHandlerConfig::Command tolerates unknown fields, and it is
the primary install-detection key shared with every other integration.

Scope is Codex-only; Copilot and Cursor legitimately carry `version: 1` in their
own schemas. Regenerated the dogfood .codex/hooks.json to match.

Verified against real Codex CLI v0.142.5: the old config reproduces the exact
parse error, the fixed config parses cleanly and runs the hooks, and the marker
is tolerated. Unit (1907), e2e (298), typecheck, lint, build, and Docker
clean-install smoke all green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01X6cq77Ku4Zg7Dx6z57hNzr
@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR fixes Codex hooks.json to remove an invalid top-level version field and corrects timeout values from milliseconds (60000) to seconds (60). Integration code strips legacy version fields for self-healing, with corresponding updates to tests, changelog, and documentation.

Changes

Codex hooks version and timeout fix

Layer / File(s) Summary
Codex hooks.json config update
.codex/hooks.json
Removes top-level version field and changes all hook timeout values from 60000 to 60.
Codex integration logic for version stripping and timeout
src/hooks/integrations.ts, src/hooks/types.ts
CodexSettingsFile no longer models version; readSettings stops injecting it; buildHookEntry uses seconds; writeHookEntries and removeHooksFromFile strip legacy version; comments clarified for Copilot/Cursor schemas.
Test coverage for schema and timeout changes
__tests__/e2e/hooks/codex-integration.e2e.test.ts, __tests__/hooks/integrations.test.ts
Tests assert no top-level version, updated nested hooks shape, timeout: 60, and version-stripping migration behavior.
Changelog and documentation updates
CHANGELOG.md, CLAUDE.md
Adds a 0.0.12-beta.0 changelog entry and expands Codex hook schema documentation.

Estimated code review effort: 2 (Simple) | ~12 minutes

Poem

A hop, a fix, no version in sight,
Sixty seconds, timed just right. ⏱️
Codex hooks now clean and true,
Self-healing configs, good as new.
This rabbit thumps with joy tonight! 🐇

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main Codex hooks.json fix: removing the invalid top-level version field.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Warning

Tools execution failed with the following error:

Failed to run tools: 13 INTERNAL: Received RST_STREAM with code 2 (Internal server error)


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/hooks/integrations.ts (1)

297-300: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Optional: extract shared "strip legacy version" helper.

The delete (s as Record<string, unknown>).version; migration logic is duplicated between writeHookEntries and removeHooksFromFile (the latter also tracks hadVersion). A small shared helper (e.g. stripLegacyVersion(settings)) would reduce duplication.

Also applies to: 325-332

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/hooks/integrations.ts` around lines 297 - 300, The legacy top-level
version stripping logic is duplicated in `writeHookEntries` and
`removeHooksFromFile`, so extract it into a shared helper such as
`stripLegacyVersion(settings)` and use it in both places. Make the helper
operate on the settings object before serialization, preserve `hadVersion`
behavior in `removeHooksFromFile`, and keep the migration behavior identical
while removing the repeated `delete (s as Record<string, unknown>).version;`
logic.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@src/hooks/integrations.ts`:
- Around line 297-300: The legacy top-level version stripping logic is
duplicated in `writeHookEntries` and `removeHooksFromFile`, so extract it into a
shared helper such as `stripLegacyVersion(settings)` and use it in both places.
Make the helper operate on the settings object before serialization, preserve
`hadVersion` behavior in `removeHooksFromFile`, and keep the migration behavior
identical while removing the repeated `delete (s as Record<string,
unknown>).version;` logic.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 4f739712-0b3e-45ce-b709-7cb55333e673

📥 Commits

Reviewing files that changed from the base of the PR and between ab9bdef and afe3eeb.

📒 Files selected for processing (7)
  • .codex/hooks.json
  • CHANGELOG.md
  • CLAUDE.md
  • __tests__/e2e/hooks/codex-integration.e2e.test.ts
  • __tests__/hooks/integrations.test.ts
  • src/hooks/integrations.ts
  • src/hooks/types.ts

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.

1 participant