Summary
On Cursor-backed models, agents repeatedly tell the user that shell/read access is blocked even when Codex is already running with full sandbox access and the Codex shell bridge tool still works.
This is not a missing-permissions bug. It is a Cursor adapter / tool-catalog / messaging bug:
- Cursor-native
Shell / Read / Grep / LS are rejected by policy (default nativeLocalExec off).
- OpenCodex guidance and rejection text push
exec_command.
- The actually working Codex shell bridge is often advertised / callable as
shell_command and/or the long MCP display name (mcp_opencodex-responses_shell_command / mcp_opencodex-responses_exec_command).
- Tool-catalog truncation changes which exact name is visible turn-to-turn.
- Models treat the resulting "tool not found" / native-exec rejection as a hard sandbox block and emit user-facing lines like:
Shell access is blocked here
Shell and Read are blocked in this environment
Observed across multiple Codex Desktop chats on Cursor models (including while diagnosing this issue).
Expected
With Codex full-access sandbox already enabled:
- Calling the Codex shell bridge succeeds.
- If Cursor-native Shell/Read are unavailable, rejection text should clearly say "use Codex bridge tool X (aliases: ...)", not sound like a sandbox denial.
- Agents should not tell the user that shell/read are blocked unless the Codex bridge shell tool itself fails.
- The shell bridge tool should remain available even when the Cursor client-tool catalog is truncated.
Actual
- Cursor-native Shell/Read get rejected with copy that points at
exec_command.
- The live callable shell tool name flips between turns among:
shell_command
exec_command
- long
mcp_opencodex-responses_* display names
- occasionally Cursor-native
Shell appearing in guidance/catalog text
- Models then emit false "blocked" commentary even though a later
shell_command / bridge call works in the same chat.
- Catalog truncation notes (
Cursor's transport limit allows N of M client tools this turn) amplify the confusion.
Evidence / code pointers
Relevant OpenCodex paths:
src/adapters/cursor/tool-definitions.ts
- hardcodes shell guidance around
exec_command
- warns against neighboring-agent tools
Read / Grep / Glob / Bash / LS
- mentions long display alias
mcp_opencodex-responses_exec_command
src/adapters/cursor/request-builder.ts
applyCursorToolBudget / toolPriority / catalogLimitNote
- truncation can omit many tools; shell bridge is not specially pinned beyond generic bare-tool priority
src/adapters/cursor/native-exec-shell.ts
- rejection: Cursor native shell unavailable; use
exec_command
src/adapters/cursor/native-exec-fs.ts
- rejection: Cursor native filesystem read/ls/grep unavailable; use
exec_command / apply_patch
src/adapters/cursor/exec-policy.ts
- default native local exec is off unless explicitly opted in
- docs:
docs-site/src/content/docs/reference/configuration.md
- documents
unsafeAllowNativeLocalExec as an intentional opt-in, not the default path
Live reproduction pattern (redacted):
- Use a
cursor/* model through OpenCodex.
- Ensure Codex sandbox is full-access / approval never.
- Ask the agent to inspect local files/run shell.
- Observe either:
- wrong tool name (
Shell / missing short name) fails, or
- Cursor-native Shell/Read rejected with "use exec_command"
- Agent announces shell/read are blocked.
- Same chat can then succeed with
shell_command / long MCP shell alias.
Why this is harmful
- Users waste time chasing phantom permission problems.
- Agents abandon working shell paths and invent alternate broken tool names.
- Multi-turn work becomes flaky because catalog truncation + naming drift changes the callable shell identifier every turn.
Proposed fix
Minimum durable fix set:
- Unify the shell tool name across catalog
shell_type, Cursor guidance, rejection messages, and docs.
- Today
shell_command and exec_command conflict.
- Pin the shell bridge tool through catalog truncation in
applyCursorToolBudget / toolPriority so truncation can drop niche MCP tools but never the shell bridge (and ideally also keep apply_patch).
- Rewrite rejection/guidance copy:
- say Cursor-native Shell/Read are disabled by policy
- point to the exact Codex bridge tool + aliases
- explicitly state this is not a sandbox denial when Codex full-access is already active
- Add anti-false-block guidance:
- never tell the user shell/read are blocked unless the Codex bridge shell tool also fails
- if a shell alias is missing, retry listed aliases instead of escalating to "blocked" language
- Make alias resolution boring and bidirectional so all of these resolve to one backend tool:
shell_command
exec_command
mcp_opencodex-responses_shell_command
mcp_opencodex-responses_exec_command
- Regression tests covering:
- full-access sandbox
- native Cursor Shell/Read rejected
- bridge shell still works
- truncated catalogs still retain bridge shell
- guidance/rejection text does not claim "Shell access is blocked"
Non-goals / not the fix
- Do not treat this as a Codex sandbox_mode / approval_policy problem.
- Do not require enabling
unsafeAllowNativeLocalExec as the primary solution.
- That flag remains an intentional escape hatch for Cursor-native local exec; the default path should remain the Codex bridge, but without false "blocked" UX.
Environment (redacted)
- Host: Windows
- Client: Codex Desktop + OpenCodex Cursor provider path
- Model family:
cursor/*
- Codex sandbox already full-access
- Issue filing account is a fork collaborator account; no local paths / tokens / private IDs included
Summary
On Cursor-backed models, agents repeatedly tell the user that shell/read access is blocked even when Codex is already running with full sandbox access and the Codex shell bridge tool still works.
This is not a missing-permissions bug. It is a Cursor adapter / tool-catalog / messaging bug:
Shell/Read/Grep/LSare rejected by policy (defaultnativeLocalExecoff).exec_command.shell_commandand/or the long MCP display name (mcp_opencodex-responses_shell_command/mcp_opencodex-responses_exec_command).Shell access is blocked hereShell and Read are blocked in this environmentObserved across multiple Codex Desktop chats on Cursor models (including while diagnosing this issue).
Expected
With Codex full-access sandbox already enabled:
Actual
exec_command.shell_commandexec_commandmcp_opencodex-responses_*display namesShellappearing in guidance/catalog textshell_command/ bridge call works in the same chat.Cursor's transport limit allows N of M client tools this turn) amplify the confusion.Evidence / code pointers
Relevant OpenCodex paths:
src/adapters/cursor/tool-definitions.tsexec_commandRead/Grep/Glob/Bash/LSmcp_opencodex-responses_exec_commandsrc/adapters/cursor/request-builder.tsapplyCursorToolBudget/toolPriority/catalogLimitNotesrc/adapters/cursor/native-exec-shell.tsexec_commandsrc/adapters/cursor/native-exec-fs.tsexec_command/apply_patchsrc/adapters/cursor/exec-policy.tsdocs-site/src/content/docs/reference/configuration.mdunsafeAllowNativeLocalExecas an intentional opt-in, not the default pathLive reproduction pattern (redacted):
cursor/*model through OpenCodex.Shell/ missing short name) fails, orshell_command/ long MCP shell alias.Why this is harmful
Proposed fix
Minimum durable fix set:
shell_type, Cursor guidance, rejection messages, and docs.shell_commandandexec_commandconflict.applyCursorToolBudget/toolPriorityso truncation can drop niche MCP tools but never the shell bridge (and ideally also keepapply_patch).shell_commandexec_commandmcp_opencodex-responses_shell_commandmcp_opencodex-responses_exec_commandNon-goals / not the fix
unsafeAllowNativeLocalExecas the primary solution.Environment (redacted)
cursor/*