Codex Desktop exposes no-op functions.zz tool that is accidentally selected and cannot be denied
Summary
Codex Desktop exposes an empty zero-argument developer tool named functions.zz. It returns {} and is repeatedly selected accidentally by the model, even when the user and agent explicitly instruct the agent not to call it.
This looks like a tool registry / runtime tool-list issue, not an AGENTS.md or prompt compliance issue. Because the tool is still present in the model-visible tool schema, the model can continue selecting it.
Environment
- Codex Desktop / Codex CLI:
codex-cli 0.138.0-alpha.7 - Codex Desktop app version visible in runtime env:
26.608.12217 - OS: macOS 26.5.1, arm64
- Collaboration mode: Default
- Model: gpt-5.5 via Responses API
- Hooks feature: enabled
Steps to reproduce
- Start a Codex Desktop thread with tools enabled.
- Observe that a tool named
functions.zzis available to the agent. - Ask the agent not to call
functions.zz, or add AGENTS.md / memory guidance that it must never be used. - Continue normal coding work or even discuss fixing this exact issue.
- The model still occasionally selects
functions.zz.
In my current thread, functions.zz was selected multiple times while the task was explicitly to remove/block/report functions.zz itself.
Actual behavior
The tool call succeeds with an empty result:
{}
It provides no useful output, wastes a tool call, creates noisy transcript history, and erodes user trust because the user explicitly asked for it not to be used.
Adding prompt/AGENTS.md instructions lowers the chance but cannot guarantee prevention, because functions.zz is still in the model-visible tool list.
Local mitigation attempted
I added a global PreToolUse hook that denies zz / functions.zz:
{
"hooks": {
"PreToolUse": [
{
"hooks": [
{
"type": "command",
"command": "/usr/bin/python3 /Users/chuan/.codex/hooks/block_functions_zz.py",
"statusMessage": "Checking blocked empty tools"
}
]
}
]
}
}
The hook script correctly emits:
{
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "Blocked empty no-op tool functions.zz."
}
}
However, functions.zz still executes and returns {} in the same Desktop session. This suggests functions.zz either bypasses the PreToolUse hook pipeline or is already injected as a developer/internal tool outside the normal MCP/Bash/apply_patch hookable tool set.
The public manual also documents disabled_tools only for MCP servers and plugin-provided MCP servers, not for built-in/developer functions.* tools.
Expected behavior
One of these would fix it:
- Remove
functions.zzfrom the runtime tool registry entirely if it is a leftover dummy/no-op tool. - Hide unavailable/dummy/internal tools from the model-visible tool list.
- Add a user-level denylist for built-in/developer tools, for example:
[tools]
disabled_tools = ["functions.zz"]
- Ensure
PreToolUsecan intercept and deny all model-visible tools, including built-in/developerfunctions.*tools, or document why those tools are excluded and provide another enforcement surface.
Why this matters
AGENTS.md, memories, and prompt instructions are not a hard control surface for tool availability. A zero-argument no-op tool is especially easy for the model to call accidentally because it requires no arguments and returns a valid empty result.
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗