Commit Graph

1136 Commits

  • [tool_suggest] Improve tool_suggest triggering conditions. (#20091)
    ## Summary
    - Tighten `tool_suggest` guidance so it prefers explicit plugin install
    requests, while still allowing a connector install when the relevant
    plugin is already installed and a needed connector from that plugin is
    missing.
    - Tell the model not to call `tool_suggest` in parallel with other
    tools.
    
    ## Testing
    - `cargo test -p codex-tools tool_suggest`
    - `cargo test -p codex-core tool_suggest`
  • fix: handle deferred network proxy denials (#19184)
    ## Why
    
    This bug is exposed by Guardian/auto-review approvals. With the managed
    network proxy enabled, a blocked network request can be reported back
    through the network approval service as an approval denial after the
    command has already started. Before this change, the shell and unified
    exec runtimes registered those network approval calls, but did not have
    a way to observe an async proxy denial as a cancellation/failure signal
    for the running process.
    
    The result was confusing: Guardian/auto-review could correctly deny
    network access, but the command path could keep running or unregister
    the approval without surfacing the denial as the command failure.
    
    ## What Changed
    
    - `NetworkApprovalService` now attaches a cancellation token to active
    and deferred network approvals.
    - Proxy-denial outcomes are recorded only for active registrations,
    cancel the owning token, and are consumed when the approval is
    finalized.
    - The shell runtime combines the normal command timeout with the
    network-denial cancellation token.
    - Unified exec stores the deferred network approval object, terminates
    tracked processes when the proxy denial arrives, and returns the denial
    as a process failure while polling or completing the process.
    - Tool orchestration passes the active network approval cancellation
    token into the sandbox attempt and preserves deferred approval errors
    instead of silently unregistering them.
    - App-server `command/exec` now handles the combined
    timeout-or-cancellation expiration variant used by the runtime.
    
    ## Verification
    
    - `cargo test -p codex-core network_approval --lib`
    - `cargo clippy -p codex-app-server --all-targets -- -D warnings`
    - `cargo clippy -p codex-core --all-targets -- -D warnings`
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Add ThreadManager sample crate (#20141)
    Summary:
    - Add codex-thread-manager-sample, a one-shot binary that starts a
    ThreadManager thread, submits a prompt, and prints the final assistant
    output.
    - Pass ThreadStore into ThreadManager::new and expose
    thread_store_from_config for existing callsites.
    - Build the sample Config directly with only --model and prompt inputs.
    
    Verification:
    - just fmt
    - cargo check -p codex-thread-manager-sample -p codex-app-server -p
    codex-mcp-server
    - git diff --check
    
    Tests: Not run per request.
  • Add environment provider snapshot (#20058)
    ## Summary
    - Change `EnvironmentProvider` to return concrete `Environment`
    instances instead of `EnvironmentConfigurations`.
    - Make `DefaultEnvironmentProvider` provide the provider-visible `local`
    environment plus optional `remote` environment from
    `CODEX_EXEC_SERVER_URL`.
    - Keep `EnvironmentManager` as the concrete cache while exposing its own
    explicit local environment for `local_environment()` fallback paths.
    
    ## Validation
    - `just fmt`
    - `git diff --check`
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • fix: restore live event submit path for apply patch tests (#20108)
    ## Summary
    
    This fixes the CI regression introduced by
    [#20040](https://github.com/openai/codex/pull/20040).
    
    That PR migrated several `apply_patch_cli` tests from direct
    `codex.submit(Op::UserTurn { ... })` calls to `harness.submit(...)`.
    `harness.submit()` waits for `TurnComplete` before returning, which
    drains the same event stream that these tests use to assert `TurnDiff`,
    `PatchApplyUpdated`, and related live events. The regressed tests then
    timed out waiting for events that had already been consumed.
    
    This change restores a no-wait submit path for the event-observing
    `apply_patch_cli` tests so they can watch the turn stream directly
    again.
    
    ## What Changed
    
    - added a local `submit_without_wait(...)` helper in
    `codex-rs/core/tests/suite/apply_patch_cli.rs`
    - switched the `apply_patch_cli` tests that assert live turn events back
    to that helper
    - left the profile-backed `harness.submit(...)` migration in place for
    tests that only care about final filesystem or tool output state
    
    ## Why macOS Looked Green
    
    In the failing run
    [25084487331](https://github.com/openai/codex/actions/runs/25084487331),
    `//codex-rs/core:core-all-test` was cached on macOS, so the regressed
    tests were not rerun there. The Linux GNU, Linux MUSL, and Windows Bazel
    jobs reran the target and exposed the failure.
    
    ## Verification
    
    - `cargo test -p codex-core apply_patch_ -- --nocapture`
    - previously failing local cases now pass again:
      - `apply_patch_cli_move_without_content_change_has_no_turn_diff`
      - `apply_patch_turn_diff_for_rename_with_content_change`
      - `apply_patch_aggregates_diff_across_multiple_tool_calls`
  • core tests: migrate hook turns to profiles (#20041)
    ## Summary
    - Removes `SandboxPolicy` from the hooks test suite.
    - Submits hook-related turns with explicit `PermissionProfile` values
    for disabled, read-only, and workspace-write cases.
    - Preserves the managed-network hook test by configuring and submitting
    a workspace-write profile with enabled network, allowing the existing
    requirements-backed proxy path to remain covered.
    
    ## Verification
    - `cargo check -p codex-core --tests`
    - `just fmt`
  • core tests: migrate apply patch turns to profiles (#20040)
    ## Summary
    - Removes `SandboxPolicy` from the apply-patch CLI test suite.
    - Uses the harness' profile-backed submit helper for danger/no-sandbox
    turns instead of constructing `Op::UserTurn` manually with legacy
    fields.
    - Converts the workspace-write traversal cases to submit
    `PermissionProfile::workspace_write_with(...)` directly.
    
    ## Verification
    - `cargo check -p codex-core --tests`
    - `just fmt`
  • core tests: migrate rmcp turns to profiles (#20037)
    ## Summary
    - Removes `SandboxPolicy` from the RMCP client test suite.
    - Adds shared read-only user-turn helpers that submit
    `PermissionProfile::read_only()` plus the legacy compatibility
    projection required by the current `Op::UserTurn` shape.
    - Keeps sandbox metadata assertions intact by deriving the expected
    legacy `sandboxPolicy` value from the same read-only profile used for
    the turn.
    
    ## Verification
    - `cargo check -p codex-core --tests`
    - `just fmt`
  • core tests: migrate compact turns to profiles (#20035)
    ## Summary
    - Removes the remaining `SandboxPolicy` usage from the compaction test
    suite.
    - Adds a small local helper for direct `Op::UserTurn` construction so
    these tests send `PermissionProfile::Disabled` plus the legacy
    compatibility projection required by the protocol field.
    - Keeps the existing danger/full-access behavior while exercising the
    canonical permission profile path.
    
    ## Verification
    - `cargo check -p codex-core --tests`
    - `just fmt`
  • core tests: migrate zsh-fork permissions to profiles (#20034)
    ## Summary
    - Updates the zsh-fork test helper to configure `PermissionProfile`
    directly instead of constructing a legacy `SandboxPolicy`.
    - Sends permission-profile-backed turns from the skill approval zsh-fork
    tests so the runtime and request path exercise the canonical permissions
    model.
    - Leaves the broader approvals suite on legacy policies for now, except
    for the zsh-fork test that shares this helper.
    
    ## Verification
    - `cargo check -p codex-core --tests`
    - `just fmt`
  • core tests: migrate request permissions tool turns to profiles (#20033)
    ## Summary
    
    This migrates the macOS request-permissions tool tests from legacy
    `SandboxPolicy` setup to `PermissionProfile` setup. The tests still
    exercise the same workspace-write baseline and request-permission
    grants, but the canonical permissions value is now the profile.
    
    ## Changes
    
    - Replaces the `workspace_write_excluding_tmp()` helper with a
    `PermissionProfile::workspace_write_with()` helper.
    - Applies test config through `Permissions::set_permission_profile()`.
    - Uses `turn_permission_fields()` for `Op::UserTurn` compatibility
    fields.
    - Removes the `SandboxPolicy` import from `request_permissions_tool.rs`.
    
    ## Verification
    
    - `cargo check -p codex-core --tests`
  • core tests: migrate prompt caching turns to profiles (#20032)
    ## Summary
    
    This removes the explicit `SandboxPolicy` constructors from
    `core/tests/suite/prompt_caching.rs`. The tests still exercise the same
    prompt-cache invariants across permission and turn-context changes, but
    the permission source is now `PermissionProfile`.
    
    ## Changes
    
    - Uses `PermissionProfile::workspace_write_with()` for workspace-write
    override scenarios.
    - Uses `PermissionProfile::Disabled` for the no-sandbox per-turn
    override.
    - Projects profiles through `turn_permission_fields()` or
    `to_legacy_sandbox_policy()` only to populate compatibility fields on
    existing ops.
    - Removes the `SandboxPolicy` import from `prompt_caching.rs`.
    
    ## Verification
    
    - `cargo check -p codex-core --tests`
  • core tests: migrate exec policy turns to profiles (#20030)
    ## Summary
    
    This migrates `core/tests/suite/exec_policy.rs` away from legacy
    `SandboxPolicy` turn construction. These tests all use no-sandbox turns
    to exercise exec-policy behavior, so `PermissionProfile::Disabled` is
    the canonical representation.
    
    ## Changes
    
    - Replaces direct `SandboxPolicy::DangerFullAccess` turn fields with
    `PermissionProfile::Disabled`.
    - Uses `turn_permission_fields()` to populate the compatibility
    `sandbox_policy` field required by `Op::UserTurn`.
    - Removes the `SandboxPolicy` import from `exec_policy.rs`.
    
    ## Verification
    
    - `cargo check -p codex-core --tests`
  • core tests: migrate permissions message tests to profiles (#20028)
    ## Summary
    
    This removes another test-only `SandboxPolicy` dependency by configuring
    `permissions_messages.rs` with a `PermissionProfile` directly. The test
    still verifies the rendered compatibility permissions text, but now
    obtains the legacy projection from the loaded `Config` rather than using
    `SandboxPolicy` as the source of truth.
    
    ## Changes
    
    - Builds the workspace-write test setup with
    `PermissionProfile::workspace_write_with()`.
    - Applies that profile through `Permissions::set_permission_profile()`.
    - Uses `Config::legacy_sandbox_policy()` only for the expected
    `PermissionsInstructions` compatibility rendering.
    
    ## Verification
    
    - `cargo check -p codex-core --tests`
  • core tests: migrate tools tests to permission profiles (#20027)
    ## Summary
    
    This continues the test-side migration away from `SandboxPolicy` by
    removing the remaining legacy policy setup in
    `core/tests/suite/tools.rs`. The affected test was already modeling a
    profile-backed filesystem policy with a deny-read glob, so configuring
    the test through `Permissions::set_permission_profile()` is a better
    match for the behavior being exercised.
    
    ## Changes
    
    - Drops the `SandboxPolicy` import from `core/tests/suite/tools.rs`.
    - Configures the glob deny-read shell test directly with a
    `PermissionProfile` instead of creating a legacy read-only policy first.
    - Submits the test turn with the session permission profile so the
    deny-read glob remains active for the command under test.
    
    ## Verification
    
    - `cargo check -p codex-core --tests`
  • core tests: migrate plan item turns to profiles (#20026)
    ## Why
    
    The core item tests still had a cluster of plan-mode `Op::UserTurn`
    literals that used `SandboxPolicy::DangerFullAccess` and omitted
    `permission_profile`. These tests are validating emitted item lifecycle
    events, so keeping them on the legacy sandbox-only turn shape adds noise
    to the broader permissions migration without testing legacy behavior.
    
    ## What Changed
    
    - Adds a local `disabled_plan_turn()` helper that preserves the existing
    `std::env::current_dir()` turn cwd behavior.
    - Uses `turn_permission_fields(PermissionProfile::Disabled, cwd)` to
    populate both the compatibility `sandbox_policy` and canonical
    `permission_profile` fields.
    - Replaces the plan-mode hand-built turns in
    `codex-rs/core/tests/suite/items.rs`, removing all `SandboxPolicy`
    references from that file and reducing remaining `codex-rs/core/tests`
    `SandboxPolicy` files from 16 to 15.
    
    ## Verification
    
    - `cargo check -p codex-core --tests`
  • core tests: migrate safety check turns to profiles (#20024)
    ## Why
    
    This stack is retiring direct `SandboxPolicy` construction from tests so
    core coverage exercises the same `PermissionProfile` turn path used by
    runtime code. `safety_check_downgrade.rs` still submitted each test turn
    as `SandboxPolicy::DangerFullAccess` with no permission profile, even
    though the tests are about model verification/reroute behavior rather
    than legacy sandbox conversion.
    
    ## What Changed
    
    - Adds a local `disabled_text_turn()` helper that derives both the
    compatibility `sandbox_policy` and canonical `permission_profile` from
    `PermissionProfile::Disabled`.
    - Replaces repeated hand-built `Op::UserTurn` literals in
    `codex-rs/core/tests/suite/safety_check_downgrade.rs` with that helper.
    - Removes all `SandboxPolicy` references from the safety-check suite,
    reducing the remaining `codex-rs/core/tests` files that mention
    `SandboxPolicy` from 17 to 16.
    
    ## Verification
    
    - `cargo check -p codex-core --tests`
  • core tests: migrate view image turns to profiles (#20021)
    ## Why
    
    This stack is removing direct `SandboxPolicy` usage from test code so
    new tests exercise the same `PermissionProfile` path that runtime code
    now treats as canonical. `view_image.rs` still built `Op::UserTurn`
    requests with `SandboxPolicy::DangerFullAccess` and no permission
    profile, which kept another core test module on the legacy turn shape.
    
    ## What Changed
    
    - Adds a small `disabled_user_turn()` helper for the view-image suite
    that derives the compatibility `sandbox_policy` and canonical
    `permission_profile` from `PermissionProfile::Disabled`.
    - Replaces repeated direct `Op::UserTurn` literals in
    `codex-rs/core/tests/suite/view_image.rs` with that helper.
    - Removes all `SandboxPolicy` references from `view_image.rs`, reducing
    the remaining `codex-rs/core/tests` files that mention `SandboxPolicy`
    from 18 to 17.
    
    ## Verification
    
    - `cargo check -p codex-core --tests`
  • core tests: migrate model/personality turns to profiles (#20018)
    ## Summary
    
    - Migrates `model_switching.rs` and `personality.rs` direct
    `Op::UserTurn` construction from legacy `SandboxPolicy` literals to
    `PermissionProfile`-backed turn fields.
    - Adds small local helpers in each file so tests keep asserting
    model/personality behavior without repeating permission plumbing.
    - Reduces `rg -l '\bSandboxPolicy\b' codex-rs/core/tests` from 20 files
    to 18; `codex-rs/tui` remains at zero `SandboxPolicy` references.
    
    ## Testing
    
    - `cargo check -p codex-core --tests`
    - `just fmt`
  • core tests: send model turns with permission profiles (#20016)
    ## Summary
    - Migrate direct `Op::UserTurn` construction in remote-model tests from
    legacy `SandboxPolicy::DangerFullAccess` to
    `PermissionProfile::Disabled` via `turn_permission_fields()`.
    - Migrate the Responses API proxy header helper from an inline
    workspace-write `SandboxPolicy` to
    `PermissionProfile::workspace_write()`.
    - Reduce `SandboxPolicy` references in `codex-rs/core/tests` from 22
    files after #20015 to 20 files.
    
    ## Testing
    - `cargo check -p codex-core --tests`
    - `just fmt`
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/20016).
    * #20041
    * #20040
    * #20037
    * #20035
    * #20034
    * #20033
    * #20032
    * #20030
    * #20028
    * #20027
    * #20026
    * #20024
    * #20021
    * #20018
    * __->__ #20016
  • core tests: configure profiles directly (#20015)
    ## Summary
    - Replace legacy sandbox config setup in delegate and telemetry tests
    with direct `PermissionProfile` configuration.
    - Move no-sandbox and read-only test turns in `tools.rs`,
    `code_mode.rs`, `user_shell_cmd.rs`, and `model_visible_layout.rs` from
    legacy `SandboxPolicy` values to `PermissionProfile` helpers, while
    leaving the deny-glob read-only compatibility case for a later targeted
    cleanup.
    - Use `PermissionProfile::read_only()` where tests need managed
    read-only behavior and `PermissionProfile::Disabled` where they
    intentionally need no sandbox.
    - Reduce `SandboxPolicy` references in `codex-rs/core/tests` from 27
    files after #20013 to 22 files.
    
    ## Testing
    - `cargo check -p codex-core --tests`
    - `just fmt`
  • core tests: migrate more turns to permission profiles (#20013)
    ## Summary
    - Migrate another batch of direct `Op::UserTurn` test construction from
    legacy `SandboxPolicy` values to `PermissionProfile` inputs via
    `turn_permission_fields()`.
    - Replace a one-off read-only `SandboxPolicy` bridge in the macOS exec
    test with `PermissionProfile::read_only()`.
    - Reduce `SandboxPolicy` references in `codex-rs/core/tests` from 32
    files at the start of the cleanup stack to 27 files.
    
    ## Testing
    - `cargo check -p codex-core --tests`
    - `just fmt`
    - `just fix -p codex-core`
  • core tests: build user turns from permission profiles (#20011)
    ## Summary
    - Add `turn_permission_fields()` so tests that construct `Op::UserTurn`
    directly can provide a canonical `PermissionProfile` while still filling
    the required legacy `sandbox_policy` compatibility field.
    - Migrate direct user-turn construction in core integration tests from
    `SandboxPolicy::DangerFullAccess` to `PermissionProfile::Disabled`.
    - Continue reducing direct `SandboxPolicy` usage in
    `codex-rs/core/tests`, from 41 files after #20010 to 32 files in this
    PR.
    
    ## Testing
    - `cargo check -p codex-core --tests`
    - `just fmt`
    - `just fix -p core_test_support`
    - `just fix -p codex-core`
  • core tests: submit turns with permission profiles (#20010)
    ## Summary
    
    - Add `PermissionProfile`-based turn submission helpers to
    `core_test_support`, while keeping the legacy `SandboxPolicy` helper for
    tests that intentionally exercise legacy fallback behavior.
    - Switch the default `TestCodex::submit_turn()` path to send a real
    `PermissionProfile` plus the required legacy compatibility projection in
    `Op::UserTurn`.
    - Migrate straightforward app/search/shell/truncation tests from
    `SandboxPolicy::{DangerFullAccess, ReadOnly}` to
    `PermissionProfile::{Disabled, read_only}`.
    - Add a TUI compatibility projection helper for legacy app-server fields
    so non-legacy writable roots are preserved instead of being downgraded
    to read-only.
    - Fix remote start/resume/fork sandbox-mode projection to classify any
    managed profile with writable roots as workspace-write, not only
    profiles that can write `cwd`.
    - Reduce `SandboxPolicy` references in `codex-rs/core/tests` from 47
    files to 41 files without changing production behavior.
    
    ## Testing
    
    - `cargo check -p codex-core --tests`
    - `cargo test -p codex-tui
    compatibility_profile_preserves_unbridgeable_write_roots`
    - `cargo test -p codex-tui
    sandbox_mode_preserves_non_cwd_write_roots_for_remote_sessions`
    - `just fmt`
    - `just fix -p core_test_support`
    - `just fix -p codex-core`
  • Discover hooks bundled with plugins (#19705)
    ## Why
    
    Plugins can bundle lifecycle hooks, but Codex previously only discovered
    hooks from user, project, and managed config layers. This adds the
    plugin discovery and runtime plumbing needed for plugin-bundled hooks
    while keeping execution behind the `plugin_hooks` feature flag.
    
    ## What
    
    - Discovers plugin hook sources from each plugin's default
    `hooks/hooks.json`.
    - Supports `plugin.json` manifest `hooks` entries as either relative
    paths or inline hook objects.
    - Plumbs discovered plugin hook sources through plugin loading into the
    hook runtime when `plugin_hooks` is enabled.
    - Marks plugin-originated hook runs as `HookSource::Plugin`.
    - Injects `PLUGIN_ROOT` and `CLAUDE_PLUGIN_ROOT` into plugin hook
    command environments.
    - Updates generated schemas and hook source metadata for the plugin hook
    source.
    
    ## Stack
    
    1. This PR - openai/codex#19705
    2. openai/codex#19778
    3. openai/codex#19840
    4. openai/codex#19882
    
    ## Reviewer Notes
    
    - Core logic is in `codex-rs/core-plugins/src/loader.rs` and
    `codex-rs/hooks/src/engine/discovery.rs`
    - Moved existing / adding new tests to
    `codex-rs/core-plugins/src/loader_tests.rs` hence the large diff there
    - Otherwise mostly plumbing and minor schema updates
    
    ### Core Changes
    
    The `codex-rs/core` changes are limited to wiring plugin hook support
    into existing core flows:
    
    - `core/src/session/session.rs` conditionally pulls effective plugin
    hook sources and plugin hook load warnings from `PluginsManager` when
    `plugin_hooks` is enabled, then passes them into `HooksConfig`.
    - `core/src/hook_runtime.rs` adds the `plugin` metric tag for
    `HookSource::Plugin`.
    - `core/config.schema.json` picks up the new `plugin_hooks` feature
    flag, and `core/src/plugins/manager_tests.rs` updates fixtures for the
    added plugin hook fields.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • [codex] Add token usage to turn tracing spans (#19432)
    ## Why
    
    Slow Codex turns are easier to debug when token usage is visible in the
    trace itself, without joining against separate analytics. This adds
    token usage to existing turn-handling spans for regular user turns only.
    
    [Example
    turn](https://openai.datadoghq.com/apm/trace/9d353efa2cb5de1f4c5b93dc33c3df04?colorBy=service&graphType=flamegraph&shouldShowLegend=true&sort=time&spanID=3555541504891512675&spanViewType=metadata&traceQuery=)
    <img width="1447" height="967" alt="Screenshot 2026-04-24 at 3 03 07 PM"
    src="https://github.com/user-attachments/assets/ab7bb187-e7fc-41f0-a366-6c44610b2b2c"
    />
    
    ## What Changed
    
    Added response-level token fields on completed handle_responses spans:
    
    gen_ai.usage.input_tokens
    gen_ai.usage.cache_read.input_tokens
    gen_ai.usage.output_tokens
    codex.usage.reasoning_output_tokens
    codex.usage.total_tokens
    Added aggregate token fields on regular turn spans:
    
    codex.turn.token_usage.*
    Added an explicit regular-turn opt-in via
    SessionTask::records_turn_token_usage_on_span() so this is not coupled
    to span-name strings.
    
    ## Testing
    
    - `cargo test -p codex-otel`
    - `cargo test -p codex-core
    turn_and_completed_response_spans_record_token_usage`
    - `just fmt`
    - `just fix -p codex-core`
    - `just fix -p codex-otel`
    - Manual local Electron/app-server smoke test: regular user turn emits
    the new span fields
    
    Known status: `cargo test -p codex-core` was attempted and failed in
    unrelated existing areas: config approvals, request-permissions,
    git-info ordering, and subagent metadata persistence.
  • permissions: add built-in default profiles (#19900)
    ## Why
    
    The migration away from `SandboxPolicy` needs new configs to start from
    permissions profiles instead of deriving profiles from legacy sandbox
    modes. Existing users can have empty `config.toml` files, and we should
    not rewrite user-owned config files that may live in shared
    repositories.
    
    This PR introduces built-in profile names so an empty config can resolve
    to a canonical `PermissionProfile`, while explicit named `[permissions]`
    profiles still behave predictably.
    
    ## What changed
    
    - Adds built-in `default_permissions` profile names:
      - `:read-only` maps to `PermissionProfile::read_only()`.
    - `:workspace` maps to the workspace-write profile, including
    project-root metadata carveouts.
    - `:danger-no-sandbox` maps to `PermissionProfile::Disabled`, preserving
    the distinction between no sandbox and a broad managed sandbox.
    - Reserves the `:` prefix for built-in profiles so user-defined
    `[permissions]` profiles cannot collide with future built-ins.
    - Allows `default_permissions` to reference a built-in profile without
    requiring a `[permissions]` table.
    - Makes an otherwise empty config choose a built-in profile by
    trust/platform context: trusted or untrusted project roots use
    `:workspace` when the platform supports that sandbox, while roots
    without a trust decision use `:read-only`.
    - Keeps legacy `sandbox_mode` configs on the legacy path, and still
    rejects user-defined `[permissions]` profiles that omit
    `default_permissions` so we do not silently guess among custom profiles.
    - Preserves compatibility behavior for implicit defaults: bare
    `network.enabled = true` allows runtime network without starting the
    managed proxy, explicit profile proxy policy still starts the proxy, and
    implicit workspace/add-dir roots keep legacy metadata carveouts.
    
    ## Verification
    
    - `cargo test -p codex-core builtin --lib`
    - `cargo test -p codex-core profile_network_proxy_config`
    - `cargo test -p codex-core
    implicit_builtin_workspace_profile_preserves_add_dir_metadata_carveouts`
    - `cargo test -p codex-core
    permissions_profiles_network_enabled_allows_runtime_network_without_proxy`
    - `cargo test -p codex-core
    permissions_profiles_proxy_policy_starts_managed_network_proxy`
    
    ## Documentation
    
    Public Codex config docs should mention these built-in names when the
    `[permissions]` config format is ready to document as stable.
    
    
    
    
    
    
    
    
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/19900).
    * #20041
    * #20040
    * #20037
    * #20035
    * #20034
    * #20033
    * #20032
    * #20030
    * #20028
    * #20027
    * #20026
    * #20024
    * #20021
    * #20018
    * #20016
    * #20015
    * #20013
    * #20011
    * #20010
    * #20008
    * __->__ #19900
  • Add turn start timestamp to turn metadata (#19473)
    ## Why
    - Without change: MCP tool calls receive
    `_meta["x-codex-turn-metadata"]` with `session_id` and `turn_id`.
    - Issue: MCP servers may want the turn start timestamp to measure
    internal latency relative to turn start.
    
    ## What Changed
    - With change: turn metadata now includes `turn_started_at_unix_ms`,
    which is propagated to MCP tool calls in
    `_meta["x-codex-turn-metadata"]`.
    
    ## Verification
    - `codex-rs/core/src/mcp_tool_call_tests.rs`
    - `codex-rs/core/src/turn_metadata_tests.rs`
    - `codex-rs/core/src/turn_timing_tests.rs`
    - `codex-rs/core/tests/responses_headers.rs`
    - `codex-rs/core/tests/suite/search_tool.rs`
  • feat: split memories part 2 (#19860)
    Keep extracting memories out of core and moving the write trigger in the
    app-server
    This is temporary and it should move at the client level as a follow-up
    This makes core fully independant from `codex-memories-write`
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • [codex-analytics] include user agent in default headers (#17689)
    ## Summary
    Adds the standard Codex `User-Agent` to shared default headers so the
    responses-api WS handshake carries the same client OS and version
    context as HTTP requests.
    
    ## Testing
    - `cargo test -p codex-core
    build_ws_client_metadata_includes_window_lineage_and_turn_metadata`
    - `cargo test -p codex-core --test all responses_websocket`
  • Remove ghost snapshots (#19481)
    ## Summary
    - Remove `ghost_snapshot` / `GhostCommit` from the Responses API surface
    and generated SDK/schema artifacts.
    - Keep legacy config loading compatible, but make undo a no-op that
    reports the feature is unavailable.
    - Clean up core history, compaction, telemetry, rollout, and tests to
    stop carrying ghost snapshot items.
    
    ## Testing
    - Unit tests passed for `codex-protocol`, `codex-core` targeted undo and
    compaction flows, `codex-rollout`, and `codex-app-server-protocol`.
    - Regenerated config and app-server schemas plus Python SDK artifacts
    and verified they match the checked-in outputs.
  • Stabilize plugin MCP fixture tests (#19452)
    ## Why
    
    Recent `main` CI had repeated flakes in the plugin fixture tests:
    
    - `codex-core::all
    suite::plugins::explicit_plugin_mentions_inject_plugin_guidance` failed
    in runs
    [24909500958](https://github.com/openai/codex/actions/runs/24909500958),
    [24908076251](https://github.com/openai/codex/actions/runs/24908076251),
    [24906197645](https://github.com/openai/codex/actions/runs/24906197645),
    and
    [24898949647](https://github.com/openai/codex/actions/runs/24898949647).
    - `codex-core::all suite::plugins::plugin_mcp_tools_are_listed` failed
    in runs
    [24909500958](https://github.com/openai/codex/actions/runs/24909500958),
    [24908076251](https://github.com/openai/codex/actions/runs/24908076251),
    and
    [24898949647](https://github.com/openai/codex/actions/runs/24898949647).
    
    The failures were in the same plugin/MCP fixture family: assertions
    expected sample plugin guidance or tool inventory, but the test could
    observe the session before the sample MCP server had finished startup.
    
    ## Root Cause
    
    `explicit_plugin_mentions_inject_plugin_guidance` submitted the user
    turn immediately after constructing the session. MCP startup is
    asynchronous, so on a slower or busier CI runner the prompt could be
    built before the sample plugin MCP server had reported its tools. That
    made the test depend on scheduler timing rather than the fixture being
    ready.
    
    `plugin_mcp_tools_are_listed` already needed the same readiness
    condition, but its wait logic was local to that test.
    
    ## What Changed
    
    - Added a shared `wait_for_sample_mcp_ready` helper for the plugin
    fixture tests.
    - Wait for `McpStartupComplete` before submitting the explicit plugin
    mention turn.
    - Reuse the same readiness helper in the MCP tool-listing test.
    
    ## Why This Should Be Reliable
    
    The tests now wait for the explicit readiness signal from the sample MCP
    server before asserting guidance or tools derived from that server. This
    removes the startup race while still exercising the real fixture path,
    so the assertions should only run after the plugin inventory is
    deterministic.
    
    ## Verification
    
    - `cargo test -p codex-core --test all plugins::`
    - GitHub CI for this PR is passing.
  • fix: filter dynamic deferred tools from model_visible_specs (#19771)
    fixes #19486
    
    ### Problem
    Right now dynamic deferred tools are filtered at normal-turn prompt
    building time, rather than upstream while building the `ToolRouter`
    itself. This causes issues because dynamic deferred tools are then
    wrongly included in the router's `model_visible_specs`, which is what
    the compaction request-building flow relies on.
    
    ### Fix
    Move the dynamic deferred tool filtering to `ToolRouter` creation time
    to solve this problem for every request that relies on `ToolRouter` for
    `model_visible_specs`, which solves the issue generically.
    
    ### Tests
    Added unit + integration tests to ensure dynamic deferred tools are
    omitted from `model_visible_specs` and compaction request respectively.
    
    Tested against live `/compact` endpoint; raw deferred dynamic tools
    without `tool_search` returned `400` (current bug), while the filtered
    payload (this fix) returns `200`.
  • refactor: make auth loading async (#19762)
    ## Summary
    
    Auth loading used to expose synchronous construction helpers in several
    places even though some auth sources now need async work. This PR makes
    the auth-loading surface async and updates the callers to await it.
    
    This is intentionally only plumbing. It does not change how
    AgentIdentity tokens are decoded, how task runtime ids are allocated, or
    how JWT signatures are verified.
    
    ## Stack
    
    1. **This PR:** [refactor: make auth loading
    async](https://github.com/openai/codex/pull/19762)
    2. [refactor: load AgentIdentity runtime
    eagerly](https://github.com/openai/codex/pull/19763)
    3. [feat: verify AgentIdentity JWTs with
    JWKS](https://github.com/openai/codex/pull/19764)
    
    ## Important call sites
    
    | Area | Change |
    | --- | --- |
    | `codex-login` auth loading | `CodexAuth` and `AuthManager`
    construction paths now await auth loading. |
    | app-server startup | Auth manager construction is awaited during
    initialization. |
    | CLI/TUI/exec/MCP/chatgpt callers | Existing auth-loading calls now
    await the same behavior. |
    | cloud requirements storage loader | The loader becomes async so it can
    share the same auth construction path. |
    | auth tests | Tests that load auth now run in async contexts. |
    
    ## Testing
    
    Tests: targeted Rust auth test compilation, formatter, scoped Clippy
    fix, and Bazel lock check.
  • feat: use git-backed workspace diffs for memory consolidation (#18982)
    ## Why
    
    This PR make the `morpheus` agent (memory phase 2) use a git diff to
    start it's consolidation. The workflow is the following:
    1. The agent acquire a lock
    2. If `.codex/memories` does not exist or is not a git root, initialize
    everything (and make a first empty commit)
    3. Update `raw_memories.md` and `rollout_summaries/` as before.
    Basically we select max N phase 1 memories based on a given policy
    4. We use git (`gix`) to get a diff between the current state of
    `.codex/memories` and the last commit.
    5. Dump the diff in `phase2_workspace_diff.md`
    6. Spawn `morpheus` and point it to `phase2_workspace_diff.md`
    7. Wait for `morpheus` to be done
    8. Re-create a new `.git` and make one single commit on it. We do this
    because we don't want to preserve history through `.git` and this is
    cheap anyway
    9. We release the lock
    On top of this, we keep the retry policies etc etc
    
    The goals of this new workflow are:
    * Better support of any memory extensions such as `chronicle`
    * Allow the user to manually edit memories and this will be considered
    by the phase 2 agent
     
    As a follow-up we will need to add support for user's edition while
    `morpheus` is running
    
    ## What Changed
    
    - Added memory workspace helpers that prepare the git baseline, compute
    the diff, write `phase2_workspace_diff.md`, and reset the baseline after
    successful consolidation.
    - Updated Phase 2 to sync current inputs into `raw_memories.md` and
    `rollout_summaries/`, prune old extension resources, skip clean
    workspaces, and run the consolidation subagent only when the workspace
    has changes.
    - Tightened Phase 2 job ownership around long-running consolidation with
    heartbeats and an ownership check before resetting the baseline.
    - Simplified the prompt and state APIs so DB watermarks are bookkeeping,
    while workspace dirtiness decides whether consolidation work exists.
    - Updated the memory pipeline README and tests for workspace diffs,
    extension-resource cleanup, pollution-driven forgetting, selection
    ranking, and baseline persistence.
    
    ## Verification
    
    - Added/updated coverage in `core/src/memories/tests.rs`,
    `core/src/memories/workspace_tests.rs`, `state/src/runtime/memories.rs`,
    and `core/tests/suite/memories.rs`.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • [codex] Move config loading into codex-config (#19487)
    ## Why
    
    Config loading had become split across crates: `codex-config` owned the
    config types and merge logic, while `codex-core` still owned the loader
    that assembled the layer stack. This change consolidates that
    responsibility in `codex-config`, so the crate that defines config
    behavior also owns how configs are discovered and loaded.
    
    To make that move possible without reintroducing the old dependency
    cycle, the shell-environment policy types and helpers that
    `codex-exec-server` needs now live in `codex-protocol` instead of
    flowing through `codex-config`.
    
    This also makes the migrated loader tests more deterministic on machines
    that already have managed or system Codex config installed by letting
    tests override the system config and requirements paths instead of
    reading the host's `/etc/codex`.
    
    ## What Changed
    
    - moved the config loader implementation from `codex-core` into
    `codex-config::loader` and deleted the old `core::config_loader` module
    instead of leaving a compatibility shim
    - moved shell-environment policy types and helpers into
    `codex-protocol`, then updated `codex-exec-server` and other downstream
    crates to import them from their new home
    - updated downstream callers to use loader/config APIs from
    `codex-config`
    - added test-only loader overrides for system config and requirements
    paths so loader-focused tests do not depend on host-managed config state
    - cleaned up now-unused dependency entries and platform-specific cfgs
    that were surfaced by post-push CI
    
    ## Testing
    
    - `cargo test -p codex-config`
    - `cargo test -p codex-core config_loader_tests::`
    - `cargo test -p codex-protocol -p codex-exec-server -p
    codex-cloud-requirements -p codex-rmcp-client --lib`
    - `cargo test --lib -p codex-app-server-client -p codex-exec`
    - `cargo test --no-run --lib -p codex-app-server`
    - `cargo test -p codex-linux-sandbox --lib`
    - `cargo shear`
    - `just bazel-lock-check`
    
    ## Notes
    
    - I did not chase unrelated full-suite failures outside the migrated
    loader surface.
    - `cargo test -p codex-core --lib` still hits unrelated proxy-sensitive
    failures on this machine, and Windows CI still shows unrelated
    long-running/timeouting test noise outside the loader migration itself.
  • permissions: derive compatibility policies from profiles (#19392)
    ## Why
    
    After #19391, `PermissionProfile` and the split filesystem/network
    policies could still be stored in parallel. That creates drift risk: a
    profile can preserve deny globs, external enforcement, or split
    filesystem entries while a cached projection silently loses those
    details. This PR makes the profile the runtime source and derives
    compatibility views from it.
    
    ## What Changed
    
    - Removes stored filesystem/network sandbox projections from
    `Permissions` and `SessionConfiguration`; their accessors now derive
    from the canonical `PermissionProfile`.
    - Derives legacy `SandboxPolicy` snapshots from profiles only where an
    older API still needs that field.
    - Updates MCP connection and elicitation state to track
    `PermissionProfile` instead of `SandboxPolicy` for auto-approval
    decisions.
    - Adds semantic filesystem-policy comparison so cwd changes can preserve
    richer profiles while still recognizing equivalent legacy projections
    independent of entry ordering.
    - Updates config/session tests to assert profile-derived projections
    instead of parallel stored fields.
    
    ## Verification
    
    - `cargo test -p codex-core direct_write_roots`
    - `cargo test -p codex-core runtime_roots_to_legacy_projection`
    - `cargo test -p codex-app-server
    requested_permissions_trust_project_uses_permission_profile_intent`
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/19392).
    * #19395
    * #19394
    * #19393
    * __->__ #19392
  • permissions: make runtime config profile-backed (#19606)
    ## Why
    
    This supersedes #19391. During stack repair, GitHub marked #19391 as
    merged into a temporary stack branch rather than into `main`, so the
    runtime-config change needed a fresh PR.
    
    `PermissionProfile` is now the canonical permissions shape after #19231
    because it can distinguish `Managed`, `Disabled`, and `External`
    enforcement while also carrying filesystem rules that legacy
    `SandboxPolicy` cannot represent cleanly. Core config and session state
    still needed to accept profile-backed permissions without forcing every
    profile through the strict legacy bridge, which rejected valid runtime
    profiles such as direct write roots.
    
    The unrelated CI/test hardening that previously rode along with this PR
    has been split into #19683 so this PR stays focused on the permissions
    model migration.
    
    ## What Changed
    
    - Adds `Permissions.permission_profile` and
    `SessionConfiguration.permission_profile` as constrained runtime state,
    while keeping `sandbox_policy` as a legacy compatibility projection.
    - Introduces profile setters that keep `PermissionProfile`, split
    filesystem/network policies, and legacy `SandboxPolicy` projections
    synchronized.
    - Uses a compatibility projection for requirement checks and legacy
    consumers instead of rejecting profiles that cannot round-trip through
    `SandboxPolicy` exactly.
    - Updates config loading, config overrides, session updates, turn
    context plumbing, prompt permission text, sandbox tags, and exec request
    construction to carry profile-backed runtime permissions.
    - Preserves configured deny-read entries and `glob_scan_max_depth` when
    command/session profiles are narrowed.
    - Adds `PermissionProfile::read_only()` and
    `PermissionProfile::workspace_write()` presets that match legacy
    defaults.
    
    ## Verification
    
    - `cargo test -p codex-core direct_write_roots`
    - `cargo test -p codex-core runtime_roots_to_legacy_projection`
    - `cargo test -p codex-app-server
    requested_permissions_trust_project_uses_permission_profile_intent`
    
    
    
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/19606).
    * #19395
    * #19394
    * #19393
    * #19392
    * __->__ #19606
  • test: harden app-server integration tests (#19683)
    ## Why
    
    Windows Bazel runs in the permissions stack exposed that app-server
    integration tests were launching normal plugin startup warmups in every
    subprocess. Those warmups can call
    `https://chatgpt.com/backend-api/plugins/featured` when a test is not
    specifically exercising plugin startup, which adds slow background work,
    noisy stderr, and dependence on external network state. The relevant
    startup/featured-plugin behavior was introduced across #15042 and
    #15264.
    
    A few app-server tests also had long optional waits or unbounded cleanup
    paths, making failures expensive to diagnose and contributing to slow
    Windows shards. One external-agent config test from #18246 used a
    GitHub-style marketplace source, which was enough to exercise the
    pending remote-import path but also meant the background completion task
    could attempt a real clone.
    
    ## What Changed
    
    - Adds explicit `AppServerRuntimeOptions` / `PluginStartupTasks`
    plumbing and a hidden debug-only
    `--disable-plugin-startup-tasks-for-tests` app-server flag, so
    integration tests can suppress startup plugin warmups without adding a
    production env-var gate.
    - Has the app-server test harness pass that hidden flag by default,
    while opting plugin-startup coverage back in for tests that
    intentionally exercise startup sync and featured-plugin warmup behavior.
    - Lowers normal app-server subprocess logging from `info`/`debug` to
    `warn` to avoid multi-megabyte stderr output in Bazel logs.
    - Prevents the external-agent config test from attempting a real
    marketplace clone by using an invalid non-local source while still
    exercising the pending-import completion path.
    - Bounds optional filesystem/realtime waits and fake WebSocket
    test-server shutdown so failures produce targeted timeouts instead of
    hanging a shard.
    - Fixes the Unix script-resolution test in `rmcp-client` to exercise
    PATH resolution directly and include the actual spawn error in failures.
    
    ## Verification
    
    - `cargo check -p codex-app-server`
    - `cargo clippy -p codex-app-server --tests -- -D warnings`
    - `cargo test -p codex-rmcp-client
    program_resolver::tests::test_unix_executes_script_without_extension`
    - `cargo test -p codex-app-server --test all
    external_agent_config_import_sends_completion_notification_after_pending_plugins_finish
    -- --nocapture`
    - `cargo test -p codex-app-server --test all
    plugin_list_uses_warmed_featured_plugin_ids_cache_on_first_request --
    --nocapture`
    - Windows Local Bazel passed with this test-hardening bundle before it
    was extracted from #19606.
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/19683).
    * #19395
    * #19394
    * #19393
    * #19392
    * #19606
    * __->__ #19683
  • Split approval matrix test groups (#19454)
    ## Why
    
    Recent `main` CI repeatedly timed out in:
    
    - `codex-core::all suite::approvals::approval_matrix_covers_all_modes`
    
    It failed in runs
    [24909500958](https://github.com/openai/codex/actions/runs/24909500958),
    [24908076251](https://github.com/openai/codex/actions/runs/24908076251),
    [24906197645](https://github.com/openai/codex/actions/runs/24906197645),
    [24905823212](https://github.com/openai/codex/actions/runs/24905823212),
    [24903439629](https://github.com/openai/codex/actions/runs/24903439629),
    [24903336028](https://github.com/openai/codex/actions/runs/24903336028),
    and
    [24898949647](https://github.com/openai/codex/actions/runs/24898949647).
    
    The failure pattern was a 60s Linux remote timeout. Logs showed many
    approval scenarios completing before the single matrix test timed out.
    
    ## Root Cause
    
    `approval_matrix_covers_all_modes` packed every approval/sandbox/tool
    scenario into one test case. That made the test vulnerable to normal CI
    variance: one slow scenario or a slow process startup could push the
    whole monolithic case past the 60s per-test timeout. It also hid which
    part of the matrix was slow because the runner only reported the one
    large matrix test.
    
    ## What Changed
    
    - Keep the shared `scenarios()` table as the single source of approval
    matrix coverage.
    - Use one `#[test_case]` per `ScenarioGroup` to generate five async
    Tokio tests: danger/full-access, read-only, workspace-write,
    apply-patch, and unified-exec.
    - Keep the group runner small and add per-scenario error context so a
    failure still reports the specific scenario name.
    
    ## Why This Should Be Reliable
    
    Each scenario group now has its own test harness timeout instead of
    sharing one timeout window with the full matrix. That removes the long
    sequential loop from a single test while keeping the implementation
    compact and easy to scan.
    
    The tests still run through the same scenario definitions and runner, so
    this preserves coverage. `test-case` already composes with
    `#[tokio::test]` in this crate and is already available for test code.
    
    ## Verification
    
    - `cargo test -p codex-core --test all approval_matrix_ -- --list`
    - `cargo test -p codex-core --test all approval_matrix_`
  • permissions: remove legacy read-only access modes (#19449)
    ## Why
    
    `ReadOnlyAccess` was a transitional legacy shape on `SandboxPolicy`:
    `FullAccess` meant the historical read-only/workspace-write modes could
    read the full filesystem, while `Restricted` tried to carry partial
    readable roots. The partial-read model now belongs in
    `FileSystemSandboxPolicy` and `PermissionProfile`, so keeping it on
    `SandboxPolicy` makes every legacy projection reintroduce lossy
    read-root bookkeeping and creates unnecessary noise in the rest of the
    permissions migration.
    
    This PR makes the legacy policy model narrower and explicit:
    `SandboxPolicy::ReadOnly` and `SandboxPolicy::WorkspaceWrite` represent
    the old full-read sandbox modes only. Split readable roots, deny-read
    globs, and platform-default/minimal read behavior stay in the runtime
    permissions model.
    
    ## What changed
    
    - Removes `ReadOnlyAccess` from
    `codex_protocol::protocol::SandboxPolicy`, including the generated
    `access` and `readOnlyAccess` API fields.
    - Updates legacy policy/profile conversions so restricted filesystem
    reads are represented only by `FileSystemSandboxPolicy` /
    `PermissionProfile` entries.
    - Keeps app-server v2 compatible with legacy `fullAccess` read-access
    payloads by accepting and ignoring that no-op shape, while rejecting
    legacy `restricted` read-access payloads instead of silently widening
    them to full-read legacy policies.
    - Carries Windows sandbox platform-default read behavior with an
    explicit override flag instead of depending on
    `ReadOnlyAccess::Restricted`.
    - Refreshes generated app-server schema/types and updates tests/docs for
    the simplified legacy policy shape.
    
    ## Verification
    
    - `cargo check -p codex-app-server-protocol --tests`
    - `cargo check -p codex-windows-sandbox --tests`
    - `cargo test -p codex-app-server-protocol sandbox_policy_`
    
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/19449).
    * #19395
    * #19394
    * #19393
    * #19392
    * #19391
    * __->__ #19449
  • [codex] Forward Codex Apps tool call IDs to backend metadata (#19207)
    ## Summary
    - include the outer tool `call_id` in Codex Apps MCP request metadata
    under `_meta._codex_apps.call_id`
    - preserve existing Codex Apps metadata like `resource_uri` and
    `contains_mcp_source`
    - add request metadata coverage for both the existing-metadata and
    no-existing-metadata cases
    
    ## Why
    The paired backend change in
    [openai/openai#850796](https://github.com/openai/openai/pull/850796)
    updates MCP compliance logging to prefer `_meta._codex_apps.call_id`
    instead of the JSON-RPC request id. This client change sends that outer
    tool call id so the backend can record the model/tool call identifier
    when it is available.
    
    This is wire-compatible with older backends because `_meta._codex_apps`
    is already reserved backend-only metadata. Backends that do not read
    `call_id` will ignore the extra field.
    
    ## Testing
    - `cargo test -p codex-core request_meta`
    - `just fmt`
    - `just fix -p codex-core`
  • feat: Compress skill paths with root aliases (#19098)
    Add skill root tracking so model-visible skill lists can use short path
    aliases when absolute paths would exceed the metadata budget.
  • Migrate fork and resume reads to thread store (#18900)
    - Route cold thread/resume and thread/fork source loading through
    ThreadStore reads instead of direct rollout path operations
    - Keep lookups that explicitly specify a rollout-path using the local
    thread store methods but return an invalid-request error for remote
    ThreadStore configurations
    - Add some additional unit tests for code path coverage
  • Update models.json and related fixtures (#19323)
    Supersedes #18735.
    
    The scheduled rust-release-prepare workflow force-pushed
    `bot/update-models-json` back to the generated models.json-only diff,
    which dropped the test and snapshot updates needed for CI.
    
    This PR keeps the latest generated `models.json` from #18735 and adds
    the corresponding fixture updates:
    - preserve model availability NUX in the app-server model cache fixture
    - update core/TUI expectations for the new `gpt-5.4` `xhigh` default
    reasoning
    - refresh affected TUI chatwidget snapshots for the `gpt-5.5`
    default/model copy changes
    
    Validation run locally while preparing the fix:
    - `just fmt`
    - `cargo test -p codex-app-server model_list`
    - `cargo test -p codex-core includes_no_effort_in_request`
    - `cargo test -p codex-core
    includes_default_reasoning_effort_in_request_when_defined_by_model_info`
    - `cargo test -p codex-tui --lib chatwidget::tests`
    - `cargo insta pending-snapshots`
    
    ---------
    
    Co-authored-by: aibrahim-oai <219906144+aibrahim-oai@users.noreply.github.com>