60 Commits

  • [plugins] Enforce marketplace source policy at runtime (#29691)
    ## Summary
    
    - project effective marketplace/plugin config through the enterprise
    source policy so blocked installed plugins become inactive
    - filter plugin list/read/discovery and CLI marketplace source/snapshot
    reporting using the same policy
    - enforce source admission for background marketplace cache refreshes
    - continue refreshing/upgrading independent marketplaces and plugins
    when one entry fails, returning per-entry errors
    - include policy-projected plugin state in cache and refresh keys so
    requirement changes invalidate stale results
    
    ## Stack
    
    This is PR 2 of 2 and is based on #29690. Review the admission model and
    source matcher in #29690 first; this PR contains only runtime
    enforcement.
    
    ## Test plan
    
    - `just test -p codex-core-plugins` (287 tests)
    - `just test -p codex-cli
    plugin_list_ignores_implicit_system_marketplace_roots_without_manifests`
    - `cargo check -p codex-cli -p codex-app-server --tests`
  • app-server: structure and test JSON shutdown logs (#30314)
    ## Why
    
    `LOG_FORMAT=json` and `RUST_LOG` are supported by app-server, but the
    behavior was only covered indirectly. We should verify the actual JSONL
    written by both user-facing entry points: `codex app-server` and the
    standalone `codex-app-server` binary.
    
    The existing processor shutdown message also always said the channel
    closed, even though the processor can exit for several different
    reasons. Structured fields make that event more accurate and useful to
    log consumers.
    
    ## What changed
    
    - Record the processor `exit_reason`, remaining connection count, and
    forced-shutdown state as structured tracing fields.
    - Add a shared process-test helper that enables JSON logging, validates
    every stderr line as JSON, and verifies the top-level timestamp is RFC
    3339.
    - Cover both `codex app-server` and `codex-app-server`, asserting the
    stable `level`, `fields`, and `target` payload.
    
    ## Test plan
    
    - `just test -p codex-app-server
    standalone_app_server_emits_json_info_events`
    - `just test -p codex-cli app_server_emits_json_info_events`
  • [codex] Observe remote exec-server lifecycle (#27470)
    ## Summary
    
    - Record bounded duration and outcome metrics for remote environment
    registration and Noise rendezvous connection attempts.
    - Count reconnects by bounded reason: disconnect, connection failure, or
    rejected registration.
    - Trace registration at the owning client boundary without exporting raw
    environment or registration identifiers.
    - Replace the stale pre-Noise WebSocket observability design with the
    current remote transport model.
    
    ## Stack
    
    Review and land this stack in order:
    
    1. #27466 — trace exec-server JSON-RPC requests
    2. #27467 — record bounded connection, request, and process lifecycle
    metrics
    3. #27470 — observe remote registration and Noise rendezvous lifecycle
    **(this PR)**
    
    ## Validation
    
    - `just test -p codex-exec-server --lib` (149 passed)
    - `just test -p codex-cli --test exec_server` (4 passed)
    - `just argument-comment-lint`
    - `just bazel-lock-check`
    - `just fix -p codex-exec-server -p codex-cli`
    - `just fmt`
  • cli: rename sandbox permission profile flag (#30095)
    ## Why
    
    `codex sandbox` accepts a single named permissions profile, so the
    existing plural `--permissions-profile` spelling is misleading. The
    canonical flag and its help text should use the singular form without
    breaking scripts that already use the old spelling.
    
    ## What changed
    
    - Make `--permission-profile` the canonical flag for all sandbox
    backends.
    - Keep `--permissions-profile` as a hidden backwards-compatible alias.
    - Cover the canonical spelling, legacy alias, and help visibility with
    regression tests.
    
    ## Testing
    
    Ran `just c sandbox --help` and verified I saw:
    
    ```shell
      -P, --permission-profile <NAME>
              Named permissions profile to apply from the active configuration stack
    ```
  • [codex] Record exec-server lifecycle metrics (#27467)
    ## Summary
    
    - Record bounded connection, request, and process lifecycle metrics.
    - Report active gauges from callbacks on every collection, including
    delta exports.
    - Serialize active-count updates so concurrent starts and finishes
    cannot publish stale values.
    - Serialize process exit, explicit termination, and shutdown through the
    process registry so exactly one completion result wins.
    - Keep the implementation small with single-owner RAII guards and one
    real OTLP/HTTP integration test using the existing `wiremock`
    dependency.
    
    ## Root cause
    
    Process exit and session shutdown previously used cloned completion
    state. That avoided duplicate emission, but it duplicated lifecycle
    ownership and made the ordering harder to reason about. The process
    registry mutex already defines the lifecycle ordering, so the final
    implementation stores the metric guard and termination flag directly on
    the process entry. Whichever path claims the entry first owns the
    completion result.
    
    Production metric export uses delta temporality. Event-only synchronous
    gauge recordings disappear after the next collection when no count
    changes, so active counts now use observable callbacks that report
    current state on every collection.
    
    The cleanup also removes the constant `result="accepted"` connection
    tag, redundant route and response assertions, a custom HTTP collector,
    and fallback initialization machinery that did not add behavior.
    
    ## Stack
    
    Review and land this stack in order:
    
    1. #27466 — trace exec-server JSON-RPC requests
    2. #27467 — record bounded connection, request, and process lifecycle
    metrics **(this PR)**
    3. #27470 — observe remote registration and Noise rendezvous lifecycle
    
    ## Validation
    
    - `just test -p codex-exec-server --lib` (158 passed)
    - `just test -p codex-cli --test exec_server` (3 passed)
    - `just test -p codex-otel
    observable_gauge_is_collected_on_every_delta_snapshot` (1 passed)
    - `CARGO_BUILD_JOBS=1 just fix -p codex-otel -p codex-exec-server`
    - `just fmt`
    - `git diff --check`
  • [codex] Initialize exec-server OpenTelemetry at startup (#25019)
    ## Summary
    
    - Initialize stderr tracing and the configured OpenTelemetry provider
    for local and remote `codex exec-server` startup.
    - Instrument the local and remote server entrypoints with a root runtime
    span.
    - Keep raw Noise environment, registration, and stream identifiers out
    of exported spans while preserving them in local debug events.
    - Keep telemetry setup in a focused CLI module instead of growing the
    top-level command entrypoint.
    
    ## Stack
    
    - Previous: none (`#27058` has merged)
    - Next: #27466
    
    ## Validation
    
    - `just test -p codex-exec-server --lib` (139 passed)
    - `just test -p codex-cli --test exec_server` (3 passed)
    - `just bazel-lock-check`
    - `just fix -p codex-exec-server -p codex-cli`
    - `just fmt`
    
    ---------
    
    Co-authored-by: Richard Lee <richardlee@openai.com>
  • [login] revoke existing auth before starting login (#27674)
    ## Why
    
    `codex login` previously persisted newly issued OAuth credentials and
    only then attempted to revoke the superseded refresh token. The old
    credential must be revoked before a replacement browser or device-code
    flow starts, and successful login must not perform any post-login
    revocation attempt.
    
    ## What changed
    
    - Revoke and clear existing stored auth before browser or device-code
    CLI login begins.
    - Remove superseded-token detection and revocation from the shared token
    persistence path; successful login now only saves the new credentials.
    - Read the raw configured auth store during CLI cleanup so
    environment-provided auth cannot mask the stored refresh token.
    - Preserve `auto` storage fallback semantics when keyring deletion fails
    by clearing the fallback auth file.
    - Add a process-level CLI regression test that requires the revoke
    request to precede every device-login request and occur exactly once.
    
    If replacement login is canceled or fails, the previous local
    credentials have already been cleared. Remote revocation remains best
    effort, matching explicit logout behavior.
    
    ## Validation
    
    ### Process-level before/after reproduction
    
    I compiled the real `codex` CLI from the pre-fix parent (`14df0e8833`)
    and from the PR implementation (`25c002f23b`; the login behavior is
    unchanged at the current head), then ran the same device-code flow
    against a local HTTP mock OAuth authority.
    
    Each run:
    
    1. Used a fresh temporary `CODEX_HOME` configured with
    `cli_auth_credentials_store = "file"`.
    2. Seeded that temporary home with managed ChatGPT auth containing
    `old-access` and `old-refresh` tokens.
    3. Pointed `CODEX_REVOKE_TOKEN_URL_OVERRIDE` at the mock `/oauth/revoke`
    endpoint.
    4. Ran the compiled CLI as:
    
       ```shell
       CODEX_HOME=<temporary-home> \
         CODEX_REVOKE_TOKEN_URL_OVERRIDE=<mock-issuer>/oauth/revoke \
    <compiled-codex> login --device-auth --experimental_issuer <mock-issuer>
       ```
    
    5. Recorded every request received by the mock authority. The mock
    marked `new-access` valid when `/oauth/token` issued it and invalidated
    it if `/oauth/revoke` arrived afterward, reproducing the observed
    session-invalidating failure mode. After login exited, the harness also
    verified the persisted refresh token and probed a protected endpoint
    with `new-access`.
    
    | Build | Observed request order | CLI/persistence result | `new-access`
    probe |
    | --- | --- | --- | --- |
    | Pre-fix | `usercode → device token → OAuth token →
    revoke(old-refresh)` | Exit `0`; `new-refresh` persisted | `401` |
    | PR | `revoke(old-refresh) → usercode → device token → OAuth token` |
    Exit `0`; `new-refresh` persisted | `200` |
    
    The PR run therefore issued exactly one revocation request, before any
    request that initiated the replacement login, and issued no revocation
    after token exchange.
    
    ### Regression coverage
    
    
    `codex-rs/cli/tests/login.rs::device_login_revokes_existing_auth_before_requesting_new_tokens`
    runs the real first-party `codex` binary against a `wiremock` OAuth
    server with an isolated temporary `CODEX_HOME`. It asserts:
    
    - the exact request sequence is `/oauth/revoke`,
    `/api/accounts/deviceauth/usercode`, `/api/accounts/deviceauth/token`,
    then `/oauth/token`;
    - there is exactly one revoke request and its body contains
    `old-refresh` with the `refresh_token` hint;
    - the completed login persists `new-refresh`.
    
    Local validation:
    
    - `just test -p codex-login` — 130 passed
    - `just test -p codex-cli` — 280 passed, including the new process-level
    regression test
    - `just bazel-lock-check`
  • Add session delete commands in CLI and TUI (#27476)
    ## Summary
    
    The app server exposes `thread/delete`, but users cannot invoke it from
    the CLI or TUI. Because deletion is irreversible, the user-facing
    commands need deliberate confirmation and safer handling of name-based
    targets.
    
    - Add `codex delete <SESSION>` with interactive confirmation,
    restricting `--force` to UUID targets.
    - Resolve exact names across active and archived sessions, including
    renamed sessions, and validate prompted UUID targets before
    confirmation.
    - Add a `/delete` command with a confirmation popup that warns the
    current session and its subagent threads will be permanently deleted.
    
    ## Manual testing
    
    - Deleted by UUID with `--force` and verified the rollout, session-index
    entry, and database row were removed.
    - Exercised name-based confirmation for both cancellation and
    affirmative deletion; cancellation preserved the session and
    confirmation removed it.
    - Verified deletion refuses to proceed without `--force`, while
    `--force` rejects names, including duplicate names.
    - Verified duplicate-name confirmation displays the concrete UUID
    selected.
    - Deleted an archived session by name.
    - Verified an already-missing UUID fails before displaying a
    confirmation prompt.
    - Exercised `/delete` in the TUI: the popup defaults to No, cancellation
    preserves the session, and confirmation deletes the session and exits.
    - Verified that `codex delete` works for both archived and non-archived
    sessions.
  • Enforce configured network proxy in codex sandbox (#27035)
    ## Why
    
    `codex sandbox` can start a network proxy from a configured permission
    profile. Previously, sandbox-level containment was tied to managed
    network requirements rather than whether a proxy was actually active.
    This meant config-driven proxy policies were not consistently enforced
    as the sandbox's only network path.
    
    ## What changed
    
    - Enable proxy-only network containment whenever `codex sandbox` starts
    a network proxy.
    - Apply the same active-proxy check to the macOS and Linux sandbox
    paths.
    - Add a Linux regression test that verifies a sandboxed command cannot
    establish a direct connection while the configured proxy is active.
    
    ## Test plan
    
    - `just test -p codex-cli debug_sandbox::tests`
    - `sandbox_with_network_proxy_blocks_direct_loopback_access` runs on
    Linux to cover the config-driven proxy path end to end.
  • [plugins] Expose marketplace source in marketplace list JSON (#27009)
    ## Summary
    - Follow-up to #26417 and #26631
    - Add `marketplaceSource` to `codex plugin marketplace list --json`
    entries for configured marketplaces
    - Reuse the existing `marketplaceSource` shape from `codex plugin list
    --json`
    - Keep human-readable marketplace list output unchanged
    - Add CLI coverage for configured local and git marketplace sources
    
    Example:
    
    ```json
    {
      "marketplaces": [
        {
          "name": "debug",
          "root": "/path/to/.codex/.tmp/marketplaces/debug",
          "marketplaceSource": {
            "sourceType": "git",
            "source": "https://example.com/acme/agent-skills.git"
          }
        }
      ]
    }
    ```
    
    ## Validation
    - `just fmt`
    - `just fix -p codex-cli`
    - `just test -p codex-cli marketplace_list`
    - `just test -p codex-cli`
  • Add JSON output for plugin subcommands (#26631)
    ## Summary
    - Follow-up to #25330 and #26417
    - Add `--json` output for `codex plugin add` and `codex plugin remove`
    - Add `--json` output for `codex plugin marketplace
    add/list/upgrade/remove`
    - Keep existing human-readable output unchanged
    - Keep existing error handling/stderr behavior unchanged; `--json`
    changes successful stdout output only
    - Align marketplace add/remove JSON field names with the existing
    app-server protocol shape
    - Add CLI coverage for plugin and marketplace JSON outputs
    
    ## Validation
    - `just fmt`
    - `just fix -p codex-cli`
    - `just test -p codex-cli`
  • Expose configured marketplace source in plugin list JSON (#26417)
    ## Summary
    - Follow-up to #25330
    - Add `marketplaceSource` to `codex plugin list --json` entries for
    configured marketplaces
    - Keep the existing per-plugin `source` field unchanged; this still
    reports the local plugin source path
    - Include only the configured marketplace `sourceType` and `source` from
    `config.toml`
    - Keep human-readable output unchanged
    - Add CLI coverage for configured local and git marketplace sources
    
    Example:
    
    ```json
    {
      "source": {
        "source": "local",
        "path": "/path/to/.codex/.tmp/marketplaces/debug/plugins/sample"
      },
      "marketplaceSource": {
        "sourceType": "git",
        "source": "https://example.com/acme/agent-skills.git"
      }
    }
    ```
    
    ## Validation
    - `just fmt`
    - `just fix -p codex-cli`
    - `just test -p codex-cli plugin_list`
  • [codex] Add plugin list JSON output (#25330)
    ## Summary
    - add `--json` output to `codex plugin list` with `installed` and
    `available` arrays
    - add `--available` for JSON output only; using it without `--json` is
    rejected
    - keep the existing non-JSON table output unchanged
    - add CLI coverage for JSON installed/available output and the
    `--available`/`--json` requirement
    
    ## Validation
    - `just test -p codex-cli plugin_list`
    - `just fix -p codex-cli`
    - `git diff --check`
    
    Note: `just fmt` ran Rust formatting first, then failed in the Python
    ruff step because `openai-codex-cli-bin==0.132.0` has no wheel for this
    Linux platform.
  • Move memory state to a dedicated SQLite DB (#24591)
    ## Summary
    
    Generated memory rows and their stage-one/stage-two job state currently
    live in `state_5.sqlite` alongside thread metadata. That makes memory
    cleanup and regeneration share the main state schema even though those
    rows are memory-pipeline data and can be rebuilt independently from the
    durable thread records.
    
    This PR moves the memory-owned tables into a dedicated
    `memories_1.sqlite` runtime database while keeping thread metadata in
    `state_5.sqlite`.
    
    ## Changes
    
    - Adds a separate memories DB runtime, migrator, path helpers, telemetry
    kind, and Bazel compile data for `state/memory_migrations`.
    - Introduces `MemoryStore` behind `StateRuntime::memories()` and moves
    memory table/job operations onto that store.
    - Drops the old memory tables from the state DB and recreates their
    schema in `state/memory_migrations/0001_memories.sql`.
    - Updates memory startup, citation usage tracking, rollout pollution
    handling, `debug clear-memories`, and app-server `memory/reset` to
    operate through the memories DB.
    - Preserves cross-DB behavior by hydrating thread metadata from the
    state DB when selecting visible memory outputs and checking stage-one
    staleness.
    
    ## Verification
    
    - Added/updated `codex-state` tests for deleted-thread memory visibility
    and already-polluted phase-two enqueue behavior.
    - Updated `debug clear-memories`, app-server `memory/reset`, and
    memories startup tests to seed and assert memory rows through
    `memories_1.sqlite`.
  • Support OAuth options in codex mcp add (#24120)
    ## Summary
    - add `--oauth-client-id` and `--oauth-resource` options for streamable
    HTTP `codex mcp add` registrations
    - persist those options in MCP server config and use them during the
    immediate OAuth login flow
    - cover add-time serialization of both OAuth options in the CLI
    integration tests
    
    ## Testing
    - `just fmt`
    - `cargo test -p codex-cli`
    - `just fix -p codex-cli`
  • mcp: surface profile migration guidance under --profile (#23890)
    ## Why
    
    `codex --profile <name> mcp ...` should reach the same profile-v2
    migration guard as runtime commands. Otherwise legacy
    `[profiles.<name>]` users see the generic command-scope rejection
    instead of the existing guidance to move settings into
    `$CODEX_HOME/<name>.config.toml`.
    
    ## What
    
    - Allow `codex mcp` through the `--profile` subcommand gate.
    - Pass profile loader overrides into the MCP entry point only to
    validate profile-v2 migration when a profile is present.
    - Keep MCP add/remove/list/get/login/logout behavior otherwise
    unchanged; this does not add profile-scoped MCP server management.
    - Cover the legacy profile migration error for `codex --profile work mcp
    list`.
    
    ## Testing
    
    - `cargo test -p codex-cli`
  • feat(plugins): tabulate plugin list output (#23727)
    ## Summary
    - render `codex plugin list` as one table per marketplace with the
    marketplace manifest path shown above each table
    - surface the installed plugin version in the CLI output by threading
    `installed_version` through marketplace listing state
    - narrow the system-root exemption so only known bundled/runtime
    marketplaces skip missing-manifest failures, and keep `VERSION` empty
    for cached-but-unconfigured plugins
    
    ## Rationale
    The plugin list UX was hard to scan as a flat list and did not show
    which installed version was active. This change makes the CLI output
    easier to read in the real multi-marketplace case, keeps the plugin path
    visible, fixes the Sapphire regression where bundled/runtime marketplace
    roots were blocking `plugin list`, and addresses the two review findings
    that came out of the follow-up deep review.
    
    ## Key Decisions
    - kept the CLI output grouped per marketplace instead of one global
    table so the marketplace path can live with the rows it owns
    - kept `VERSION` as the installed version, which means it is empty until
    a plugin is actually installed
    - handled the bundled/runtime regression in the CLI snapshot validation
    path rather than widening app-server protocol or changing marketplace
    loading behavior
    - narrowed the exemption to known system marketplace names plus expected
    system paths, so user-configured marketplaces under those directories
    still fail loudly
    - gated `installed_version` on actual installed state so `VERSION`
    cannot show stale cache state for `not installed` rows
    
    ## Validation
    - `just fmt`
    - Sapphire: `cargo test -p codex-cli --test plugin_cli` (`14 passed; 0
    failed`)
    - Sapphire smoke test: bundled/runtime roots still work
      - `cargo run -q -p codex-cli -- plugin add sample@debug`
      - `cargo run -q -p codex-cli -- plugin list`
    - verified the bundled/runtime-root scenario no longer errors and shows
    the expected marketplace table output
    - Sapphire smoke test: custom marketplace under bundled path still
    errors
    - verified `failed to load configured marketplace snapshot(s)` for
    `custom-marketplace`
    - Sapphire smoke test: cached-but-unconfigured plugin hides version
    - verified `sample@debug not installed` renders with an empty `VERSION`
    column
    
    ## Sample Output
    ```text
    /tmp/custom-marketplace/plugin.json
    NAME          VERSION  STATUS         DESCRIPTION
    sample@debug  1.0.0    enabled        Debug sample plugin
    other@local            not installed  Local development plugin
    ```
  • cli: add strict config to exec-server (#23719)
    ## Why
    
    PR #20559 added opt-in strict config parsing to the config-loading
    command surfaces, but `codex exec-server` was left out. That meant
    `codex exec-server --strict-config` was rejected even though the command
    can load config for remote registration, and local server startup had no
    way to fail fast on misspelled config keys.
    
    ## What Changed
    
    - Added `--strict-config` to `codex exec-server`.
    - Allowed root-level inheritance from `codex --strict-config
    exec-server`.
    - Validated config before local exec-server startup when strict mode is
    requested.
    - Reused the loaded strict-config-aware config for remote exec-server
    registration auth.
    - Added CLI coverage showing `codex exec-server --strict-config` rejects
    unknown config fields.
    
    ## Verification
    
    - `cargo test -p codex-cli`
    - New integration test:
    `strict_config_rejects_unknown_config_fields_for_exec_server`
    
    ## Documentation
    
    Any strict-config command list on developers.openai.com/codex should
    include `codex exec-server` with the other supported config-loading
    entry points.
  • [codex] add plugin marketplace CLI commands (#21396)
    ## Why
    
    Plugin CLI installs should behave more like `apt-get install`:
    configured marketplaces are the only install sources, the local
    marketplace snapshot is the package index used at install time, and
    `plugins/cache` is only a cache of already-downloaded plugin bytes.
    
    That distinction matters once marketplaces and plugins have auth or
    availability state. A repo-local marketplace manifest or leftover cached
    plugin artifact should not silently become an install source unless the
    marketplace was explicitly configured and its readable snapshot still
    authorizes the plugin.
    
    ## What Changed
    
    - add CLI commands to list configured marketplaces and add, list, or
    remove marketplace plugins
    - accept stable `plugin@marketplace` ids for add/remove while preserving
    the explicit `--marketplace` form
    - restrict `codex plugin add` and `codex plugin list` to configured
    marketplaces instead of also discovering current-working-directory
    marketplace roots
    - fail `codex plugin add` and `codex plugin list` when a configured
    marketplace snapshot is missing or malformed instead of treating it as
    an empty source or a generic plugin miss
    - preserve marketplace snapshot semantics: a configured local/Git
    marketplace snapshot can authorize installs without consulting the
    original upstream source
    - allow `plugins/cache` reuse only after configured marketplace
    resolution succeeds
    - keep removal resilient after marketplace deletion or drift and ignore
    malformed marketplace config entries in listing
    
    ## Commands Added
    
    - `codex plugin add <plugin>@<marketplace>`
    - `codex plugin add <plugin> --marketplace <marketplace>`
    - `codex plugin list`
    - `codex plugin list --marketplace <marketplace>`
    - `codex plugin remove <plugin>@<marketplace>`
    - `codex plugin remove <plugin> --marketplace <marketplace>`
    - `codex plugin marketplace add <source>`
    - `codex plugin marketplace add <source> --ref <ref>`
    - `codex plugin marketplace add <source> --sparse <path>`
    - `codex plugin marketplace list`
    - `codex plugin marketplace upgrade`
    - `codex plugin marketplace upgrade <marketplace>`
    - `codex plugin marketplace remove <marketplace>`
    
    ## CLI Help Output
    
    <details>
    <summary><code>codex plugin --help</code></summary>
    
    ```text
    Manage Codex plugins
    
    Usage: codex plugin [OPTIONS] <COMMAND>
    
    Commands:
      add          Install a plugin from a configured marketplace snapshot
      list         List plugins available from configured marketplace snapshots
      marketplace  Add, list, upgrade, or remove configured plugin marketplaces
      remove       Remove an installed plugin from local config and cache
      help         Print this message or the help of the given subcommand(s)
    ```
    
    </details>
    
    <details>
    <summary><code>codex plugin add --help</code></summary>
    
    ```text
    Install a plugin from a configured marketplace snapshot.
    
    Pass either `PLUGIN@MARKETPLACE` or pass `PLUGIN` with `--marketplace MARKETPLACE`.
    
    Usage: codex plugin add [OPTIONS] <PLUGIN[@MARKETPLACE]>
    
    Arguments:
      <PLUGIN[@MARKETPLACE]>
              Plugin selector to install: either PLUGIN@MARKETPLACE or PLUGIN with --marketplace
    
    Options:
      -m, --marketplace <MARKETPLACE>
              Configured marketplace name to use when PLUGIN does not include @MARKETPLACE
    
    Examples:
      codex plugin add sample@debug
      codex plugin add sample --marketplace debug
    ```
    
    </details>
    
    <details>
    <summary><code>codex plugin list --help</code></summary>
    
    ```text
    List plugins available from configured marketplace snapshots
    
    Usage: codex plugin list [OPTIONS]
    
    Options:
      -m, --marketplace <MARKETPLACE>
              Only list plugins from this configured marketplace name
    
    Examples:
      codex plugin list
      codex plugin list --marketplace debug
    ```
    
    </details>
    
    <details>
    <summary><code>codex plugin remove --help</code></summary>
    
    ```text
    Remove an installed plugin from local config and cache.
    
    Pass either `PLUGIN@MARKETPLACE` or pass `PLUGIN` with `--marketplace MARKETPLACE`.
    
    Usage: codex plugin remove [OPTIONS] <PLUGIN[@MARKETPLACE]>
    
    Arguments:
      <PLUGIN[@MARKETPLACE]>
              Plugin selector to remove: either PLUGIN@MARKETPLACE or PLUGIN with --marketplace
    
    Options:
      -m, --marketplace <MARKETPLACE>
              Marketplace name to use when PLUGIN does not include @MARKETPLACE
    
    Examples:
      codex plugin remove sample@debug
      codex plugin remove sample --marketplace debug
    ```
    
    </details>
    
    <details>
    <summary><code>codex plugin marketplace --help</code></summary>
    
    ```text
    Add, list, upgrade, or remove configured plugin marketplaces
    
    Usage: codex plugin marketplace [OPTIONS] <COMMAND>
    
    Commands:
      add      Add a local or Git marketplace to the configured marketplace sources
      list     List configured marketplace names and their local snapshot roots
      upgrade  Refresh configured Git marketplace snapshots
      remove   Remove a configured marketplace source by name
    ```
    
    </details>
    
    <details>
    <summary><code>codex plugin marketplace add --help</code></summary>
    
    ```text
    Add a local or Git marketplace to the configured marketplace sources
    
    Usage: codex plugin marketplace add [OPTIONS] <SOURCE>
    
    Arguments:
      <SOURCE>
              Marketplace source: a local path, owner/repo[@ref], HTTPS Git URL, or SSH Git URL
    
    Options:
          --ref <REF>
              Git ref to fetch for Git marketplace sources
    
          --sparse <PATH>
              Sparse checkout path for Git marketplace sources. Can be repeated
    
    Examples:
      codex plugin marketplace add ./path/to/marketplace
      codex plugin marketplace add owner/repo --ref main
      codex plugin marketplace add https://github.com/owner/repo --sparse plugins/foo
    ```
    
    </details>
    
    <details>
    <summary><code>codex plugin marketplace list --help</code></summary>
    
    ```text
    List configured marketplace names and their local snapshot roots
    
    Usage: codex plugin marketplace list [OPTIONS]
    ```
    
    </details>
    
    <details>
    <summary><code>codex plugin marketplace upgrade --help</code></summary>
    
    ```text
    Refresh configured Git marketplace snapshots.
    
    Omit MARKETPLACE_NAME to upgrade all configured Git marketplaces.
    
    Usage: codex plugin marketplace upgrade [OPTIONS] [MARKETPLACE_NAME]
    
    Arguments:
      [MARKETPLACE_NAME]
              Optional configured marketplace name to upgrade. Omit to upgrade all Git marketplaces
    
    Examples:
      codex plugin marketplace upgrade
      codex plugin marketplace upgrade debug
    ```
    
    </details>
    
    <details>
    <summary><code>codex plugin marketplace remove --help</code></summary>
    
    ```text
    Remove a configured marketplace source by name
    
    Usage: codex plugin marketplace remove [OPTIONS] <MARKETPLACE_NAME>
    
    Arguments:
      <MARKETPLACE_NAME>
              Configured marketplace name to remove
    
    Example:
      codex plugin marketplace remove debug
    ```
    
    </details>
    
    ## Public Semantics
    
    - `codex plugin add <plugin>@<marketplace>` succeeds only when
    `<marketplace>` is configured and its local marketplace snapshot
    contains `<plugin>`
    - repo-local marketplaces are not install sources until the user runs
    `codex plugin marketplace add ...`
    - configured marketplace snapshots must be readable; missing or
    malformed snapshots fail the CLI operation rather than silently falling
    through to cache or empty results
    - cached plugin artifacts can satisfy reinstall only when the configured
    marketplace snapshot still authorizes that plugin
    - cached plugin artifacts alone never make a plugin installable
    
    ## Tests
    
    - `cargo test -p codex-cli --test plugin_cli`
    - `cargo clippy -p codex-cli --tests -- -D warnings`
    - `cargo test -p codex-cli`
    - `git diff --check`
    - `just bazel-lock-update`
    - `just bazel-lock-check`
  • config: add strict config parsing (#20559)
    ## Why
    
    Codex intentionally ignores unknown `config.toml` fields by default so
    older and newer config files keep working across versions. That leniency
    also makes typo detection hard because misspelled or misplaced keys
    disappear silently.
    
    This change adds an opt-in strict config mode so users and tooling can
    fail fast on unrecognized config fields without changing the default
    permissive behavior.
    
    This feature is possible because `serde_ignored` exposes the exact
    signal Codex needs: it lets Codex run ordinary Serde deserialization
    while recording fields Serde would otherwise ignore. That avoids
    requiring `#[serde(deny_unknown_fields)]` across every config type and
    keeps strict validation opt-in around the existing config model.
    
    ## What Changed
    
    ### Added strict config validation
    
    - Added `serde_ignored`-based validation for `ConfigToml` in
    `codex-rs/config/src/strict_config.rs`.
    - Combined `serde_ignored` with `serde_path_to_error` so strict mode
    preserves typed config error paths while also collecting fields Serde
    would otherwise ignore.
    - Added strict-mode validation for unknown `[features]` keys, including
    keys that would otherwise be accepted by `FeaturesToml`'s flattened
    boolean map.
    - Kept typed config errors ahead of ignored-field reporting, so
    malformed known fields are reported before unknown-field diagnostics.
    - Added source-range diagnostics for top-level and nested unknown config
    fields, including non-file managed preference source names.
    
    ### Kept parsing single-pass per source
    
    - Reworked file and managed-config loading so strict validation reuses
    the already parsed `TomlValue` for that source.
    - For actual config files and managed config strings, the loader now
    reads once, parses once, and validates that same parsed value instead of
    deserializing multiple times.
    - Validated `-c` / `--config` override layers with the same
    base-directory context used for normal relative-path resolution, so
    unknown override keys are still reported when another override contains
    a relative path.
    
    ### Scoped `--strict-config` to config-heavy entry points
    
    - Added support for `--strict-config` on the main config-loading entry
    points where it is most useful:
      - `codex`
      - `codex resume`
      - `codex fork`
      - `codex exec`
      - `codex review`
      - `codex mcp-server`
      - `codex app-server` when running the server itself
      - the standalone `codex-app-server` binary
      - the standalone `codex-exec` binary
    - Commands outside that set now reject `--strict-config` early with
    targeted errors instead of accepting it everywhere through shared CLI
    plumbing.
    - `codex app-server` subcommands such as `proxy`, `daemon`, and
    `generate-*` are intentionally excluded from the first rollout.
    - When app-server strict mode sees invalid config, app-server exits with
    the config error instead of logging a warning and continuing with
    defaults.
    - Introduced a dedicated `ReviewCommand` wrapper in `codex-rs/cli`
    instead of extending shared `ReviewArgs`, so `--strict-config` stays on
    the outer config-loading command surface and does not become part of the
    reusable review payload used by `codex exec review`.
    
    ### Coverage
    
    - Added tests for top-level and nested unknown config fields, unknown
    `[features]` keys, typed-error precedence, source-location reporting,
    and non-file managed preference source names.
    - Added CLI coverage showing invalid `--enable`, invalid `--disable`,
    and unknown `-c` overrides still error when `--strict-config` is
    present, including compound-looking feature names such as
    `multi_agent_v2.subagent_usage_hint_text`.
    - Added integration coverage showing both `codex app-server
    --strict-config` and standalone `codex-app-server --strict-config` exit
    with an error for unknown config fields instead of starting with
    fallback defaults.
    - Added coverage showing unsupported command surfaces reject
    `--strict-config` with explicit errors.
    
    ## Example Usage
    
    Run Codex with strict config validation enabled:
    
    ```shell
    codex --strict-config
    ```
    
    Strict config mode is also available on the supported config-heavy
    subcommands:
    
    ```shell
    codex --strict-config exec "explain this repository"
    codex review --strict-config --uncommitted
    codex mcp-server --strict-config
    codex app-server --strict-config --listen off
    codex-app-server --strict-config --listen off
    ```
    
    For example, if `~/.codex/config.toml` contains a typo in a key name:
    
    ```toml
    model = "gpt-5"
    approval_polic = "on-request"
    ```
    
    then `codex --strict-config` reports the misspelled key instead of
    silently ignoring it. The path is shortened to `~` here for readability:
    
    ```text
    $ codex --strict-config
    Error loading config.toml:
    ~/.codex/config.toml:2:1: unknown configuration field `approval_polic`
      |
    2 | approval_polic = "on-request"
      | ^^^^^^^^^^^^^^
    ```
    
    Without `--strict-config`, Codex keeps the existing permissive behavior
    and ignores the unknown key.
    
    Strict config mode also validates ad-hoc `-c` / `--config` overrides:
    
    ```text
    $ codex --strict-config -c foo=bar
    Error: unknown configuration field `foo` in -c/--config override
    
    $ codex --strict-config -c features.foo=true
    Error: unknown configuration field `features.foo` in -c/--config override
    ```
    
    Invalid feature toggles are rejected too, including values that look
    like nested config paths:
    
    ```text
    $ codex --strict-config --enable does_not_exist
    Error: Unknown feature flag: does_not_exist
    
    $ codex --strict-config --disable does_not_exist
    Error: Unknown feature flag: does_not_exist
    
    $ codex --strict-config --enable multi_agent_v2.subagent_usage_hint_text
    Error: Unknown feature flag: multi_agent_v2.subagent_usage_hint_text
    ```
    
    Unsupported commands reject the flag explicitly:
    
    ```text
    $ codex --strict-config cloud list
    Error: `--strict-config` is not supported for `codex cloud`
    ```
    
    ## Verification
    
    The `codex-cli` `strict_config` tests cover invalid `--enable`, invalid
    `--disable`, the compound `multi_agent_v2.subagent_usage_hint_text`
    case, unknown `-c` overrides, app-server strict startup failure through
    `codex app-server`, and rejection for unsupported commands such as
    `codex cloud`, `codex mcp`, `codex remote-control`, and `codex
    app-server proxy`.
    
    The config and config-loader tests cover unknown top-level fields,
    unknown nested fields, unknown `[features]` keys, source-location
    reporting, non-file managed config sources, and `-c` validation for keys
    such as `features.foo`.
    
    The app-server test suite covers standalone `codex-app-server
    --strict-config` startup failure for an unknown config field.
    
    ## Documentation
    
    The Codex CLI docs on developers.openai.com/codex should mention
    `--strict-config` as an opt-in validation mode for supported
    config-heavy entry points once this ships.
  • Rename agent identity login surface to access token (#21059)
    ## Why
    The external startup/login surface for this auth path should talk about
    an access token instead of exposing the internal Agent Identity
    terminology. Users should pass `CODEX_ACCESS_TOKEN` or pipe a token into
    `codex login --with-access-token`; the old external env/flag spellings
    are removed so there is only one supported user-facing path.
    
    ## What Changed
    - Added `CODEX_ACCESS_TOKEN` as the supported environment variable for
    this auth path.
    - Added `codex login --with-access-token` as the supported stdin-based
    login command.
    - Removed the legacy `CODEX_AGENT_IDENTITY` env-var fallback and hidden
    `--with-agent-identity` CLI alias.
    - Updated CLI error, status, and stdin prompts to use access-token
    language.
    - Added coverage for access-token env loading, CLI login failure
    behavior, and renamed login status text.
    
    ## Validation
    - `cargo test -p codex-login`
    - `cargo test -p codex-cli`
    - `just fix -p codex-login`
    - `just fix -p codex-cli`
  • Add codex update command (#19933)
    ## Why
    
    Addresses #9274
    
    Running `codex update` currently starts an interactive Codex session
    with `update` as the prompt. That is a rough edge for users who expect a
    direct self-update command after seeing the existing update notice, and
    it forces them to copy the suggested package-manager command manually.
    
    ## What changed
    
    - Added a top-level `codex update` subcommand.
    - Reused the existing install-channel detection and update command
    runner that the TUI already uses for update prompts.
    - Exposed the update-action lookup from `codex-tui` so the CLI can
    invoke the same behavior.
    - Added CLI coverage to ensure `codex update` is parsed as a subcommand
    instead of becoming an interactive prompt.
    
    ## Verification
    
    - `cargo test -p codex-cli`
    - `cargo test -p codex-tui update_action::tests`
  • feat: load AgentIdentity from JWT login/env (#18904)
    ## Summary
    
    This PR lets programmatic AgentIdentity users provide one token through
    either stdin login or environment auth.
    
    `codex login --with-agent-identity` reads an Agent Identity JWT from
    stdin, validates that it has the required claims, and stores that token
    as the `agent_identity` value in `auth.json`. The file format is
    token-only; the decoded account and key fields are runtime state, not
    hand-authored auth.json fields.
    
    The Agent Identity JWT claim shape and decoder live in
    `codex-agent-identity`; `codex-login` only owns env/storage precedence
    and conversion into `CodexAuth::AgentIdentity`.
    
    When env auth is enabled, `CODEX_AGENT_IDENTITY` can provide the same
    JWT without writing auth state to disk. `CODEX_API_KEY` still wins if
    both env vars are set.
    
    Reference old stack: https://github.com/openai/codex/pull/17387/changes
    Reference JWT/env stack: https://github.com/openai/codex/pull/18176
    
    ## Stack
    
    1. https://github.com/openai/codex/pull/18757: full revert
    2. https://github.com/openai/codex/pull/18871: isolated Agent Identity
    crate
    3. https://github.com/openai/codex/pull/18785: explicit AgentIdentity
    auth mode and startup task allocation
    4. https://github.com/openai/codex/pull/18811: migrate Codex backend
    auth callsites through AuthProvider
    5. This PR: accept AgentIdentity JWTs through login/env
    
    ## Testing
    
    Tests: targeted login and Agent Identity crate tests, CLI checks, scoped
    formatter/linter cleanup, and CI.
    
    ---------
    
    Co-authored-by: Shijie Rao <shijie.rao@openai.com>
  • Move marketplace add/remove and startup sync out of core. (#19099)
    Move more things to core-plugins.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Stabilize debug clear memories integration test (#18858)
    ## Why
    
    `debug_clear_memories_resets_state_and_removes_memory_dir` can be flaky
    because the test drops its `sqlx::SqlitePool` immediately before
    invoking `codex debug clear-memories`. Dropping the pool does not wait
    for all SQLite connections to close, so the CLI can race with still-open
    test connections.
    
    ## What changed
    
    - Await `pool.close()` before spawning `codex debug clear-memories`.
    - Close the reopened verification pool before the temp `CODEX_HOME` is
    torn down.
    
    ## Verification
    
    - `cargo test -p codex-cli --test debug_clear_memories
    debug_clear_memories_resets_state_and_removes_memory_dir`
  • [5/6] Wire executor-backed MCP stdio (#18212)
    ## Summary
    - Add the executor-backed RMCP stdio transport.
    - Wire MCP stdio placement through the executor environment config.
    - Cover local and executor-backed stdio paths with the existing MCP test
    helpers.
    
    ## Stack
    ```text
    o  #18027 [6/6] Fail exec client operations after disconnect
    │
    @  #18212 [5/6] Wire executor-backed MCP stdio
    │
    o  #18087 [4/6] Abstract MCP stdio server launching
    │
    o  #18020 [3/6] Add pushed exec process events
    │
    o  #18086 [2/6] Support piped stdin in exec process API
    │
    o  #18085 [1/6] Add MCP server environment config
    │
    o  main
    ```
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • [codex] Add marketplace remove command and shared logic (#17752)
    ## Summary
    
    Move the marketplace remove implementation into shared core logic so
    both the CLI command and follow-up app-server RPC can reuse the same
    behavior.
    
    This change:
    - adds a shared `codex_core::plugins::remove_marketplace(...)` flow
    - moves validation, config removal, and installed-root deletion out of
    the CLI
    - keeps the CLI as a thin wrapper over the shared implementation
    - adds focused core coverage for the shared remove path
    
    ## Validation
    
    - `just fmt`
    - focused local coverage for the shared remove path
    - heavier follow-up validation deferred to stacked PR CI
  • Move marketplace add under plugin command (#18116)
    ## Summary
    - move the marketplace add CLI from `codex marketplace add` to `codex
    plugin marketplace add`
    - keep marketplace config overrides working through the nested plugin
    command
    - reject `--sparse` for local marketplace directory sources before the
    local-source install path bypasses git-source validation
    
    ## Validation
    - `just fmt`
    - `git diff --check`
    - `cargo test -p codex-cli`
    - `cargo test -p codex-core marketplace_add -- --nocapture`
    - `cargo test -p codex-core
    install_plugin_updates_config_with_relative_path_and_plugin_key --
    --nocapture`
    - `xli-test-marketplace-cli` local isolated matrix: `T1`, `L1`-`L10`
  • chore: unify memory drop endpoints (#18134)
    Unify all the memories drop behind a single implementation that drops
    both the main memories and the extensions
  • [codex] Support local marketplace sources (#17756)
    ## Summary
    
    - Port marketplace source support into the shared core marketplace-add
    flow
    - Support local marketplace directory sources
    - Support direct `marketplace.json` URL sources
    - Persist the new source types in config/schema and cover them in CLI
    and app-server tests
    
    ## Validation
    
    - `cargo test -p codex-core marketplace_add`
    - `cargo test -p codex-cli marketplace_add`
    - `cargo test -p codex-app-server marketplace_add`
    - `just write-config-schema`
    - `just fmt`
    - `just fix -p codex-core`
    - `just fix -p codex-cli`
    
    ## Context
    
    Current `main` moved marketplace-add behavior into shared core code and
    still assumed only git-backed sources. This change keeps that structure
    but restores support for local directories and direct manifest URLs in
    the shared path.
  • Stabilize marketplace add local source test (#17424)
    ## Summary
    - Update the marketplace add local-source integration test to pass an
    explicit relative local path.
    - Keep the change test-only; no CLI source parsing behavior changes.
    
    ## Tests
    - cargo fmt -p codex-cli
    - cargo test -p codex-cli --test marketplace_add
    
    ## Impact
    - Production behavior is unchanged.
    - No impact to feedback upload logic, DAGs, exports, or downstream
    pipelines.
    
    Co-authored-by: Codex <noreply@openai.com>
  • Add marketplace command (#17087)
    Added a new top-level `codex marketplace add` command for installing
    plugin marketplaces into Codex’s local marketplace cache.
    
    This change adds source parsing for local directories, GitHub shorthand,
    and git URLs, supports optional `--ref` and git-only `--sparse` checkout
    paths, stages the source in a temp directory, validates the marketplace
    manifest, and installs it under
    `$CODEX_HOME/marketplaces/<marketplace-name>`
    
    Included tests cover local install behavior in the CLI and marketplace
    discovery from installed roots in core. Scoped formatting and fix passes
    were run, and targeted CLI/core tests passed.
  • [codex] Remove codex-core config type shim (#16529)
    ## Why
    
    This finishes the config-type move out of `codex-core` by removing the
    temporary compatibility shim in `codex_core::config::types`. Callers now
    depend on `codex-config` directly, which keeps these config model types
    owned by the config crate instead of re-expanding `codex-core` as a
    transitive API surface.
    
    ## What Changed
    
    - Removed the `codex-rs/core/src/config/types.rs` re-export shim and the
    `core::config::ApprovalsReviewer` re-export.
    - Updated `codex-core`, `codex-cli`, `codex-tui`, `codex-app-server`,
    `codex-mcp-server`, and `codex-linux-sandbox` call sites to import
    `codex_config::types` directly.
    - Added explicit `codex-config` dependencies to downstream crates that
    previously relied on the `codex-core` re-export.
    - Regenerated `codex-rs/core/config.schema.json` after updating the
    config docs path reference.
  • feat: add debug clear-memories command to hard-wipe memories state (#13085)
    #### what
    adds a `codex debug clear-memories` command to help with clearing all
    memories state from disk, sqlite db, and marking threads as
    `memory_mode=disabled` so they don't get resummarized when the
    `memories` feature is re-enabled.
    
    #### tests
    add tests
  • fix: sort codex features list alphabetically (#12944)
    ## Why
    
    `codex features list` currently prints features in declaration order
    from `codex_core::features::FEATURES`. That makes the output harder to
    scan when looking for a specific flag, and the order can change for
    reasons unrelated to the CLI.
    
    ## What changed
    
    - Sort the `codex features list` rows by feature key before printing
    them in `codex-rs/cli/src/main.rs`.
    - Add an integration test in `codex-rs/cli/tests/features.rs` that runs
    `codex features list` and asserts the feature-name column is
    alphabetized.
    
    ## Verification
    
    - Added `features_list_is_sorted_alphabetically_by_feature_name`.
    - Ran `cargo test -p codex-cli`.
  • Add features enable/disable subcommands (#10180)
    ## Summary
    - add `codex features enable <feature>` and `codex features disable
    <feature>`
    - persist feature flag changes to `config.toml` (respecting profile)
    - print the under-development feature warning when enabling prerelease
    features
    - keep `features list` behavior unchanged and add unit/integration tests
    
    ## Testing
    - cargo test -p codex-cli
  • Propagate MCP disabled reason (#9207)
    Indicate why MCP servers are disabled when they are disabled by
    requirements:
    
    ```
    ➜  codex git:(main) ✗ just codex mcp list
    cargo run --bin codex -- "$@"
        Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.27s
         Running `target/debug/codex mcp list`
    Name         Command          Args  Env  Cwd  Status                                                                  Auth
    docs         docs-mcp         -     -    -    disabled: requirements (MDM com.openai.codex:requirements_toml_base64)  Unsupported
    hello_world  hello-world-mcp  -     -    -    disabled: requirements (MDM com.openai.codex:requirements_toml_base64)  Unsupported
    
    ➜  codex git:(main) ✗ just c
    cargo run --bin codex -- "$@"
        Finished `dev` profile [unoptimized + debuginfo] target(s) in 0.90s
         Running `target/debug/codex`
    ╭─────────────────────────────────────────────╮
    │ >_ OpenAI Codex (v0.0.0)                    │
    │                                             │
    │ model:     gpt-5.2 xhigh   /model to change │
    │ directory: ~/code/codex/codex-rs            │
    ╰─────────────────────────────────────────────╯
    
    /mcp
    
    🔌  MCP Tools
    
      • No MCP tools available.
    
      • docs (disabled)
        • Reason: requirements (MDM com.openai.codex:requirements_toml_base64)
    
      • hello_world (disabled)
        • Reason: requirements (MDM com.openai.codex:requirements_toml_base64)
    ```
  • feat: add justification arg to prefix_rule() in *.rules (#8751)
    Adds an optional `justification` parameter to the `prefix_rule()`
    execpolicy DSL so policy authors can attach human-readable rationale to
    a rule. That justification is propagated through parsing/matching and
    can be surfaced to the model (or approval UI) when a command is blocked
    or requires approval.
    
    When a command is rejected (or gated behind approval) due to policy, a
    generic message makes it hard for the model/user to understand what went
    wrong and what to do instead. Allowing policy authors to supply a short
    justification improves debuggability and helps guide the model toward
    compliant alternatives.
    
    Example:
    
    ```python
    prefix_rule(
        pattern = ["git", "push"],
        decision = "forbidden",
        justification = "pushing is blocked in this repo",
    )
    ```
    
    If Codex tried to run `git push origin main`, now the failure would
    include:
    
    ```
    `git push origin main` rejected: pushing is blocked in this repo
    ```
    
    whereas previously, all it was told was:
    
    ```
    execpolicy forbids this command
    ```
  • feat: introduce codex-utils-cargo-bin as an alternative to assert_cmd::Command (#8496)
    This PR introduces a `codex-utils-cargo-bin` utility crate that
    wraps/replaces our use of `assert_cmd::Command` and
    `escargot::CargoBuild`.
    
    As you can infer from the introduction of `buck_project_root()` in this
    PR, I am attempting to make it possible to build Codex under
    [Buck2](https://buck2.build) as well as `cargo`. With Buck2, I hope to
    achieve faster incremental local builds (largely due to Buck2's
    [dice](https://buck2.build/docs/insights_and_knowledge/modern_dice/)
    build strategy, as well as benefits from its local build daemon) as well
    as faster CI builds if we invest in remote execution and caching.
    
    See
    https://buck2.build/docs/getting_started/what_is_buck2/#why-use-buck2-key-advantages
    for more details about the performance advantages of Buck2.
    
    Buck2 enforces stronger requirements in terms of build and test
    isolation. It discourages assumptions about absolute paths (which is key
    to enabling remote execution). Because the `CARGO_BIN_EXE_*` environment
    variables that Cargo provides are absolute paths (which
    `assert_cmd::Command` reads), this is a problem for Buck2, which is why
    we need this `codex-utils-cargo-bin` utility.
    
    My WIP-Buck2 setup sets the `CARGO_BIN_EXE_*` environment variables
    passed to a `rust_test()` build rule as relative paths.
    `codex-utils-cargo-bin` will resolve these values to absolute paths,
    when necessary.
    
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/8496).
    * #8498
    * __->__ #8496
  • fix: policy/*.codexpolicy -> rules/*.rules (#7888)
    We decided that `*.rules` is a more fitting (and concise) file extension
    than `*.codexpolicy`, so we are changing the file extension for the
    "execpolicy" effort. We are also changing the subfolder of `$CODEX_HOME`
    from `policy` to `rules` to match.
    
    This PR updates the in-repo docs and we will update the public docs once
    the next CLI release goes out.
    
    Locally, I created `~/.codex/rules/default.rules` with the following
    contents:
    
    ```
    prefix_rule(pattern=["gh", "pr", "view"])
    ```
    
    And then I asked Codex to run:
    
    ```
    gh pr view 7888 --json title,body,comments
    ```
    
    and it was able to!
  • Refactor execpolicy fallback evaluation (#7544)
    ## Refactor of the `execpolicy` crate
    
    To illustrate why we need this refactor, consider an agent attempting to
    run `apple | rm -rf ./`. Suppose `apple` is allowed by `execpolicy`.
    Before this PR, `execpolicy` would consider `apple` and `pear` and only
    render one rule match: `Allow`. We would skip any heuristics checks on
    `rm -rf ./` and immediately approve `apple | rm -rf ./` to run.
    
    To fix this, we now thread a `fallback` evaluation function into
    `execpolicy` that runs when no `execpolicy` rules match a given command.
    In our example, we would run `fallback` on `rm -rf ./` and prevent
    `apple | rm -rf ./` from being run without approval.
  • execpolicycheck command in codex cli (#7012)
    adding execpolicycheck tool onto codex cli
    
    this is useful for validating policies (can be multiple) against
    commands.
    
    it will also surface errors in policy syntax:
    <img width="1150" height="281" alt="Screenshot 2025-11-19 at 12 46
    21 PM"
    src="https://github.com/user-attachments/assets/8f99b403-564c-4172-acc9-6574a8d13dc3"
    />
    
    this PR also changes output format when there's no match in the CLI.
    instead of returning the raw string `noMatch`, we return
    `{"noMatch":{}}`
    
    this PR is a rewrite of: https://github.com/openai/codex/pull/6932 (due
    to the numerous merge conflicts present in the original PR)
    
    ---------
    
    Co-authored-by: Michael Bolin <mbolin@openai.com>
  • chore: config editor (#5878)
    The goal is to have a single place where we actually write files
    
    In a follow-up PR, will move everything config related in a dedicated
    module and move the helpers in a dedicated file