Skip to content

release: 0.3.3, the Codex plugin hook inspects prompts again - #27

Merged
DurthVadr merged 2 commits into
mainfrom
fix/codex-plugin-hook-ran-nothing
Sep 15, 2026
Merged

DurthVadr merged 2 commits into
mainfrom
fix/codex-plugin-hook-ran-nothing

Conversation

@DurthVadr

Copy link
Copy Markdown
Member

A silent no-inspection bug in 0.3.1 and 0.3.2, found during the 1.0 smoke pass.

What was wrong

plugins/shim-cli/hooks/hooks.json (the Codex hook file, which Claude Code also loads by convention) opened with [ -n "$CLAUDE_PLUGIN_ROOT" ] && exit 0 so Claude Code would not run it. Codex 0.151.0 sets CLAUDE_PLUGIN_ROOT too — its hook engine exports PLUGIN_ROOT, CLAUDE_PLUGIN_ROOT, PLUGIN_DATA, CLAUDE_PLUGIN_DATA (visible in the binary's strings next to the hooks engine). The command exited 0 before running the launcher, and Codex reported Completed. Under enforce nothing was blocked; under any mode nothing was reported. shim install codex (package route) was never affected.

How it was found and pinned

Isolated CODEX_HOME, user-prompt = "enforce", prompt with a synthetic email, codex exec --dangerously-bypass-hook-trust:

Install Result
shim install codex (package) hook: UserPromptSubmit Blocked
plugin from 1.0 candidate Completed
plugin from the published 0.3.2 (GetSHIM/shim-cli) Completed
plugin from this branch hook: UserPromptSubmit Blocked (and Completed under observe)

The launcher, instrumented, never executed under Codex; the archive and launcher run by hand blocked correctly.

Fix

Guard on [ -z "${PLUGIN_ROOT}" ] && exit 0: Claude Code leaves it unset (why the unguarded command used to run /hooks/run-shim), Codex sets it (and substitutes it textually). Fails safe: if Claude Code ever set PLUGIN_ROOT, a prompt is inspected twice, not zero times.

Claude Code 2.1.263 with this branch's plugin (project scope, stock /usr/bin/python3 3.9.6): UserPromptSubmit says: shim: found SECRET (1) in your prompt. Not modified. once, no exit-127 noise.

Tests

tests/plugins/test_plugin.py: test_the_codex_command_keys_on_the_variable_only_codex_sets, test_the_codex_command_exits_silently_when_claude_code_runs_it (only CLAUDE_PLUGIN_ROOT set), test_the_codex_command_inspects_the_prompt_under_codex[text|environment] (both variables set, as Codex does). The three Codex tests fail on 0.3.2's hooks.json. The old test's docstring encoded the wrong assumption ("sets no CLAUDE_PLUGIN_ROOT").

Why a 0.3.3

Codex caches an installed plugin by version (plugins/cache/shim-cli/shim-cli/0.3.2/), so a fix on main under the same version may not reach existing installs. Version 0.3.3 in the four declaring files, archive rebuilt, docs/releases/0.3.3.md, docs/compatibility.md paragraph corrected. check.py: 2,006 passed.

🤖 Generated with Claude Code

DurthVadr and others added 2 commits September 15, 2026 19:40
The Codex command in hooks/hooks.json stood down when CLAUDE_PLUGIN_ROOT was
set, to keep Claude Code from running it. Codex 0.151.0 sets that variable for
its own plugin hooks, so from 0.3.1 the Codex plugin hook exited before
inspecting anything and Codex reported it Completed. The guard now keys on
PLUGIN_ROOT, which Claude Code leaves unset and Codex sets; the failure mode
becomes double inspection instead of none.

The tests that run the Codex command now set both variables as Codex does and
fail on the 0.3.2 command. Seen live on Codex 0.151.0: Blocked under enforce.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
0.2.0 wrote its default entity list by name, and the list predates CUSTOM.
On an upgraded machine `shim config --custom` saved the pattern, said PASS,
and it never matched. Adding a pattern now enables CUSTOM unless the same
command disables it. Found in the 1.0 smoke pass (J3 then J4 on one home).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@DurthVadr

Copy link
Copy Markdown
Member Author

Added a second silent defect found in the same smoke pass: on a config migrated from 0.2.0 (explicit 11-entity list, no CUSTOM), shim config --custom printed PASS Entity settings saved. and the pattern never matched (ATLAS-0042 passed through shim redact). Adding a pattern now enables CUSTOM unless the same command says --disable CUSTOM. Test: tests/cli/test_cli.py::test_adding_a_pattern_enables_custom_on_a_0_2_0_entity_list, which fails without the change (assert {} == {'CUSTOM': 1}). check.py: 2,008 passed.

@DurthVadr
DurthVadr merged commit cc171c8 into main Sep 15, 2026
9 checks passed
@DurthVadr
DurthVadr deleted the fix/codex-plugin-hook-ran-nothing branch September 15, 2026 16:50
@DurthVadr DurthVadr mentioned this pull request Sep 15, 2026
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