Files
codex/codex-rs/execpolicy
Eric Traut 713ae22c04 Another round of improvements for config error messages (#9746)
In a [recent PR](https://github.com/openai/codex/pull/9182), I made some
improvements to config error messages so errors didn't leave app server
clients in a dead state. This is a follow-on PR to make these error
messages more readable and actionable for both TUI and GUI users. For
example, see #9668 where the user was understandably confused about the
source of the problem and how to fix it.

The improved error message:
1. Clearly identifies the config file where the error was found (which
is more important now that we support layered configs)
2. Provides a line and column number of the error
3. Displays the line where the error occurred and underlines it

For example, if my `config.toml` includes the following:
```toml
[features]
collaboration_modes = "true"
```

Here's the current CLI error message:
```
Error loading config.toml: invalid type: string "true", expected a boolean in `features`
```

And here's the improved message:
```
Error loading config.toml:
/Users/etraut/.codex/config.toml:43:23: invalid type: string "true", expected a boolean
   |
43 | collaboration_modes = "true"
   |                       ^^^^^^
```

The bulk of the new logic is contained within a new module
`config_loader/diagnostics.rs` that is responsible for calculating the
text range for a given toml path (which is more involved than I would
have expected).

In addition, this PR adds the file name and text range to the
`ConfigWarningNotification` app server struct. This allows GUI clients
to present the user with a better error message and an optional link to
open the errant config file. This was a suggestion from @.bolinfest when
he reviewed my previous PR.
2026-01-23 20:11:09 -08:00
..
2025-12-02 15:05:27 -05:00

codex-execpolicy

Overview

  • Policy engine and CLI built around prefix_rule(pattern=[...], decision?, justification?, match?, not_match?).
  • This release covers the prefix-rule subset of the execpolicy language; a richer language will follow.
  • Tokens are matched in order; any pattern element may be a list to denote alternatives. decision defaults to allow; valid values: allow, prompt, forbidden.
  • justification is an optional human-readable rationale for why a rule exists. It can be provided for any decision and may be surfaced in different contexts (for example, in approval prompts or rejection messages). When decision = "forbidden" is used, include a recommended alternative in the justification, when appropriate (e.g., "Use `jj` instead of `git`.").
  • match / not_match supply example invocations that are validated at load time (think of them as unit tests); examples can be token arrays or strings (strings are tokenized with shlex).
  • The CLI always prints the JSON serialization of the evaluation result.
  • The legacy rule matcher lives in codex-execpolicy-legacy.

Policy shapes

  • Prefix rules use Starlark syntax:
prefix_rule(
    pattern = ["cmd", ["alt1", "alt2"]], # ordered tokens; list entries denote alternatives
    decision = "prompt",                 # allow | prompt | forbidden; defaults to allow
    justification = "explain why this rule exists",
    match = [["cmd", "alt1"], "cmd alt2"],           # examples that must match this rule
    not_match = [["cmd", "oops"], "cmd alt3"],       # examples that must not match this rule
)

CLI

  • From the Codex CLI, run codex execpolicy check subcommand with one or more policy files (for example src/default.rules) to check a command:
codex execpolicy check --rules path/to/policy.rules git status
  • Pass multiple --rules flags to merge rules, evaluated in the order provided, and use --pretty for formatted JSON.
  • You can also run the standalone dev binary directly during development:
cargo run -p codex-execpolicy -- check --rules path/to/policy.rules git status
  • Example outcomes:
    • Match: {"matchedRules":[{...}],"decision":"allow"}
    • No match: {"matchedRules":[]}

Response shape

{
  "matchedRules": [
    {
      "prefixRuleMatch": {
        "matchedPrefix": ["<token>", "..."],
        "decision": "allow|prompt|forbidden",
        "justification": "..."
      }
    }
  ],
  "decision": "allow|prompt|forbidden"
}
  • When no rules match, matchedRules is an empty array and decision is omitted.
  • matchedRules lists every rule whose prefix matched the command; matchedPrefix is the exact prefix that matched.
  • The effective decision is the strictest severity across all matches (forbidden > prompt > allow).

Note: execpolicy commands are still in preview. The API may have breaking changes in the future.