exec_command PreToolUse payload drops workdir and misclassifies isolated worktrees

Resolved 💬 1 comment Opened Jul 23, 2026 by douville Closed Jul 23, 2026
💡 Likely answer: A maintainer (github-actions[bot], contributor) responded on this thread — see the highlighted reply below.

What version of Codex CLI is running?

codex-cli 0.144.5 from codex doctor --json; the active TUI session metadata reports cli_version: 0.145.0 after the update check selected 0.145.0.

What subscription do you have?

ChatGPT-authenticated operator-managed account (exact plan not exposed to this session).

Which model were you using?

gpt-5.6-sol

What platform is your computer?

Linux 7.0.11-76070011-generic x86_64 x86_64 (Pop!_OS 24.4.0), tmux 3.4.

Codex doctor report

Overall status ok. Relevant fields:

{
  "codexVersion": "0.144.5",
  "overallStatus": "ok",
  "auth": "ChatGPT",
  "features": ["unified_exec", "code_mode_host", "hooks"],
  "latestVersion": "0.145.0",
  "platform": "linux-x86_64"
}

What issue are you seeing?

exec_command accepts and executes an explicit workdir, but its PreToolUse hook payload discards that field and exposes only the command. Hook policy therefore sees the outer session cwd and can falsely classify a safe linked-worktree mutation as a primary-checkout mutation.

This also reproduces through code mode / nested functions.exec -> exec_command: the outer custom-tool transcript retains the nested workdir, the command executes in that worktree, but the corresponding PreToolUse event contains the session's primary-checkout cwd.

Current upstream root cause at 44d76c6a6dd04fa2efc302b906ac8774267a1272:

codex-rs/core/src/tools/handlers/unified_exec/exec_command.rs, ExecCommandHandler::pre_tool_use_payload, parses ExecCommandArgs and then constructs:

tool_input: serde_json::json!({ "command": args.cmd }),

args.workdir is intentionally omitted. The focused test exec_command_pre_tool_use_payload_uses_raw_command in unified_exec_tests.rs locks in the lossy shape.

The execution path later resolves and honors args.workdir, so execution and hook-policy provenance disagree.

What steps can reproduce the bug?

  1. Start Codex with unified_exec and hooks enabled from a repository's primary checkout.
  2. Register a PreToolUse hook matching Bash that records stdin JSON.
  3. Create a linked worktree at /tmp/repro-worktree.
  4. Invoke exec_command with cmd: "git status --short" and workdir: "/tmp/repro-worktree".
  5. Observe that the command runs in /tmp/repro-worktree, but hook stdin contains tool_input.command only; common cwd remains the session's primary checkout.
  6. The same loss occurs when exec_command is invoked inside code mode / functions.exec.

A unit-level reproduction is to extend exec_command_pre_tool_use_payload_uses_raw_command with "workdir": "/tmp/repro-worktree"; the expected hook payload cannot currently include it.

What is the expected behavior?

The PreToolUse payload for unified exec should preserve the model-facing execution provenance needed for policy evaluation, at minimum:

{
  "tool_name": "Bash",
  "tool_input": {
    "command": "git status --short",
    "workdir": "/tmp/repro-worktree"
  }
}

Omit workdir only when it was absent from the invocation. Direct and code-mode/nested unified exec should produce the same hook contract. PostToolUse should remain correlated with the same effective target.

View original on GitHub ↗

1 Comment

github-actions[bot] contributor · 1 month ago

Potential duplicates detected. Please review them and close your issue if it is a duplicate.

  • #33986

Powered by Codex Action