Skip to content

Provide a supported way for local IDE/wrapper installers to request trust for installed hooks #21615

Open

Description

@brennanb2025

What version of Codex CLI is running?

0.129.0

What platform is your computer?

Darwin 25.3.0 arm64 arm

What terminal emulator and version are you using (if applicable)?

Orca terminal, running Codex CLI inside Orca

What issue are you seeing?

I maintain a local IDE/wrapper integration that runs Codex CLI and installs Codex hooks into ~/.codex/hooks.json so the wrapper can observe session/tool/turn lifecycle events.

After hook trust enforcement was added, those wrapper-installed hooks do not run until the user manually opens /hooks and approves each hook entry. In our case this blocks wrapper integration entirely until the user reviews several hooks by hand. The same review wall returns whenever the wrapper updates its hook command (e.g. install path moves between dev/prod, or an upgrade changes the wrapper script).

The issue is not that the trust gate is wrong. The problem is that there does not appear to be a supported programmatic way for a non-privileged installer to request user-consented trust for hooks it has installed. The available auto-trusted paths require system/MDM-managed configuration, while the user-writable path ~/.codex/hooks.json always hits manual review.

This isn't theoretical: the trust hash is reproducible from the open-source implementation, so the practical alternative for integrators today is to write Codex's internal trust state directly with [hooks.state."<key>"] trusted_hash = "..." entries in ~/.codex/config.toml. A supported API would be better than having each integrator ship its own copy of that private logic.

Expected: Codex provides a supported CLI/API path for local wrappers to request or complete user-consented trust for an already-installed hook entry.

Actual: wrappers either require the user to manually approve every installed hook in /hooks, or they edit Codex's internal trust state directly.

What steps can reproduce the bug?

Thread id: not applicable.

  1. Install or run Codex 0.129.0 or newer.

  2. Add an unmanaged hook to ~/.codex/hooks.json.

    Example:

    {
      "hooks": {
        "SessionStart": [
          {
            "matcher": "",
            "hooks": [
              {
                "type": "command",
                "command": "node /path/to/local-wrapper-hook.js SessionStart"
              }
            ]
          }
        ],
        "PreToolUse": [
          {
            "matcher": "",
            "hooks": [
              {
                "type": "command",
                "command": "node /path/to/local-wrapper-hook.js PreToolUse"
              }
            ]
          }
        ]
      }
    }
  3. Start Codex normally inside a local IDE/wrapper or terminal.

  4. Trigger an event covered by the hook, such as starting a session or running a tool call.

  5. Observe that the hook does not run because Codex requires manual approval through /hooks.

  6. Open /hooks and approve the hook manually.

  7. Trigger the same event again and observe that the hook now runs.

  8. Change the hook command identity, for example by changing the script path or generated command.

  9. Start Codex again and observe that the hook requires manual review again.

This is reproducible with any local wrapper that installs user-level hooks into ~/.codex/hooks.json. The important part is that the installer is user-level and cannot write to system-managed config such as /etc/codex/config.toml without requiring root.

What is the expected behavior?

Codex should provide a supported, stable way for a local installer to request user consent for a hook entry that already exists in Codex's discovered hook set.

For example, a CLI/API along these lines would solve the integrator case:

codex hooks trust request \
  --source ~/.codex/hooks.json \
  --event PreToolUse \
  --command 'node /path/to/wrapper-hook.js PreToolUse' \
  --json

Identifying entries by their content (event + command + optional matcher) rather than positional --group/--handler indices avoids fragility when other tools edit hooks.json between writes and shifts those indices.

Expected properties:

  • Idempotent.
  • Computes trust using Codex's own current normalization rules.
  • Refuses to trust a hook that does not already exist in hooks.json.
  • Produces machine-readable output for wrappers.
  • Returns enough state for wrappers to surface "pending approval" clearly to users.

If maintainers want an approval command, it should still be user-consented, for example by opening the same Codex-owned confirmation path as /hooks:

codex hooks trust approve --interactive \
  --source ~/.codex/hooks.json \
  --event PreToolUse \
  --command 'node /path/to/wrapper-hook.js PreToolUse' \
  --json

That would avoid an unconditional auto-grant while still giving wrappers a supported path, instead of requiring each integrator to reproduce Codex's internal trust hash and edit ~/.codex/config.toml directly.

Additional information

This is not a request to remove or weaken hook trust enforcement. The trust gate is useful, and the current behavior makes sense for manually edited user config.

The gap is specifically for user-installed local tools that wrap Codex and need hooks as an integration surface. Those tools are not system administrators, so requiring /etc/codex or MDM-managed config is not a practical install path. At the same time, asking users to manually approve several generated hooks on every command/path change creates a poor setup and upgrade experience.

We have verified that reproducing Codex's current trust hash and writing to ~/.codex/config.toml works as a workaround, including for versions before 0.129.0 where the trust gate is absent. The concern is that this workaround depends on private implementation details and will likely be copied by multiple wrappers unless Codex exposes a supported trust/request API.

I'm happy to test or send a PR if maintainers are interested in a specific direction.

Activity

  1. added
    enhancementNew feature or request
    CLIIssues related to the Codex CLI
    hooksIssues related to event hooks
    on May 7, 2026
  2. removed
    CLIIssues related to the Codex CLI
    bugSomething isn't working
    on May 7, 2026
  3. oxysoft commented on May 8, 2026

    @oxysoft

    Indexed this hook ticket in the umbrella tracker: #21753

    Goal: collect the scattered Codex hook requests and bugs into one parity matrix for Full Claude Code Hook Parity (29+), while preserving this issue as the detailed thread for its specific behavior.

  4. mkjt2 commented on May 15, 2026

    @mkjt2

    Hard agree. The fact that a hook's position changing in the broad hook list loses trust is a problem.

  5. jsirish commented on Aug 26, 2026

    @jsirish

    Confirming this works and adding a data point: verified on macOS, codex-cli v0.149.0.

    Copied a [hooks.state."<plugin>@<marketplace>:hooks/hooks.json:<event>:0:0"] trusted_hash = "..." block (originally granted via an interactive codex -p <profile> exec session that went through the normal directory-trust prompt) from a profile-layered config file (~/.codex/<profile>.config.toml) into the base ~/.codex/config.toml — the file the Desktop app reads exclusively, since it has no --profile mechanism of its own. Also had to set features.plugin_hooks = true in that same base config's [features] table (unclear if this was strictly necessary or redundant with the copy — didn't isolate the two variables).

    After that, automatic hook-driven capture started firing correctly in two different real projects, confirmed live in Codex Desktop itself (not just headless codex exec) — matches what #37362 describes as a real gap in Desktop's own trust review flow.

    +1 on a real codex hooks trust request-style subcommand. Hand-copying trust hashes between config layers works today (the hash is portable since it's content-based, not tied to how it was originally granted), but it's clearly not meant to be the supported path, and it's easy to imagine it breaking silently on a future release.

  6. added a commit that references this issue on Aug 26, 2026
  7. mib00038 commented on Oct 2, 2026

    @mib00038

    Another concrete case for this. We install PreCompact/PostCompact command hooks from a launcher. Changing only a handler's timeout (8 → 45) puts timeout into the normalised config that is hashed (hooks/src/engine/discovery.rs:559-565, :775-791), so every host's existing trust becomes Modified (:805-808) and the hooks are skipped until a person re-trusts them in /hooks on each machine. A supported, user-consented way for an installer to request trust for the exact handler it just wrote would remove that manual step per host.

  8. glmn commented on Oct 7, 2026

    @glmn

    Another data point: the same wall applies to hooks that are not installed anywhere. We pass hooks for a single run only, through the session-flags layer (codex -c 'hooks={...}'), so nothing is written to the user's ~/.codex. Those hooks are still reviewed like user hooks, so the only way to start without the review screen (and without --dangerously-bypass-hook-trust, which would also run a repository's untrusted hooks) is to reproduce Codex's canonical-JSON SHA-256 and pass hooks.state."<key>".trusted_hash in the same -c layer. That works (checked against codex app-server hooks/list on 0.153.4), but it depends on private details: the key format, the normalisation in hooks/src/engine/discovery.rs, and the position-based keys (#49399).

    For a host that builds the command line itself, a supported way to say "the hooks in this layer were authored by the launcher" would remove the need for that copy. For example, hooks supplied via -c on the command line could count as trusted for that run only, or a --trust-session-hooks flag could apply only to hooks from the session-flags layer and never to project or plugin hooks.

  9. mib00038 commented on Oct 13, 2026

    @mib00038

    A follow-up to the position-keyed trust point raised in #49399, which was closed as not planned. It belongs here, because it is the installer side of the same problem.

    We just cleaned up a host (codex-cli 0.161.0, Linux) where an older installer had left two stale handler groups around the current one in ~/.codex/hooks.json, for SessionStart, PreCompact and PostCompact. Removing the stale entries is a pure deletion: the remaining handler's definition did not change. Because trust is keyed by <source>:<event>:<group_index>:<handler_index>, the current handler moved from index 1 to index 0. Its existing trust no longer applied, so every event needed a person in /hooks before the hooks would run again.

    Two consequences for installers:

    1. Cleanup cannot stay unattended. An installer cannot safely remove its own stale entries if they sit in front of a live entry. Every cleanup of that kind becomes an interactive maintenance window, during which no session should start on that host.
    2. The result cannot be checked programmatically without starting a session. hooks/list is the obvious read, but we found no supported read-only connection to an existing app-server, and attaching through a client replaces that client. So after the review, the only confirmation we had was the person reading the /hooks screen.

    Keying trust on the handler's definition, rather than on its position, would make all three cases in this thread safe: the edits by hand in #49399, an installer's in-place updates, and cleanup by deletion. A read-only way to list hook trust state without starting a thread would cover verification.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or requesthooksIssues related to event hooks

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions