On Codex, whether a tool-gates ask becomes a visible prompt is decided by Codex's own approval_policy, not by tool-gates. This page covers what tool-gates can and cannot control on Codex, and the one supported lever, execpolicy rules, that makes it authoritative over Codex's built-in safe-read list.
Where the prompt comes from
Codex's approval_policy owns the prompt, not tool-gates.
On Codex a tool-gates ask is pass-through. Codex PreToolUse has no supported ask decision; its only positive decision is allow paired with updatedInput. Tool Gates does not turn an ask-level rewrite into an auto-running allow, so all non-denies emit empty stdout and hand the decision back to Codex. Whether the user is then prompted depends entirely on Codex's approval_policy.
approval_policy
Does a tool-gates ask reach a prompt?
untrusted
Yes. Every command Codex doesn't recognise as a known-safe read is sent to the approval path, where the PermissionRequest hook (tool-gates) and then the user decide. This is the only policy where tool-gates acts as a prompt layer.
on-request
Mostly no. Non-dangerous commands run inside the sandbox without a prompt; the user is asked only when the model explicitly requests escalation. A tool-gates ask is moot.
on-failure
No. Commands run sandboxed and prompt only if they fail. A tool-gates ask never surfaces.
never
No prompts at all.
These four are the common presets. Codex also has a fifth granular policy for fine-grained per-category approvals.
tool-gates can hard-deny here, and only deny. Everything else passes through.
▸safe-list / execpolicy
Codex-internal
Auto-approve?
A command on Codex's built-in is_safe_command read list auto-approves here and never reaches tool-gates, unless an execpolicy rule (matched first) forces it onward.
▸PermissionRequest
when approval is needed
tool-gates decides
allow auto-approves and suppresses the prompt; deny blocks; pass-through hands off to the user prompt.
▷
User prompt, then run
Codex shows the prompt only when tool-gates passed through.
Capability
What tool-gates can and cannot do on Codex.
Deny always works
A hard deny lands on both PreToolUse and PermissionRequest. The security floor (destructive rm, pipe-to-shell, your own deny rules) is fully enforced on Codex. Every PreToolUse deny includes a nonempty permissionDecisionReason, which Codex displays as hook feedback. Structured recovery stays separate in Codex's supported PreToolUse additionalContext, which Codex records before returning the blocked result.
Recovery matches Codex capabilities
The shared gate never embeds another client's tool name. For an output cap over one confirmed source file, Codex receives the requested first or last line count plus a conditional bat -r example. For streamed output such as git log | sed -n '1,10p', no file reader is suggested; recovery stays at the producer or persisted complete output.
Auto-approval stays on PermissionRequest
A positive allow that auto-approves and suppresses the prompt is honoured on PermissionRequest under untrusted. PreToolUse also accepts allow, but only as an input rewrite paired with updatedInput; plain allow and ask are invalid. Tool Gates deliberately does not map its ask-level command rewrites to that form because doing so would auto-run the replacement. Non-deny hints and Tier-3 warnings remain on PostToolUse; deny recovery uses PreToolUse additionalContext.
Safe-reads are invisible
Codex auto-approves cat, ls, grep, rg, sed -n, git status/log/diff, and similar reads before any hook runs. tool-gates never sees them on PermissionRequest; it can only deny them via PreToolUse, never turn them into a prompt. The lever to change that is execpolicy, below.
Project edits can auto-allow
With [codex] accept_project_edits, an apply_patch whose paths are all inside the project auto-approves on PermissionRequest, honouring your settings.json deny and ask patterns and the file guards. Opt-in, off by default; covered below.
Strict output validation
Codex validates hook stdout JSON stringently. Returning extra fields like updatedInput, updatedPermissions, addDirectories, or interrupt in PermissionRequest responses, or updatedMCPToolOutput in PostToolUse responses, results in a validation error rather than being silently ignored. tool-gates actively strips these fields to maintain hook compatibility.
Why deny-only
There is no ask on Codex PreToolUse.
Codex PreToolUse has no ask decision, so no hook output can force a prompt for an otherwise-permitted command. Its positive allow form is reserved for input rewrites and is not a prompt substitute. Tool Gates therefore keeps this phase deny-only, and routing a safe-read to a prompt happens through execpolicy rather than a hook decision.
Codex evaluates execpolicy rules before its built-in is_safe_command fallback. A prefix_rule with decision="prompt" on an otherwise-safe program overrides the auto-approval and routes the command to the approval path, where the PermissionRequest hook (tool-gates) and the user decide. This is the supported way to make tool-gates authoritative over Codex's allowlist.
There is no wildcard: the first pattern token is a literal program name, so you enumerate each command you want gated. Validate a rule with codex execpolicy check --rules ~/.codex/rules/default.rules -- cat foo. Pair this with approval_policy = "untrusted"; under never a prompt rule is forbidden instead of surfaced.
With accept_project_edits enabled, a Codex apply_patch edit auto-approves on the PermissionRequest hook (behavior: allow, no prompt) when every touched path is inside the project (the session cwd plus the additionalDirectories from settings.json) and no path is guarded, asked, or denied. Codex shell commands are also evaluated as acceptEdits, so in-project file-editing commands (sd, prettier --write, mkdir -p, sed -i, ...) auto-allow while dangerous bases (rm, mv, cp) and out-of-project targets still prompt. This mirrors Claude Code's acceptEdits for Codex.
The auto-allow honours your ~/.claude/settings.jsonWrite(...) / Edit(...) / MultiEdit(...) rules: a deny pattern denies the patch, an ask pattern (for example Write(**/.env*), Write(**/secrets/**), Edit(**/package-lock.json)) still prompts, and the AI-config file guards still prompt. Patterns match gitignore-style, so **/package-lock.json matches at any depth. For a multi-file patch the strictest path decision wins: one denied or asked path blocks or prompts the whole patch.
allow_edits_anywhere = true widens the auto-allow to edits anywhere on disk, still subject to every deny pattern, ask pattern, and file guard. Leave it off to keep auto-approval scoped to the project.
Footguns
Two settings silently disable the prompt layer.
Both flip approval_policy to on-request, where mutations stop prompting. Selecting Default in the Codex /permissions popup changes it for the running session only (a runtime override, not written to disk), so a restart restores your config. Enabling "Approve for me" (Guardian) persists approval_policy = "on-request" to config.toml. Keep untrusted if you want tool-gates and prompts to govern mutations.
Sandbox vs approval
The sandbox and the prompt are different axes.
Codex's sandbox decides where a command may write; approval_policy decides when you are asked. They are independent. Turning the sandbox off (sandbox_mode = "danger-full-access") does not reduce prompts, because prompts come from approval_policy, not the sandbox. It only removes containment, leaving tool-gates plus your prompts plus the execpolicy deny floor as the safety net. A stricter sandbox, likewise, does not add prompts.