Codex Desktop exposes no-op functions.zz tool that is accidentally selected and cannot be denied

Open 💬 1 comment Opened Jun 10, 2026 by CHANGGELY

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

  1. Start a Codex Desktop thread with tools enabled.
  2. Observe that a tool named functions.zz is available to the agent.
  3. Ask the agent not to call functions.zz, or add AGENTS.md / memory guidance that it must never be used.
  4. Continue normal coding work or even discuss fixing this exact issue.
  5. 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:

  1. Remove functions.zz from the runtime tool registry entirely if it is a leftover dummy/no-op tool.
  2. Hide unavailable/dummy/internal tools from the model-visible tool list.
  3. Add a user-level denylist for built-in/developer tools, for example:
[tools]
disabled_tools = ["functions.zz"]
  1. Ensure PreToolUse can intercept and deny all model-visible tools, including built-in/developer functions.* 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.

View original on GitHub ↗

This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗