Skip to content

v5.2.0 β€” Codex CLI Compatibility (3rd editor target)

Latest

Choose a tag to compare

@ChanMeng666 ChanMeng666 released this 04 May 11:49
· 8 commits to master since this release

Codex CLI compatibility. OpenAI's Codex CLI now joins Claude Code and Cursor IDE as a first-class editor target. Single AI-first prompt installs everything; the calling AI agent handles every follow-up step that requires a config edit. No human-in-the-loop steps.

πŸ†• For Codex users: paste this single prompt into Codex (or any AI agent that can run shell commands):

"Clone https://github.com/ChanMeng666/claude-code-audio-hooks into ~/audio-hooks, then run python ~/audio-hooks/bin/audio-hooks install --codex. Read the JSON output: if feature_flag_state is section_missing or flag_missing_or_false, follow the next_steps instruction (use your Edit tool to add [features]\ncodex_hooks = true to ~/.codex/config.toml). Then restart Codex."

What's new

audio-hooks install --codex / uninstall --codex

  • Writes $CODEX_HOME/hooks.json (default ~/.codex/hooks.json) registering the 6 events Codex supports per developers.openai.com/codex/hooks: SessionStart, PreToolUse, PostToolUse, PermissionRequest, UserPromptSubmit, Stop. The other 18 audio-hooks canonical events have no Codex equivalent and the runner no-ops them with a skipped_no_codex_equivalent debug NDJSON event.
  • Tags every entry with _managed_by: "audio-hooks" so re-installs are idempotent and uninstall preserves user-authored hooks. Never touches ~/.codex/config.toml on uninstall β€” the codex_hooks flag may benefit other Codex hook plugins.
  • Codex does NOT auto-bridge Claude Code plugins (unlike Cursor). Confirmed by independent investigation of openai/codex. Consequence: no DUPLICATE_BRIDGE problem to solve.

AI-first feature-flag handling

Codex hooks require [features]\ncodex_hooks = true in ~/.codex/config.toml. The install:

State Action
File doesn't exist Authors a fresh config.toml with the flag enabled (feature_flag_state: "freshly_written")
Flag already true Skips silently (feature_flag_state: "already_enabled")
Flag missing or false Emits a machine-readable next_steps JSON instruction so the calling AI agent can add the flag with its Edit tool

We never round-trip user-authored TOML β€” formatting and comments would be destroyed. The AI agent handles targeted edits with its Edit tool while the install handles the safe cases.

--invoker codex CLI flag

Codex sets no env var we could detect by (unlike Cursor's CURSOR_VERSION). The install template bakes --invoker codex into every command:

{ "command": "python \"/abs/path/to/hook_runner.py\" stop --invoker codex" }

New hooks/invoker.py module extracted from hook_runner.py so user_preferences.py can ask "which IDE invoked us?" without a circular import. detect_invoker() checks argv first, then env vars, then falls back to unknown. The cache is primed before argv stripping so downstream callers see the right answer.

editor_targets.codex block in audio-hooks status / manifest

Reports state (active / active-but-flag-disabled / active-but-flag-unknown / inactive), hooks_file, config_path, feature_flag_enabled, data_dir. Surfaces a CODEX_FEATURE_FLAG_MISSING warning when the install is in place but the flag isn't enabled β€” actionable for the calling AI agent.

codex: {...} sub-object in webhook payloads

When invoker == "codex", the raw payload includes a codex sub-object with turn_id, tool_use_id, permission_mode, tool_response, stop_hook_active (parallel to cursor: {...}). Schema stays at audio-hooks.webhook.v1 β€” additive, no breaking changes.

Codex-gated step in _resolve_data_dir()

New priority 3 (between env-var overrides and the plugin-cache layout): when detect_invoker() == "codex" AND $CODEX_HOME/audio-hooks-data/user_preferences.json exists, return that path. Sits ahead of the Claude Code shared dir so a developer machine that happens to have both Claude Code and Codex installed still lands at the right dir under Codex sessions.

Tests + CI

33 new bridge-contract tests in tests/test_codex_hooks.py across 8 TestCase classes:

  • Invoker detection from argv (4 cases including the --invoker=codex form and invalid-value fallback)
  • strip_invoker_args correctness
  • _resolve_data_dir Codex fallback (positive + negative gating)
  • Template validity (all 6 events, every command carries --invoker codex, every canonical handler is known)
  • Unsupported-events no-op (all 18)
  • NDJSON invoker field, webhook codex sub-object
  • Install end-to-end (writes hooks.json, substitutes paths, seeds user_preferences, writes install_marker, idempotent, preserves foreign entries)
  • Feature-flag handling (4 states)
  • Uninstall (removes managed, preserves foreign, preserves data dir by default, --purge, never touches config.toml)
  • editor_targets.codex end-to-end

135/135 tests pass on Windows.

Out of scope for 5.2.0

  • Project-scope install (<repo>/.codex/hooks.json). User-scope only is the v1 design. Users wanting per-repo audio config can hand-edit <repo>/.codex/hooks.json themselves.
  • Codex plugin packaging (~/.codex/plugins/audio-hooks/). Codex has its own plugin system but we haven't packaged audio-hooks for it; the hooks.json install is sufficient for v1.
  • Auto-editing existing ~/.codex/config.toml. Too risky for user-authored TOML β€” TOML round-trip with comment preservation is hard and getting it wrong destroys user formatting. The next_steps AI-readable instruction is the right contract for v1.

Files changed

24 files: 19 modified + 5 new. +2505 / -81. New files: codex-hooks/hooks.json, hooks/invoker.py, tests/test_codex_hooks.py, plus plugin-layout copies. See CHANGELOG.md for the full entry.