Commit Graph

581 Commits

  • Sync local plugin imports, async remote imports, refresh caches after… (#18246)
    … import
    
    ## Why
    
    `externalAgentConfig/import` used to spawn plugin imports in the
    background and return immediately. That meant local marketplace imports
    could still be in flight when the caller refreshed plugin state, so
    newly imported plugins would not show up right away.
    
    This change makes local marketplace imports complete before the RPC
    returns, while keeping remote marketplace imports asynchronous so we do
    not block on remote fetches.
    
    ## What changed
    
    - split plugin migration details into local and remote marketplace
    imports based on the external config source
    - import local marketplaces synchronously during
    `externalAgentConfig/import`
    - return pending remote plugin imports to the app-server so it can
    finish them in the background
    - clear the plugin and skills caches before responding to plugin
    imports, and again after background remote imports complete, so the next
    `plugin/list` reloads fresh state
    - keep marketplace source parsing encapsulated behind
    `is_local_marketplace_source(...)` instead of re-exporting the internal
    enum
    - add core and app-server coverage for the synchronous local import path
    and the pending remote import path
    
    ## Verification
    
    - `cargo test -p codex-app-server-protocol`
    - `cargo test -p codex-core` (currently fails an existing unrelated
    test:
    `config_loader::tests::cli_override_can_update_project_local_mcp_server_when_project_is_trusted`)
    - `cargo test` (currently fails existing `codex-app-server` integration
    tests in MCP/skills/thread-start areas, plus the unrelated `codex-core`
    failure above)
  • [codex] Revoke ChatGPT tokens on logout (#17825)
    ## Summary
    
    This changes Codex logout so managed ChatGPT auth is revoked against
    AuthAPI before local auth state is removed. CLI logout, TUI `/logout`,
    and the app-server account logout path now use the token-revoking logout
    flow instead of only deleting `auth.json` / credential store state.
    
    ## Root Cause
    
    Logout previously cleared only local auth storage. That removed Codex's
    local credentials but did not ask the backend to invalidate the
    refresh/access token state associated with a managed ChatGPT login.
    
    ## Behavior
    
    For managed ChatGPT auth, logout sends the stored refresh token to
    `https://auth.openai.com/oauth/revoke` with `token_type_hint:
    refresh_token` and the Codex OAuth client id, then deletes all local
    auth stores after revocation succeeds. If only an access token is
    available, it falls back to revoking that access token. API key auth and
    externally supplied `chatgptAuthTokens` are still only cleared locally
    because Codex does not own a refresh token for those modes.
    
    Revocation failures are fail-closed: if Codex cannot load stored auth or
    the backend revoke call fails, logout returns an error and leaves local
    auth in place so the user can retry instead of silently clearing local
    state while backend tokens remain valid.
    
    ## Validation
    ran local version of `codex-cli` with staging overrides/harness for auth
    
    ran `codex login` then `codex logout`:
    
    saw auth.json clear and  backend revocation endpoints were called
    
    ```
    POST /oauth/revoke
    status: 200
    
    revoking access token
    should clear auth session
    clearing auth session due to token revocation
    successfully revoked session and access token
    CANONICAL-API-LINE Response: status='200' method='POST' path='/oauth/revoke
    ```
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • codex: split thread/read view loading (#18231)
    Summary
    - refactor thread/read into explicit persisted-load, live-load, and
    merge steps
    - preserve existing SQLite/filesystem/live-thread behavior exactly
    - keep ThreadStore migration out of this PR so the next PR is easier to
    review
    
    Validation
    - this one's a pure reorganization that relies on existing test coverage
  • Refactor config loading to use filesystem abstraction (#18209)
    Initial pass propagating FileSystem through config loading.
  • fix(app-server): replay token usage after resume and fork (#18023)
    ## Problem
    
    When a user resumed or forked a session, the TUI could render the
    restored thread history immediately, but it did not receive token usage
    until a later model turn emitted a fresh usage event. That left the
    context/status UI blank or stale during the exact window where the user
    expects resumed state to look complete. Core already reconstructed token
    usage from the rollout; the missing behavior was app-server lifecycle
    replay to the client that just attached.
    
    ## Mental model
    
    Token usage has two representations. The rollout is the durable source
    of historical `TokenCount` events, and the core session cache is the
    in-memory snapshot reconstructed from that rollout on resume or fork.
    App-server v2 clients do not read core state directly; they learn about
    usage through `thread/tokenUsage/updated`. The fix keeps those roles
    separate: core exposes the restored `TokenUsageInfo`, and app-server
    sends one targeted notification after a successful `thread/resume` or
    `thread/fork` response when that restored snapshot exists.
    
    This notification is not a new model event. It is a replay of
    already-persisted state for the client that just attached. That
    distinction matters because using the normal core event path here would
    risk duplicating `TokenCount` entries in the rollout and making future
    resumes count historical usage twice.
    
    ## Non-goals
    
    This change does not add a new protocol method or payload shape. It
    reuses the existing v2 `thread/tokenUsage/updated` notification and the
    TUI’s existing handler for that notification.
    
    This change does not alter how token usage is computed, accumulated,
    compacted, or written during turns. It only exposes the token usage that
    resume and fork reconstruction already restored.
    
    This change does not broadcast historical usage replay to every
    subscribed client. The replay is intentionally scoped to the connection
    that requested resume or fork so already-attached clients are not
    surprised by an old usage update while they may be rendering live
    activity.
    
    ## Tradeoffs
    
    Sending the usage notification after the JSON-RPC response preserves a
    clear lifecycle order: the client first receives the thread object, then
    receives restored usage for that thread. The tradeoff is that usage is
    still a notification rather than part of the `thread/resume` or
    `thread/fork` response. That keeps the protocol shape stable and avoids
    duplicating usage fields across response types, but clients must
    continue listening for notifications after receiving the response.
    
    The helper selects the latest non-in-progress turn id for the replayed
    usage notification. This is conservative because restored usage belongs
    to completed persisted accounting, not to newly attached in-flight work.
    The fallback to the last turn preserves a stable wire payload for
    unusual histories, but histories with no meaningful completed turn still
    have a weak attribution story.
    
    ## Architecture
    
    Core already seeds `Session` token state from the last persisted rollout
    `TokenCount` during `InitialHistory::Resumed` and
    `InitialHistory::Forked`. The new core accessor exposes the complete
    `TokenUsageInfo` through `CodexThread` without giving app-server direct
    session mutation authority.
    
    App-server calls that accessor from three lifecycle paths: cold
    `thread/resume`, running-thread resume/rejoin, and `thread/fork`. In
    each path, the server sends the normal response first, then calls a
    shared helper that converts core usage into
    `ThreadTokenUsageUpdatedNotification` and sends it only to the
    requesting connection.
    
    The tests build fake rollouts with a user turn plus a persisted token
    usage event. They then exercise `thread/resume` and `thread/fork`
    without starting another model turn, proving that restored usage arrives
    before any next-turn token event could be produced.
    
    ## Observability
    
    The primary debug path is the app-server JSON-RPC stream. After
    `thread/resume` or `thread/fork`, a client should see the response
    followed by `thread/tokenUsage/updated` when the source rollout includes
    token usage. If the notification is absent, check whether the rollout
    contains an `event_msg` payload of type `token_count`, whether core
    reconstruction seeded `Session::token_usage_info`, and whether the
    connection stayed attached long enough to receive the targeted
    notification.
    
    The notification is sent through the existing
    `OutgoingMessageSender::send_server_notification_to_connections` path,
    so existing app-server tracing around server notifications still
    applies. Because this is a replay, not a model turn event, debugging
    should start at the resume/fork handlers rather than the turn event
    translation in `bespoke_event_handling`.
    
    ## Tests
    
    The focused regression coverage is `cargo test -p codex-app-server
    emits_restored_token_usage`, which covers both resume and fork. The core
    reconstruction guard is `cargo test -p codex-core
    record_initial_history_seeds_token_info_from_rollout`.
    
    Formatting and lint/fix passes were run with `just fmt`, `just fix -p
    codex-core`, and `just fix -p codex-app-server`. Full crate test runs
    surfaced pre-existing unrelated failures in command execution and plugin
    marketplace tests; the new token usage tests passed in focused runs and
    within the app-server suite before the unrelated command execution
    failure.
  • Refactor AGENTS.md discovery into AgentsMdManager (#18035)
    Encapsulate Agents MD processing a bit and drop user_instructions_path
    from config.
  • Auto-upgrade configured marketplaces (#17425)
    ## Summary
    - Add best-effort auto-upgrade for user-configured Git marketplaces
    recorded in `config.toml`.
    - Track the last activated Git revision with `last_revision` so
    unchanged marketplace sources skip clone work.
    - Trigger the upgrade from plugin startup and `plugin/list`, while
    preserving existing fail-open plugin behavior with warning logs rather
    than new user-visible errors.
    
    ## Details
    - Remote configured marketplaces use `git ls-remote` to compare the
    source/ref against the recorded revision.
    - Upgrades clone into a staging directory, validate that
    `.agents/plugins/marketplace.json` exists and that the manifest name
    matches the configured marketplace key, then atomically activate the new
    root.
    - Local `.agents/plugins/marketplace.json` marketplaces remain live
    filesystem state and are not auto-pulled.
    - Existing non-curated plugin cache refresh is kicked after successful
    marketplace root upgrades.
    
    ## Validation
    - `just write-config-schema`
    - `cargo test -p codex-core marketplace_upgrade`
    - `cargo check -p codex-cli -p codex-app-server`
    - `just fix -p codex-core`
    
    Did not run the complete `cargo test` suite because the repo
    instructions require asking before a full core workspace run.
  • fix: auth preflight (#18117)
    Fix app-server startup when `remote_control = true` is enabled without
    ChatGPT auth.
    
    Remote control now starts in a degraded/retrying state instead of
    failing app-server initialization, so Desktop is not stranded before the
    initial initialize handshake.
  • chore: unify memory drop endpoints (#18134)
    Unify all the memories drop behind a single implementation that drops
    both the main memories and the extensions
  • Fix MCP startup cancellation through app server (#18078)
    Addresses https://github.com/openai/codex/issues/17143
    
    Problem: TUI interrupts without an active turn stopped cancelling slow
    MCP startup after routing through the app-server APIs.
    
    Solution: Route no-active-turn interrupts through app-server as startup
    cancels, acknowledge them immediately, and emit cancelled MCP startup
    updates.
    
    Testing: I manually confirmed that MCP cancellation didn't work prior to
    this PR and works after the fix was in place.
  • Extract plugin loading and marketplace logic into codex-core-plugins (#18070)
    Split plugin loading, marketplace, and related infrastructure out of
    core into codex-core-plugins, while keeping the core-facing
    configuration and orchestration flow in codex-core.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • [codex][mcp] Add resource uri meta to tool call item. (#17831)
    - [x] Add resource uri meta to tool call item so that the app-server
    client can start prefetching resources immediately without loading mcp
    server status.
  • Async config loading (#18022)
    Parts of config will come from executor. Prepare for that by making
    config loading methods async.
  • Migrate archive/unarchive to local ThreadStore (#17892)
    # Summary
    - implement local ThreadStore archive/unarchive operations
    - implement local ThreadStore read_thread operation
    - break up the various ThreadStore local method implementations into
    separate files
    - migrate app-server archive/unarchive and core archive fixture to use
    ThreadStore (but not all read operations yet!)
    - use the ThreadStore's read operation as a proxy check for thread
    persistence/existence in the app server code
    - move all other filesystem operations related to archive (path
    validation etc) into the local thread store.
    
    # Tests
    - add dedicated local store archive/unarchive tests
  • app-server: track remote-control seq IDs per stream (#17902)
    ## Summary
    
    - Track outbound remote-control sequence IDs independently for each
    client stream.
    - Retain unacked outbound messages per stream using FIFO buffers.
    - Require stream-scoped acks and update tests for contiguous per-stream
    sequencing.
    
    ## Why
    
    The remote-control peer uses outbound sequence gaps to detect lost
    messages and re-initialize. A single global outbound sequence counter
    can create apparent gaps on an individual stream when another stream
    receives an interleaved message.
    
    ## Validation
    
    - `just fmt`
    - `cargo test -p codex-app-server remote_control`
    - `just fix -p codex-app-server`
    - `git diff --check`
  • [codex] Add local thread store listing (#17824)
    Builds on top of #17659 
    
    Move the filesystem + sqlite thread listing-related operations inside of
    a local ThreadStore implementation and call ThreadStore from the places
    that used to perform these filesystem/sqlite operations.
    
    This is the first of a series of PRs that will implement the rest of the
    local ThreadStore.
    
    Testing:
    - added unit tests for the thread store implementation
    - adjusted some unit tests in the realtime + personality packages whose
    callsites changed. Specifically I'm trying to hide ThreadMetadata inside
    of the local implementation and make ThreadMetadata a sqlite
    implementation detail concern rather than a public interface, preferring
    the more generate StoredThread interface instead
    - added a corner case test for the personality migration package that
    wasn't covered by the existing test suite
    - adjust the behavior of searched thread listing to run the existing
    local rollout repair/backfill pass _before_ querying SQLite results, so
    callers using ThreadStore::list_threads do not miss matches after a
    partial metadata warm-up
  • Register agent identities behind use_agent_identity (#17386)
    ## Summary
    
    Stack PR 2 of 4 for feature-gated agent identity support.
    
    This PR adds agent identity registration behind
    `features.use_agent_identity`. It keeps the app-server protocol
    unchanged and starts registration after ChatGPT auth exists rather than
    requiring a client restart.
    
    ## Stack
    
    - PR1: https://github.com/openai/codex/pull/17385 - add
    `features.use_agent_identity`
    - PR2: https://github.com/openai/codex/pull/17386 - this PR
    - PR3: https://github.com/openai/codex/pull/17387 - register agent tasks
    when enabled
    - PR4: https://github.com/openai/codex/pull/17388 - use `AgentAssertion`
    downstream when enabled
    
    ## Validation
    
    Covered as part of the local stack validation pass:
    
    - `just fmt`
    - `cargo test -p codex-core --lib agent_identity`
    - `cargo test -p codex-core --lib agent_assertion`
    - `cargo test -p codex-core --lib websocket_agent_task`
    - `cargo test -p codex-api api_bridge`
    - `cargo build -p codex-cli --bin codex`
    
    ## Notes
    
    The full local app-server E2E path is still being debugged after PR
    creation. The current branch stack is directionally ready for review
    while that follow-up continues.
  • fix: add websocket capability token hash support (#17871)
    ## Summary
    - Allow app-server websocket capability auth to accept a precomputed
    SHA-256 digest via `--ws-token-sha256`.
    - Keep token-file support and enforce exactly one capability token
    source.
    - Document the new auth flag.
    
    ## Testing
    - `just fmt`
    - `cargo test -p codex-app-server transport::auth::tests`
    - `cargo test -p codex-app-server
    websocket_capability_token_sha256_args_parse`
    - `cargo test -p codex-cli app_server_capability_token_flags_parse`
    - `cargo clippy -p codex-app-server --all-targets -- -D warnings`
    - `just fix -p codex-cli`
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Make skill loading filesystem-aware (#17720)
    Migrates skill loading to support reading repo skills from the remote
    environment.
  • Spread AbsolutePathBuf (#17792)
    Mechanical change to promote absolute paths through code.
  • [codex-analytics] enable general analytics by default (#17389)
    ## Summary
    - Make GeneralAnalytics stable and enabled by default.
    - Update feature tests and app-server lifecycle fixtures for explicit
    general_analytics=false.
    - Keep app-server integration tests isolated from host managed config so
    explicit feature fixtures are deterministic.
    
    ## Validation
    - cargo test -p codex-features
    - cargo test -p codex-app-server general_analytics (matched 0 tests)
    - cargo test -p codex-app-server thread_start_
    - cargo test -p codex-app-server thread_fork_
    - cargo test -p codex-app-server thread_resume_
    - cargo test -p codex-app-server
    config_read_includes_system_layer_and_overrides
  • [codex] Fix app-server initialized request analytics build (#17830)
    Problem: PR #17372 moved initialized request handling into
    `dispatch_initialized_client_request`, leaving analytics code that uses
    `connection_id` without a local binding and breaking `codex-app-server`
    builds.
    
    Solution: Restore the `connection_id` binding from
    `connection_request_id` before initialized request validation and
    analytics tracking.
  • app-server: prepare to run initialized rpcs concurrently (#17372)
    ## Summary
    
    - Refactors `MessageProcessor` and per-connection session state so
    initialized service RPC handling can be moved into spawned tasks in a
    follow-up PR.
    - Shares the processor and initialized session data with
    `Arc`/`OnceLock` instead of mutable borrowed connection state.
    - Keeps initialized request handling synchronous in this PR; it does
    **not** call `tokio::spawn` for service RPCs yet.
    
    ## Testing
    
    - `just fmt`
    - `cargo test -p codex-app-server` *(fails on existing hardening gaps
    covered by #17375, #17376, and #17377; the pipelined config regression
    passed before the unrelated failures)*
    - `just fix -p codex-app-server`
  • fix: Revert danger-full-access denylist-only mode (#17732)
    ## Summary
    
    - Reverts openai/codex#16946 and removes the danger-full-access
    denylist-only network mode.
    - Removes the corresponding config requirements, app-server
    protocol/schema, config API, TUI debug output, and network proxy
    behavior.
    - Drops stale tests that depended on the reverted mode while preserving
    newer managed allowlist-only coverage.
    
    ## Verification
    
    - `just write-app-server-schema`
    - `just fmt`
    - `cargo test -p codex-config network_requirements`
    - `cargo test -p codex-core network_proxy_spec`
    - `cargo test -p codex-core
    managed_network_proxy_decider_survives_full_access_start`
    - `cargo test -p codex-app-server map_requirements_toml_to_api`
    - `cargo test -p codex-tui debug_config_output`
    - `cargo test -p codex-app-server-protocol`
    - `just fix -p codex-config -p codex-core -p codex-app-server-protocol
    -p codex-app-server -p codex-tui`
    - `git diff --cached --check`
    
    Not run: full workspace `cargo test` (repo instructions ask for
    confirmation before that broader run).
  • Moving updated-at timestamps to unique millisecond times (#17489)
    To allow the ability to have guaranteed-unique cursors, we make two
    important updates:
    * Add new updated_at_ms and created_at_ms columns that are in
    millisecond precision
    * Guarantee uniqueness -- if multiple items are inserted at the same
    millisecond, bump the new one by one millisecond until it becomes unique
    
    This lets us use single-number cursors for forwards and backwards paging
    through resultsets and guarantee that the cursor is a fixed point to do
    (timestamp > cursor) and get new items only.
    
    This updated implementation is backwards-compatible since multiple
    appservers can be running and won't handle the previous method well.
  • Add realtime output modality and transcript events (#17701)
    - Add outputModality to thread/realtime/start and wire text/audio output
    selection through app-server, core, API, and TUI.\n- Rename the realtime
    transcript delta notification and add a separate transcript done
    notification that forwards final text from item done without correlating
    it with deltas.
  • [codex-analytics] feature plumbing and emittance (#16640)
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/16640).
    * #16870
    * #16706
    * #16641
    * __->__ #16640
  • Refactor plugin loading to async (#17747)
    Simplifies skills migration.
  • [codex] Refactor marketplace add into shared core flow (#17717)
    ## Summary
    
    Move `codex marketplace add` onto a shared core implementation so the
    CLI and app-server path can use one source of truth.
    
    This change:
    - adds shared marketplace-add orchestration in `codex-core`
    - switches the CLI command to call that shared implementation
    - removes duplicated CLI-only marketplace add helpers
    - preserves focused parser and add-path coverage while moving the shared
    behavior into core tests
    
    ## Why
    
    The new `marketplace/add` RPC should reuse the same underlying
    marketplace-add flow as the CLI. This refactor lands that consolidation
    first so the follow-up app-server PR can be mostly protocol and handler
    wiring.
    
    ## Validation
    
    - `cargo test -p codex-core marketplace_add`
    - `cargo test -p codex-cli marketplace_cmd`
    - `just fix -p codex-core`
    - `just fix -p codex-cli`
    - `just fmt`
  • [codex] Add symlink flag to fs metadata (#17719)
    Add `is_symlink` to FsMetadata struct.
  • Add turn item injection API (#17703)
    ## Summary
    - Add `turn/inject_items` app-server v2 request support for appending
    raw Responses API items to a loaded thread history without starting a
    turn.
    - Generate JSON schema and TypeScript protocol artifacts for the new
    params and empty response.
    - Document the new endpoint and include a request/response example.
    - Preserve compatibility with the typo alias `turn/injet_items` while
    returning the canonical method name.
    
    ## Testing
    - Not run (not requested)
  • app-server: Only unload threads which were unused for some time (#17398)
    Currently app-server may unload actively running threads once the last
    connection disconnects, which is not expected.
    Instead track when was the last active turn & when there were any
    subscribers the last time, also add 30 minute idleness/no subscribers
    timer to reduce the churn.
  • Do not fail thread start when trust persistence fails (#17595)
    Addresses #17593
    
    Problem: A regression introduced in
    https://github.com/openai/codex/pull/16492 made thread/start fail when
    Codex could not persist trusted project state, which crashes startup for
    users with read-only config.toml.
    
    Solution: Treat trusted project persistence as best effort and keep the
    current thread's config trusted in memory when writing config.toml
    fails.
  • Suppress duplicate compaction and terminal wait events (#17601)
    Addresses #17514
    
    Problem: PR #16966 made the TUI render the deprecated context-compaction
    notification, while v2 could also receive legacy unified-exec
    interaction items alongside terminal-interaction notifications, causing
    duplicate "Context compacted" and "Waited for background terminal"
    messages.
    
    Solution: Suppress deprecated context-compaction notifications and
    legacy unified-exec interaction command items from the app-server v2
    projection, and render canonical context-compaction items through the
    existing TUI info-event path.
  • Run exec-server fs operations through sandbox helper (#17294)
    ## Summary
    - run exec-server filesystem RPCs requiring sandboxing through a
    `codex-fs` arg0 helper over stdin/stdout
    - keep direct local filesystem execution for `DangerFullAccess` and
    external sandbox policies
    - remove the standalone exec-server binary path in favor of top-level
    arg0 dispatch/runtime paths
    - add sandbox escape regression coverage for local and remote filesystem
    paths
    
    ## Validation
    - `just fmt`
    - `git diff --check`
    - remote devbox: `cd codex-rs && bazel test --bes_backend=
    --bes_results_url= //codex-rs/exec-server:all` (6/6 passed)
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Expose instruction sources (AGENTS.md) via app server (#17506)
    Addresses #17498
    
    Problem: The TUI derived /status instruction source paths from the local
    client environment, which could show stale <none> output or incorrect
    paths when connected to a remote app server.
    
    Solution: Add an app-server v2 instructionSources snapshot to thread
    start/resume/fork responses, default it to an empty list when older
    servers omit it, and render TUI /status from that server-provided
    session data.
    
    Additional context: The app-server field is intentionally named
    instructionSources rather than AGENTS.md-specific terminology because
    the loaded instruction sources can include global instructions, project
    AGENTS.md files, AGENTS.override.md, user-defined instruction files, and
    future dynamic sources.
  • Pass turn id with feedback uploads (#17314)
    ## Summary
    - Add an optional `tags` dictionary to feedback upload params.
    - Capture the active app-server turn id in the TUI and submit it as
    `tags.turn_id` with `/feedback` uploads.
    - Merge client-provided feedback tags into Sentry feedback tags while
    preserving reserved system fields like `thread_id`, `classification`,
    `cli_version`, `session_source`, and `reason`.
    
    ## Behavior / impact
    Existing feedback upload callers remain compatible because `tags` is
    optional and nullable. The wire shape is still a normal JSON object /
    TypeScript dictionary, so adding future feedback metadata will not
    require a new top-level protocol field each time. This change only adds
    feedback metadata for Codex CLI/TUI uploads; it does not affect existing
    pipelines, DAGs, exports, or downstream consumers unless they choose to
    read the new `turn_id` feedback tag.
    
    ## Tests
    - `cargo fmt -- --config imports_granularity=Item` passed; stable
    rustfmt warned that `imports_granularity` is nightly-only.
    - `cargo run -p codex-app-server-protocol --bin write_schema_fixtures`
    - `cargo test -p codex-feedback
    upload_tags_include_client_tags_and_preserve_reserved_fields`
    - `cargo test -p codex-app-server-protocol
    schema_fixtures_match_generated`
    - `cargo test -p codex-tui build_feedback_upload_params`
    - `cargo test -p codex-tui
    live_app_server_turn_started_sets_feedback_turn_id`
    - `cargo check -p codex-app-server --tests`
    - `git diff --check`
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Fix thread/list cwd filtering for Windows verbatim paths (#17414)
    Addresses #17302
    
    Problem: `thread/list` compared cwd filters with raw path equality, so
    `resume --last` could miss Windows sessions when the saved cwd used a
    verbatim path form and the current cwd did not.
    
    Solution: Normalize cwd comparisons through the existing path comparison
    utilities before falling back to direct equality, and add Windows
    regression coverage for verbatim paths. I made this a general utility
    function and replaced all of the duplicated instance of it across the
    code base.
  • [mcp] Support MCP Apps part 3 - Add mcp tool call support. (#17364)
    - [x] Add a new app-server method so that MCP Apps can call their own
    MCP server directly.
  • representing guardian review timeouts in protocol types (#17381)
    ## Summary
    
    - Add `TimedOut` to Guardian/review carrier types:
      - `ReviewDecision::TimedOut`
      - `GuardianAssessmentStatus::TimedOut`
      - app-server v2 `GuardianApprovalReviewStatus::TimedOut`
    - Regenerate app-server JSON/TypeScript schemas for the new wire shape.
    - Wire the new status through core/app-server/TUI mappings with
    conservative fail-closed handling.
    - Keep `TimedOut` non-user-selectable in the approval UI.
    
    **Does not change runtime behavior yet; emitting `TimeOut` and
    parent-model timeout messaging will come in followup PRs**
  • Revert "Option to Notify Workspace Owner When Usage Limit is Reached" (#17391)
    Reverts openai/codex#16969
    
    #sev3-2026-04-10-accountscheckversion-500s-for-openai-workspace-7300
  • fix(guardian, app-server): introduce guardian review ids (#17298)
    ## Description
    
    This PR introduces `review_id` as the stable identifier for guardian
    reviews and exposes it in app-server `item/autoApprovalReview/started`
    and `item/autoApprovalReview/completed` events.
    
    Internally, guardian rejection state is now keyed by `review_id` instead
    of the reviewed tool item ID. `target_item_id` is still included when a
    review maps to a concrete thread item, but it is no longer overloaded as
    the review lifecycle identifier.
    
    ## Motivation
    
    We'd like to give users the ability to preempt a guardian review while
    it's running (approve or decline).
    
    However, we can't implement the API that allows the user to override a
    running guardian review because we didn't have a unique `review_id` per
    guardian review. Using `target_item_id` is not correct since:
    - with execve reviews, there can be multiple execve calls (and therefore
    guardian reviews) per shell command
    - with network policy reviews, there is no target item ID
    
    The PR that actually implements user overrides will use `review_id` as
    the stable identifier.