Repository navigation
feat(hooks): add direct Codex command rewriting - #3552
Conversation
|
Hi @aeppling @KuSh @TaKO8Ki, Codex has been gaining a lot of traction lately, and I think this integration could be really useful for its users. It lets RTK work transparently in Codex, so command output takes up less context without adding an extra model round trip. Whenever you have some bandwidth, I would really appreciate a review. I am happy to respond quickly and keep improving anything that needs work. Thanks! |
|
AFAIK this is already open in #2557, sadly not yet merged. |
Thanks! I checked #2557. There is an important behavioral difference between the two implementations. #2557 intentionally skips rewriting in default and ask modes, and only applies Our PR targets the current Codex hook semantics. The official Codex hooks documentation now explicitly specifies This means RTK can transparently rewrite the command in normal modes while still preserving Codex's native approval and sandbox flow. I also verified this end to end with Codex CLI So while the two PRs overlap in purpose, the behavior is meaningfully different. Happy to consolidate with #2557 if the maintainers prefer. |
|
Thanks! One thought after looking more closely at #2557 and the review discussion: Our PR may be better considered as an alternative implementation rather than necessarily a follow-up. It keeps RTK responsible only for I’m happy to follow whichever direction you prefer, whether that means reviewing Our PR directly or rebasing it on top of #2557 and incorporating the relevant parts. |
|
Replying to #3552 (comment) — On "alternative implementation vs follow-up": I think that framing is fair on the protocol point specifically. I traced Codex's own source ( That said, digging further turned up a real gap in that argument, plus some independent bugs — I'd want these addressed regardless of which PR becomes the reference implementation: 1. 2. Wrapping through 3. Local install has no working uninstall. 4. Two hook-detection parser regressions in On duplication ( Happy to help verify any of the above against a specific approach if useful. |
2d34e13 to
e85985e
Compare
|
Thanks for the detailed review. I rebased onto the latest
I added regression tests for each case. I kept the agent-specific orchestration separate as suggested. I did not include the broader low-level scaffolding extraction in this update, but I am happy to follow up with that if you would prefer it in this PR. Would appreciate another look when you have time. Happy to keep iterating. |
|
Rechecked against the updated branch — the four issues from the previous round are genuinely fixed, verified against source rather than just the diff:
Three minor things left, none of them merge blockers:
Nice work turning the previous round around — this is in good shape. |
e85985e to
cff625a
Compare
|
Thanks for checking this again. I rebased onto the latest
I also added regression coverage for missing and empty JSON files, path-aware parse and read errors, successful backups, backup failures, and preservation of the original file when a backup fails. Local verification is green: formatting, Clippy, 2,634 unit tests with 8 expected ignores, all 78 integration tests, the real Codex install and uninstall flow, and a workflow-equivalent Semgrep scan with zero findings. The new CI run is currently waiting for maintainer approval before GitHub will start any jobs. One unrelated note: the benchmark job on the current Happy to address anything else that comes up after the CI run is approved. |
|
Re-verified
One more pass at high effort surfaced one actionable item, posted inline below. Two other things it turned up are not asks for this PR:
|
KuSh
left a comment
There was a problem hiding this comment.
Requesting one small change (inline below) — the rest of the previous review round is resolved, see the follow-up comment.
cff625a to
e4b74fd
Compare
KuSh
left a comment
There was a problem hiding this comment.
Two real regressions from the read_json_file/backup_and_atomic_write refactor in 53fc1b61 (inline below), plus a handful of non-blocking cleanup notes on where the duplication this PR set out to reduce is still present.
|
Thanks for the detailed follow-up. I pushed
I added regression coverage for the malformed Cursor JSON path, Cursor I/O error propagation, and the Droid multi-candidate failure case. Local verification is green: formatting, Clippy, 2,675 unit tests with 8 expected ignores, all 79 integration tests, a workflow-equivalent Semgrep scan with zero findings, and a real project-scoped Droid install and uninstall round trip. I kept the non-blocking cleanup suggestions out of this change so this round stays focused on the two behavioral regressions. The new CI run is waiting for maintainer approval before GitHub will start the jobs. |
Thanks
Would you mind tackling these points in a follow-up PR? |
|
Command rewriting works, but RTK history remains broken in Codex workspace sandboxes: SQLite cannot open its database directory ( Safe follow-up: during |
e260715 to
293a50f
Compare
|
@patrickstratznig Thanks for reporting this. I pushed
I verified custom paths, TOML escaping, and the real init flow, including that no |
293a50f to
0d7e4fb
Compare
|
@KuSh Pushed Formatting, Clippy, the full test suite (3,568 unit tests passed, 8 ignored, and 155 integration tests passed), and the baseline Semgrep scan pass locally. The cleanup items remain scoped to #4002. Could you approve the workflow run for this head so we can get the CI results? |
Codex and Vibe both return empty rule vectors; keeping them as separate arms multiplies branches that have to stay in sync. Group them, sorted, with one comment covering both. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
KuSh
left a comment
There was a problem hiding this comment.
Round 6 (landing) — APPROVED
Claim: Add a native rtk hook codex PreToolUse processor that rewrites Bash commands to rtk … for Codex CLI, plus rtk init --codex install/uninstall/status tooling.
Scope: accept (frozen).
Ran: full gate on the rebased head — cargo fmt --all --check clean, cargo clippy --all-targets zero warnings, cargo test --all green (3,568 unit + all integration); mutation test on the restored audit reasons; head re-checked against develop (0 behind).
CI @ce6e277c: all green (ubuntu / macos / windows, clippy, fmt, benchmark, Security Scan, semgrep, doc review, CLA).
Blocks merge (0)
Round 5's blocker is gone: you rebased onto exactly current develop and it compiles.
Checked and correct — no need to re-verify
-
Shared-decision adaptation. Routing through
decide_hook_action(cmd, Host::Codex)is the right call, and theAskRewritewrinkle is resolved well: both Allow and Ask emit protocol-levelallowbecause Codex can't acceptupdatedInputotherwise, while the internal outcome staysAskso it's never recorded as an RTK auto-approval. The comment says exactly that, which is what a future reader needs.Being precise for the record about what this did and didn't change:
load_rules_for(Host::Codex)returns empty vectors, so no RTK deny/ask rule applies to Codex today and the behaviour is unchanged. TheDeny/AllowRewritearms are unreachable in production but tested, so they're ready if a Codex-side rule source ever exists. That's a reasonable documented choice matchingHost::Vibe, and it isn't something I'm holding this on. -
Audit reasons restored.
reasontravelling onSkipis the right shape givendecisionalone can't separate the three defer causes. Verified by mutation rather than by reading: collapsingskip:unsupported_permission_modeback toskip:deferfailstest_codex_skip_reasons_remain_distinct, so all three causes are genuinely pinned. -
Earlier rounds' fixes still hold — the Cursor parse-vs-I/O split, the Droid per-candidate cleanup, and the
raw_first_tokenremoval after #3704 landed, all re-verified on this head.
Fixup pushed — ce6e277c
One cosmetic change, since Host::Codex and Host::Vibe both return empty rule vectors and separate arms just multiply branches that have to stay in sync:
- Host::Codex => (Vec::new(), Vec::new(), Vec::new()),
- Host::Vibe => (Vec::new(), Vec::new(), Vec::new()),
+ Host::Codex | Host::Vibe => (Vec::new(), Vec::new(), Vec::new()),with the comment reworded to cover both. No behaviour change; fmt, clippy and the full suite are green on it, and CI re-ran on the new head.
Filed as follow-ups
#4002 — the four hook-config I/O cleanups you offered to take separately. Unchanged from last round.
Your questions
- "Could you approve the workflow run for this head?" → done, and it came back green. I've approved the run on the fixup head too.
Next
Nothing — approving. Thanks for the patience across six rounds; the mutation-verified regression tests on the Cursor and Droid paths are what made the last two rounds cheap to check.
Rounds: landing. Threads: 0 open, 9 resolved.
Summary
PreToolUseintegration that transparently rewrites supported shell commands tortk ...throughupdatedInput.Implementation
rtk hook codexwith fail-open parsing and preservation of other tool input fields.rtk init --codexand update Codex guidance and integration docs.Benefits
Codex users get transparent RTK token savings without relying on prompt compliance or paying for another model inference, while retaining Codex's native approval and sandbox checks.
This integration is now mature because the required
PreToolUse.updatedInputcapability is available in Codex and has been verified end to end against Codex CLI0.147.0-alpha.6.6.I would appreciate review and merge if this direction aligns with the project.
Test plan
cargo fmt --all && cargo clippy --all-targets && cargo testls -laexecuted asrtk ls -laand returned compact outputRelated issues
Closes #1003
Closes #1812
Addresses #2921