Trust cmux's own Codex hooks so Codex stops asking to review them
Summary
Starting codex in a cmux-tui terminal (every Cloud VM, and cmux-tui on a Mac) showed "Hooks need review: 11 hooks are new or changed". /hooks listed each event as Installed 2, Active 1, Review 1. Only the untrusted copy carries the terminal route, so it's the one the shared app-server needs, and it didn't run until the user clicked Trust. After this change, Codex trusts every hook cmux writes or injects, and starts without asking.
Cause. The cmux-tui codex wrapper adds a per-launch copy of each hook through -c, and the ssh-tmux helper (Resources/bin/cmux-tmux-agent.py) does the same. Both passed that copy's trust as -c hooks.state."/<session-flags>/config.toml:stop:0:0".trusted_hash=.... They also passed enabled=false for the persistent hooks.json copies. Codex splits a -c key on every ., even inside TOML quotes (codex-rs/config/src/overrides.rs apply_toml_override). Every one of these keys contains a dot (config.toml, hooks.json), so none of those settings ever applied. As a result, the persistent copy stayed enabled and trusted while the per-launch copy was untrusted. Both now pass the whole state as one inline table, -c hooks.state={"<key>"={trusted_hash="..."}, ...}. Codex merges that table with the trust already in config.toml, and user trust is untouched.
Two smaller ways the persistent producers could leave a cmux hook untrusted are fixed too:
- cmux-tui reordered a shared
hooks.jsonon reinstall. A reinstall removed cmux-tui's group and appended a new one at the end. When the cmux app's hooks came after it, they shifted up one group, away from their trusted key. cmux-tui's new trust entry then overwrote the app's key. cmux-tui now puts its group back in the slot it came from, as the app CLI already does. - The cmux CLI resolved symlinks in the trust key. It keyed trust by the fully resolved
hooks.jsonpath. Codex resolves an explicitCODEX_HOMEbut uses$HOME/.codexverbatim, so a symlinked home left every app hook untrusted. The CLI now builds the key the same way Codex does, and it still cleans up old resolved-path entries that carry cmux's own hashes.
Both producers stay installed. The app's hooks only act inside cmux app terminals, and cmux-tui's only inside cmux-tui terminals or tmux. Neither trusts a hook it didn't write. The Cloud boot rewrite of ~/.codex/config.toml (agent-config.sh) already copies the existing file, including [hooks.state], so it needs no change.
The first commit is a one-line rustfmt fix to session_journal.rs that's already on main. Without it, hosted cmux-tui verification stops at cargo fmt before any test runs.
Testing
Tests were committed red before the fix:
cmux-tui/crates/cmux-tui/tests/codex_wrapper.rs: the-cparser now applies overrides the way Codex does (split on every., last segment replaces).codex_wrapper_scopes_trust_and_suppresses_only_installed_cmux_hooksthen requires the session-flag trust andenabled=falseentries to land at their real keys.agent_hook_install.rscodex_reinstall_keeps_a_later_producers_hook_and_trust_in_place: installs cmux-tui, adds an app-style Stop hook after it with its trust entry, reinstalls cmux-tui, and asserts both hooks keep their positions and trust.scripts/tests/test_remote_tmux_agent_helper.py: requires a singlehooks.stateoverride containing every session-flag key.cmuxTests/CLIGenericHookPersistenceTests.swifttestCodexHookTrustKeysUseTheDefaultCodexHomeVerbatim: installs through a symlinked$HOMEand expects the unresolved key.
Results:
- Hosted cmux-tui
--filter codex_: test commit run 38524404119 (expected red) and fix run 38524560666 are still running;cargo fmtpasses on both. Results will be added here. python3 -m unittest test_remote_tmux_agent_helper: red before, 10/10 after.python3 scripts/verify-local.py: 17/17.- The Swift test runs in the app CI on this PR; I didn't build the app locally.
Checked against the real Codex 0.162.1 release (codex app-server โ hooks/list, temp CODEX_HOME):
- cmux-tui's persistent install plus the old wrapper flags reproduced the report: 11 hooks.json copies trusted and enabled, 11
/<session-flags>copiesuntrusted. - The same layout with the inline
hooks.statevalue: hooks.json copies trusted and disabled, session-flag copies trusted and enabled. A user hook's trust fromconfig.tomlwas unchanged. - The fixed tmux helper's actual argv: all 7 session-flag hooks
trusted, no warnings. $HOME/.codexthrough a symlink is keyed by the unresolved path.
Changelog
Fixed: Codex no longer asks to review cmux's own hooks when it starts in a cmux-tui terminal or a Cloud machine
Proof
No UI change; the hooks/list results above are the behavior check.
Checklist
- Behavior changes have added or updated tests, or Testing says why not
- Reviewed with a subagent before merge (cmux-review), and all bot and human review comments resolved
๐ค Generated with Claude Code
Need help on this PR? Tag @codesmith-bot with what you need.
Summary by cubic
Stops Codex from asking to review cmux's own hooks when it starts in a cmux-tui terminal or a Cloud VM.
- The
-ctrust overrides Codex splits on every dot, even inside quotes, so the per-launch hook copies were left untrusted; trust andenabled=falsenow go in a singlehooks.stateinline table, which Codex merges with the persistent trust. - cmux-tui reinstalls now reinsert its hook group in its original slot in a shared
hooks.json, keeping hooks another producer added later on their trusted keys. - The cmux CLI now keys trust by
$HOME/.codexverbatim instead of the resolved path, fixing symlinked homes; user trust inconfig.tomlis untouched. - Includes a one-line rustfmt fix to
session_journal.rsthat was blocking hosted verification.
Summary by CodeRabbit
- Bug Fixes
- Improved Codex hook trust handling, including when configuration paths use environment overrides or symlinked home directories.
- Reinstalling cmux hooks now better preserves the placement of hooks added by other tools and retains their trust settings.
- Codex sessions now consistently apply hook trust settings when launched.