Codex CLI guardrails
Reflex adds Codex hooks that judge each Bash command inside whatever sandbox mode and approval policy Codex runs with; those stay in charge. Codex hooks cannot show a prompt, so a Reflex ask blocks with a reason and the human runs the exact command with reflex run in their own terminal.
Install: npx @ursuciprian/reflex setup starts with local rules in shadow mode, no account or key.
Plugins for Claude Code, Codex CLI and opencode: setup guide.
What guardrails can I add to Codex CLI, and how does Reflex work with the Codex sandbox?
Reflex adds Codex hooks (PreToolUse and PostToolUse in ~/.codex/hooks.json) that judge each
Bash command inside whatever sandbox mode and approval policy Codex runs with; those stay in
charge. Codex hooks cannot show a prompt or approve, so a Reflex ask blocks with a reason, and the
human runs the exact command with reflex run "command" --cwd /path in their own terminal. The
injection guard reads Bash and MCP results in Codex (web search is not hookable). Hooks must be
trusted once in Codex's /hooks before they run.
See: supported agents, docs/SETUP.md: install the hooks.
How do I install Reflex as a Codex CLI plugin?
Add the marketplace in this repository and install the plugin from a shell:
codex plugin marketplace add ursuciprian/reflex, then codex plugin add reflex@reflex. Open
codex, run /hooks and trust the Reflex entries: Codex runs no plugin hook it has not been told to
trust. The plugin wires the same Codex hooks as reflex setup --agent codex: the PreToolUse
command gate on Bash and spawn_agent, the post-tool records, conditional instructions and the
prompt injection guard on Bash and MCP results and on prompts. It needs Node.js 18+ on the PATH
and no build step or API key; with no saved settings it runs the local engine in shadow mode. If
reflex setup hooks are also in ~/.codex/hooks.json, the plugin's hooks stand down so nothing is
judged twice, and reflex doctor shows which one is active.
See: README: Codex CLI plugin, docs/SETUP.md: Codex CLI plugin.
Codex CLI plugin
The same repository is a Codex plugin marketplace (.agents/plugins/marketplace.json) that lists
the reflex plugin at the repository root. Codex reads .codex-plugin/plugin.json there, which
points at hooks/codex.json, not at the Claude Code hooks/hooks.json. Codex copies the plugin to
$CODEX_HOME/plugins/cache/reflex/reflex/<version>/ and runs the hooks from that copy with node.
codex plugin marketplace add ursuciprian/reflex
codex plugin add reflex@reflex
codex plugin marketplace upgrade reflex # later, for a new release,
codex plugin add reflex@reflex # then add it again to copy the new version
Inside Codex, /plugins shows the same marketplace. Then open codex, run /hooks and trust the
Reflex entries: Codex runs no plugin hook it has not been told to trust, and it asks again when a
new release changes one.
| Part | What it is |
|---|---|
hooks/codex.json | the same Codex events, matchers and timeouts as install.mjs --agent codex (see step 3): PreToolUse on ^(Bash|spawn_agent)$ (15 s), PostToolUse records on ^(Bash|spawn_agent)$ (5 s), the injection guard on PostToolUse for ^Bash$|^mcp__ (15 s), UserPromptSubmit instructions (10 s) and prompt guard (5 s). Each runs node "$PLUGIN_ROOT/<script>.mjs" <flag> --plugin (an environment variable Codex sets; the form works in sh, bash, zsh and fish); a test keeps the file in step with install.mjs |
skills/reflex | tells the agent when to use reflex check and reflex replay, and not to work around a deny |
Codex loads skills/ by default and turns two of the Claude Code commands (status, queue) into skills (checked with Codex 0.157: they appear under .codex-plugin/migrated-command-skills/ in the installed copy). The reflex CLI
is not put on the PATH by Codex; install the package (npm install -g @ursuciprian/reflex) if you
want those skills and reflex status to work. Configuration, defaults and logs are the same as for
reflex setup: config.json, the environment and, for Jev, the key variable or the Keychain item
(the Claude Code plugin options above do not apply to Codex).
Plugin and reflex setup together. Codex runs every matching hook from every source, so both
would judge each call. When reflex setup (or install.mjs --agent codex) has written Reflex hooks
into ~/.codex/hooks.json, every plugin hook exits at once without reading its input or writing a
log line. The plugin checks the file Codex reads, $CODEX_HOME/hooks.json when CODEX_HOME is set.
A hook whose script no longer exists does not count, and reflex status reports it as an error.
reflex status and reflex doctor print which path is active (Codex CLI hooks: ...); doctor
also runs the plugin's installed PreToolUse command through $SHELL -lc, as Codex does, when the plugin is the active one. Codex runs a hooks.json entry only after you trust it, but the plugin stands down for it either way; reflex status warns when setup hooks silence the plugin and none of them has run yet. To switch to the plugin only:
node <copy that installed them>/install.mjs --agent codex --uninstall; to switch to setup only:
codex plugin remove reflex@reflex. The plugin's gate timeout is 15 s, the same as reflex setup
without System 2; with the autonomous profile use reflex setup --profile autonomous.
To remove the plugin: codex plugin remove reflex@reflex, and
codex plugin marketplace remove reflex for the marketplace. The gate's tamper rule asks before
the agent runs either of them.