Commit Graph

4081 Commits

  • Add realtime audio device config (#12849)
    ## Summary
    - add top-level realtime audio config for microphone and speaker
    selection
    - apply configured devices when starting realtime capture and playback
    - keep missing-device behavior on the system default fallback path
    
    ## Validation
    - just write-config-schema
    - cargo test -p codex-core realtime_audio
    - cargo test -p codex-tui
    - just fix -p codex-core
    - just fix -p codex-tui
    - just fmt
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • 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`.
  • Allow clients not to send summary as an option (#12950)
    Summary is a required parameter on UserTurn. Ideally we'd like the core
    to decide the appropriate summary level.
    
    Make the summary optional and don't send it when not needed.
  • tui: use thread_id for resume/fork cwd resolution (#12727)
    ## Summary
    - make resume/fork targets explicit and typed as `SessionTarget { path,
    thread_id }` (non-optional `thread_id`)
    - resolve `thread_id` centrally via `resolve_session_thread_id(...)`:
    - use CLI input directly when it is a UUID (`--resume <uuid>` / `--fork
    <uuid>`)
    - otherwise read `thread_id` from rollout `SessionMeta` for path-based
    selections (picker, `--resume-last`, name-based resume/fork)
    - use `thread_id` to read cwd from SQLite first during resume/fork cwd
    resolution
    - keep rollout fallback for cwd resolution when SQLite is unavailable or
    does not return thread metadata (`TurnContext` tail, then `SessionMeta`)
    - keep the resume picker open when a selected row has unreadable session
    metadata, and show an inline recoverable error instead of aborting the
    TUI
    
    ## Why
    This removes ad-hoc rollout filename parsing and makes resume/fork
    target identity explicit. The resume/fork cwd check can use indexed
    SQLite lookup by `thread_id` in the common path, while preserving
    rollout-based fallback behavior. It also keeps malformed legacy rows
    recoverable in the picker instead of letting a selection failure unwind
    the app.
    
    ## Notes
    - minimal TUI-only change; no schema/protocol changes
    - includes TUI test coverage for SQLite cwd precedence when `thread_id`
    is available
    - includes TUI regression coverage for picker inline error rendering /
    non-fatal unreadable session rows
    
    ## Codex author
    `codex resume 019c9205-7f8b-7173-a2a2-f082d4df3de3`
  • feat: include sandbox config with escalation request (#12839)
    ## Why
    
    Before this change, an escalation approval could say that a command
    should be rerun, but it could not carry the sandbox configuration that
    should still apply when the escalated command is actually spawned.
    
    That left an unsafe gap in the `zsh-fork` skill path: skill scripts
    under `scripts/` that did not declare permissions could be escalated
    without a sandbox, and scripts that did declare permissions could lose
    their bounded sandbox on rerun or cached session approval.
    
    This PR extends the escalation protocol so approvals can optionally
    carry sandbox configuration all the way through execution. That lets the
    shell runtime preserve the intended sandbox instead of silently widening
    access.
    
    We likely want a single permissions type for this codepath eventually,
    probably centered on `Permissions`. For now, the protocol needs to
    represent both the existing `PermissionProfile` form and the fuller
    `Permissions` form, so this introduces a temporary disjoint union,
    `EscalationPermissions`, to carry either one.
    
    Further, this means that today, a skill either:
    
    - does not declare any permissions, in which case it is run using the
    default sandbox for the turn
    - specifies permissions, in which case the skill is run using that exact
    sandbox, which might be more restrictive than the default sandbox for
    the turn
    
    We will likely change the skill's permissions to be additive to the
    existing permissions for the turn.
    
    ## What Changed
    
    - Added `EscalationPermissions` to `codex-protocol` so escalation
    requests can carry either a `PermissionProfile` or a full `Permissions`
    payload.
    - Added an explicit `EscalationExecution` mode to the shell escalation
    protocol so reruns distinguish between `Unsandboxed`, `TurnDefault`, and
    `Permissions(...)` instead of overloading `None`.
    - Updated `zsh-fork` shell reruns to resolve `TurnDefault` at execution
    time, which keeps ordinary `UseDefault` commands on the turn sandbox and
    preserves turn-level macOS seatbelt profile extensions.
    - Updated the `zsh-fork` skill path so a skill with no declared
    permissions inherits the conversation's effective sandbox instead of
    escalating unsandboxed.
    - Updated the `zsh-fork` skill path so a skill with declared permissions
    reruns with exactly those permissions, including when a cached session
    approval is reused.
    
    ## Testing
    
    - Added unit coverage in
    `core/src/tools/runtimes/shell/unix_escalation.rs` for the explicit
    `UseDefault` / `RequireEscalated` / `WithAdditionalPermissions`
    execution mapping.
    - Added unit coverage in
    `core/src/tools/runtimes/shell/unix_escalation.rs` for macOS seatbelt
    extension preservation in both the `TurnDefault` and
    explicit-permissions rerun paths.
    - Added integration coverage in `core/tests/suite/skill_approval.rs` for
    permissionless skills inheriting the turn sandbox and explicit skill
    permissions remaining bounded across cached approval reuse.
  • Remove noisy log (#12929)
    This log message floods logs on windows
  • Log js_repl nested tool responses in rollout history (#12837)
    ## Summary
    
    - add tracing-based diagnostics for nested `codex.tool(...)` calls made
    from `js_repl`
    - emit a bounded, sanitized summary at `info!`
    - emit the exact raw serialized response object or error string seen by
    JavaScript at `trace!`
    - document how to enable these logs and where to find them, especially
    for `codex app-server`
    
    ## Why
    
    Nested `codex.tool(...)` calls inside `js_repl` are a debugging
    boundary: JavaScript sees the tool result, but that result is otherwise
    hard to inspect from outside the kernel.
    
    This change adds explicit tracing for that path using the repo’s normal
    observability pattern:
    - `info` for compact summaries
    - `trace` for exact raw payloads when deep debugging is needed
    
    ## What changed
    
    - `js_repl` now summarizes nested tool-call results across the response
    shapes it can receive:
      - message content
      - function-call outputs
      - custom tool outputs
      - MCP tool results and MCP error results
      - direct error strings
    - each nested `codex.tool(...)` completion logs:
      - `exec_id`
      - `tool_call_id`
      - `tool_name`
      - `ok`
      - a bounded summary struct describing the payload shape
    - at `trace`, the same path also logs the exact serialized response
    object or error string that JavaScript received
    - docs now include concrete logging examples for `codex app-server`
    - unit coverage was added for multimodal function output summaries and
    error summaries
    
    ## How to use it
    
    ### Summary-only logging
    
    Set:
    
    ```sh
    RUST_LOG=codex_core::tools::js_repl=info
    ```
    
    For `codex app-server`, tracing output is written to the server process
    `stderr`.
    
    Example:
    
    ```sh
    RUST_LOG=codex_core::tools::js_repl=info \
    LOG_FORMAT=json \
    codex app-server \
    2> /tmp/codex-app-server.log
    ```
    
    This emits bounded summary lines for nested `codex.tool(...)` calls.
    
    ### Full raw debugging
    
    Set:
    
    ```sh
    RUST_LOG=codex_core::tools::js_repl=trace
    ```
    
    Example:
    
    ```sh
    RUST_LOG=codex_core::tools::js_repl=trace \
    LOG_FORMAT=json \
    codex app-server \
    2> /tmp/codex-app-server.log
    ```
    
    At `trace`, you get:
    - the same `info` summary line
    - a `trace` line with the exact serialized response object seen by
    JavaScript
    - or the exact error string if the nested tool call failed
    
    ### Where the logs go
    
    For `codex app-server`, these logs go to process `stderr`, so redirect
    or capture `stderr` to inspect them.
    
    Example:
    
    ```sh
    RUST_LOG=codex_core::tools::js_repl=trace \
    LOG_FORMAT=json \
    /Users/fjord/code/codex/codex-rs/target/debug/codex app-server \
    2> /tmp/codex-app-server.log
    ```
    
    Then inspect:
    
    ```sh
    rg "js_repl nested tool call" /tmp/codex-app-server.log
    ```
    
    Without an explicit `RUST_LOG` override, these `js_repl` nested
    tool-call logs are typically not visible.
  • Use model catalog default for reasoning summary fallback (#12873)
    ## Summary
    - make `Config.model_reasoning_summary` optional so unset means use
    model default
    - resolve the optional config value to a concrete summary when building
    `TurnContext`
    - add protocol support for `default_reasoning_summary` in model metadata
    
    ## Validation
    - `cargo test -p codex-core --lib client::tests -- --nocapture`
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • split-debuginfo (#12871)
    Attempt to reduce disk usage in mac ci.
    
    >off - This is the default for platforms with ELF binaries and
    windows-gnu (not Windows MSVC and not macOS). This typically means that
    DWARF debug information can be found in the final artifact in sections
    of the executable. This option is not supported on Windows MSVC. On
    macOS this options prevents the final execution of dsymutil to generate
    debuginfo.
  • Skip history metadata scan for subagents (#12918)
    Summary
    - Skip `history_metadata` scanning when spawning subagents to avoid
    expensive per-spawn history scans.
    - Keeps behavior unchanged for normal sessions.
    
    Testing
      - `cd codex-rs && cargo test -p codex-core` 
    - Failing in this environment (pre-existing and I don't think something
    I did?):
    - `suite::cli_stream::responses_mode_stream_cli` (SIGKILL + OTEL export
    error to http://localhost:14318/v1/logs)
    - `suite::grep_files::grep_files_tool_collects_matches` (unsupported
    call: grep_files)
    - `suite::grep_files::grep_files_tool_reports_empty_results`
    (unsupported call: grep_files)
    
    Co-authored-by: Codex <noreply@openai.com>
  • feat: memories forgetting (#12900)
    Add diff based memory forgetting
  • tui: restore visible line numbers for hidden file links (#12870)
    we recently changed file linking so the model uses markdown links when
    it wants something to be clickable.
    
    This works well across the GUI surfaces because they can render markdown
    cleanly and use the full absolute path in the anchor target.
    
    A previous pass hid the absolute path in the TUI (and only showed the
    label), but that also meant we could lose useful location info when the
    model put the line number or range in the anchor target instead of the
    label.
    
    This follow-up keeps the TUI behavior simple while making local file
    links feel closer to the old TUI file reference style.
    
    key changes:
    - Local markdown file links in the TUI keep the old file-ref feel: code
    styling, no underline, no visible absolute path.
    - If the hidden local anchor target includes a location suffix and the
    label does not already include one, we append that suffix to the visible
    label.
    - This works for single lines, line/column references, and ranges.
    - If the label already includes the location, we leave it alone.
    - normal web links keep the old TUI markdown-link behavior
    
    some examples:
    - `[foo.rs](/abs/path/foo.rs)` renders as `foo.rs`
    - `[foo.rs](/abs/path/foo.rs:45)` renders as `foo.rs:45`
    - `[foo.rs](/abs/path/foo.rs:45:3-48:9)` renders as `foo.rs:45:3-48:9`
    - `[foo.rs:45](/abs/path/foo.rs:45)` stays `foo.rs:45`
    - `[docs](https://example.com/docs)` still renders like a normal web
    link
    
    how it looks:
    <img width="732" height="813" alt="Screenshot 2026-02-26 at 9 27 55 AM"
    src="https://github.com/user-attachments/assets/d51bf236-653a-4e83-96e4-9427f0804471"
    />
  • core: bundle settings diff updates into one dev/user envelope (#12417)
    ## Summary
    - bundle contextual prompt injection into at most one developer message
    plus one contextual user message in both:
      - per-turn settings updates
      - initial context insertion
    - preserve `<model_switch>` across compaction by rebuilding it through
    canonical initial-context injection, instead of relying on
    strip/reattach hacks
    - centralize contextual user fragment detection in one shared definition
    table and reuse it for parsing/compaction logic
    - keep `AGENTS.md` in its natural serialized format:
      - `# AGENTS.md instructions for {dirname}`
      - `<INSTRUCTIONS>...</INSTRUCTIONS>`
    - simplify related tests/helpers and accept the expected snapshot/layout
    updates from bundled multi-part messages
    
    ## Why
    The goal is to converge toward a simpler, more intentional prompt shape
    where contextual updates are consistently represented as one developer
    envelope plus one contextual user envelope, while keeping parsing and
    compaction behavior aligned with that representation.
    
    ## Notable details
    - the temporary `SettingsUpdateEnvelope` wrapper was removed; these
    paths now return `Vec<ResponseItem>` directly
    - local/remote compaction no longer rely on model-switch strip/restore
    helpers
    - contextual user detection is now driven by shared fragment definitions
    instead of ad hoc matcher assembly
    - AGENTS/user instructions are still the same logical context; only the
    synthetic `<user_instructions>` wrapper was replaced by the natural
    AGENTS text format
    
    ## Testing
    - `just fmt`
    - `cargo test -p codex-app-server
    codex_message_processor::tests::extract_conversation_summary_prefers_plain_user_messages
    -- --exact`
    - `cargo test -p codex-core
    compact::tests::collect_user_messages_filters_session_prefix_entries
    --lib -- --exact`
    - `cargo test -p codex-core --test all
    'suite::compact::snapshot_request_shape_pre_turn_compaction_strips_incoming_model_switch'
    -- --exact`
    - `cargo test -p codex-core --test all
    'suite::compact_remote::snapshot_request_shape_remote_pre_turn_compaction_strips_incoming_model_switch'
    -- --exact`
    - `cargo test -p codex-core --test all
    'suite::client::includes_apps_guidance_as_developer_message_when_enabled'
    -- --exact`
    - `cargo test -p codex-core --test all
    'suite::client::includes_developer_instructions_message_in_request' --
    --exact`
    - `cargo test -p codex-core --test all
    'suite::client::includes_user_instructions_message_in_request' --
    --exact`
    - `cargo test -p codex-core --test all
    'suite::client::resume_includes_initial_messages_and_sends_prior_items'
    -- --exact`
    - `cargo test -p codex-core --test all
    'suite::review::review_input_isolated_from_parent_history' -- --exact`
    - `cargo test -p codex-exec --test all
    'suite::resume::exec_resume_last_respects_cwd_filter_and_all_flag' --
    --exact`
    - `cargo test -p core_test_support
    context_snapshot::tests::full_text_mode_preserves_unredacted_text --
    --exact`
    
    ## Notes
    - I also ran several targeted `compact`, `compact_remote`,
    `prompt_caching`, `model_visible_layout`, and `event_mapping` tests
    while iterating on prompt-shape changes.
    - I have not claimed a clean full-workspace `cargo test` from this
    environment because local sandbox/resource conditions have previously
    produced unrelated failures in large workspace runs.
  • Enforce user input length cap (#12823)
    Currently there is no bound on the length of a user message submitted in
    the TUI or through the app server interface. That means users can paste
    many megabytes of text, which can lead to bad performance, hangs, and
    crashes. In extreme cases, it can lead to a [kernel
    panic](https://github.com/openai/codex/issues/12323).
    
    This PR limits the length of a user input to 2**20 (about 1M)
    characters. This value was chosen because it fills the entire context
    window on the latest models, so accepting longer inputs wouldn't make
    sense anyway.
    
    Summary
    - add a shared `MAX_USER_INPUT_TEXT_CHARS` constant in codex-protocol
    and surface it in TUI and app server code
    - block oversized submissions in the TUI submit flow and emit error
    history cells when validation fails
    - reject heavy app-server requests with JSON-RPC `-32602` and structured
    `input_too_large` data, plus document the behavior
    
    Testing
    - ran the IDE extension with this change and verified that when I
    attempt to paste a user message that's several MB long, it correctly
    reports an error instead of crashing or making my computer hot.
  • Hide local file link destinations in TUI markdown (#12705)
    ## Summary
    - hide appended destinations for local path-style markdown links in the
    TUI renderer
    - keep web links rendering with their visible destination and style link
    labels consistently
    - add markdown renderer tests and a snapshot for the new file-link
    output
    
    ## Testing
    - just fmt
    - cargo test -p codex-tui
    <img width="1120" height="968" alt="image"
    src="https://github.com/user-attachments/assets/490e8eda-ae47-4231-89fa-b254a1f83eed"
    />
  • Reduce js_repl Node version requirement to 22.22.0 (#12857)
    ## Summary
    
    Lower the `js_repl` minimum Node version from `24.13.1` to `22.22.0`.
    
    This updates the enforced minimum in `codex-rs/node-version.txt` and the
    corresponding user-facing `/experimental` description for the JavaScript
    REPL feature.
    
    ## Rationale
    
    The previous `24.13.1` floor was stricter than necessary for `js_repl`.
    I validated the REPL kernel behavior under Node `22.22.0` still works.
    
    ## Why `22.22.0`
    
    `22.22.0` is a current, widely packaged Node 22 release across common
    developer environments and distros, including Homebrew `node@22`, Fedora
    `nodejs22`, Arch `nodejs-lts-jod`, and Debian testing. That makes it a
    better exact floor than guessing at an older `22.x` patch we have not
    validated.
    
    `22.x` is also a maintenance branch that will be supported through April
    2027, where the previous maintenance branch of `20.x` is only supported
    through April of this year.
    
    ## Changes
    
    - Update `codex-rs/node-version.txt` from `24.13.1` to `22.22.0`
    - Update the `/experimental` JavaScript REPL description to say
    `Requires Node >= v22.22.0 installed.`
  • Skip system skills for extra roots (#12744)
    When extra roots is set do not load system skills.
  • Try fixing windows pipeline (#12848)
    # External (non-OpenAI) Pull Request Requirements
    
    Before opening this Pull Request, please read the dedicated
    "Contributing" markdown file or your PR may be closed:
    https://github.com/openai/codex/blob/main/docs/contributing.md
    
    If your PR conforms to our contribution guidelines, replace this text
    with a detailed and high quality description of your changes.
    
    Include a link to a bug report or enhancement request.
  • Clarify device auth login hint (#12813)
    Mention device auth for remote login
  • Disable js_repl when Node is incompatible at startup (#12824)
    ## Summary
    - validate `js_repl` Node compatibility during session startup when the
    experiment is enabled
    - if Node is missing or too old, disable `js_repl` and
    `js_repl_tools_only` for the session before tools and instructions are
    built
    - surface that startup disablement to users through the existing startup
    warning flow instead of only logging it
    - reuse the same compatibility check in js_repl kernel startup so
    startup gating and runtime behavior stay aligned
    - add a regression test that verifies the warning is emitted and that
    the first advertised tool list omits `js_repl` and `js_repl_reset` when
    Node is incompatible
    
    ## Why
    Today `js_repl` can be advertised based only on the feature flag, then
    fail later when the kernel starts. That makes the available tool list
    inaccurate at the start of a conversation, and users do not get a clear
    explanation for why the tool is unavailable.
    
    This change makes tool availability reflect real startup checks, keeps
    the advertised tool set stable for the lifetime of the session, and
    gives users a visible warning when `js_repl` is disabled.
    
    ## Testing
    - `just fmt`
    - `cargo test -p codex-core --test all
    js_repl_is_not_advertised_when_startup_node_is_incompatible`
  • feat: include available decisions in command approval requests (#12758)
    Command-approval clients currently infer which choices to show from
    side-channel fields like `networkApprovalContext`,
    `proposedExecpolicyAmendment`, and `additionalPermissions`. That makes
    the request shape harder to evolve, and it forces each client to
    replicate the server's heuristics instead of receiving the exact
    decision list for the prompt.
    
    This PR introduces a mapping between `CommandExecutionApprovalDecision`
    and `codex_protocol::protocol::ReviewDecision`:
    
    ```rust
    impl From<CoreReviewDecision> for CommandExecutionApprovalDecision {
        fn from(value: CoreReviewDecision) -> Self {
            match value {
                CoreReviewDecision::Approved => Self::Accept,
                CoreReviewDecision::ApprovedExecpolicyAmendment {
                    proposed_execpolicy_amendment,
                } => Self::AcceptWithExecpolicyAmendment {
                    execpolicy_amendment: proposed_execpolicy_amendment.into(),
                },
                CoreReviewDecision::ApprovedForSession => Self::AcceptForSession,
                CoreReviewDecision::NetworkPolicyAmendment {
                    network_policy_amendment,
                } => Self::ApplyNetworkPolicyAmendment {
                    network_policy_amendment: network_policy_amendment.into(),
                },
                CoreReviewDecision::Abort => Self::Cancel,
                CoreReviewDecision::Denied => Self::Decline,
            }
        }
    }
    ```
    
    And updates `CommandExecutionRequestApprovalParams` to have a new field:
    
    ```rust
    available_decisions: Option<Vec<CommandExecutionApprovalDecision>>
    ```
    
    when, if specified, should make it easier for clients to display an
    appropriate list of options in the UI.
    
    This makes it possible for `CoreShellActionProvider::prompt()` in
    `unix_escalation.rs` to specify the `Vec<ReviewDecision>` directly,
    adding support for `ApprovedForSession` when approving a skill script,
    which was previously missing in the TUI.
    
    Note this results in a significant change to `exec_options()` in
    `approval_overlay.rs`, as the displayed options are now derived from
    `available_decisions: &[ReviewDecision]`.
    
    ## What Changed
    
    - Add `available_decisions` to
    [`ExecApprovalRequestEvent`](https://github.com/openai/codex/blob/de00e932dd9801de0a4faac0519162099753f331/codex-rs/protocol/src/approvals.rs#L111-L175),
    including helpers to derive the legacy default choices when older
    senders omit the field.
    - Map `codex_protocol::protocol::ReviewDecision` to app-server
    `CommandExecutionApprovalDecision` and expose the ordered list as
    experimental `availableDecisions` in
    [`CommandExecutionRequestApprovalParams`](https://github.com/openai/codex/blob/de00e932dd9801de0a4faac0519162099753f331/codex-rs/app-server-protocol/src/protocol/v2.rs#L3798-L3807).
    - Thread optional `available_decisions` through the core approval path
    so Unix shell escalation can explicitly request `ApprovedForSession` for
    session-scoped approvals instead of relying on client heuristics.
    [`unix_escalation.rs`](https://github.com/openai/codex/blob/de00e932dd9801de0a4faac0519162099753f331/codex-rs/core/src/tools/runtimes/shell/unix_escalation.rs#L194-L214)
    - Update the TUI approval overlay to build its buttons from the ordered
    decision list, while preserving the legacy fallback when
    `available_decisions` is missing.
    - Update the app-server README, test client output, and generated schema
    artifacts to document and surface the new field.
    
    ## Testing
    
    - Add `approval_overlay.rs` coverage for explicit decision lists,
    including the generic `ApprovedForSession` path and network approval
    options.
    - Update `chatwidget/tests.rs` and app-server protocol tests to populate
    the new optional field and keep older event shapes working.
    
    ## Developers Docs
    
    - If we document `item/commandExecution/requestApproval` on
    [developers.openai.com/codex](https://developers.openai.com/codex), add
    experimental `availableDecisions` as the preferred source of approval
    choices and note that older servers may omit it.
  • Revert "Add skill approval event/response (#12633)" (#12811)
    This reverts commit https://github.com/openai/codex/pull/12633. We no
    longer need this PR, because we favor sending normal exec command
    approval server request with `additional_permissions` of skill
    permissions instead
  • Add macOS and Linux direct install script (#12740)
    ## Summary
    - add a direct install script for macOS and Linux at
    `scripts/install/install.sh`
    - stage `install.sh` into `dist/` during release so it is published as a
    GitHub release asset
    - reuse the existing platform npm payload so the installer includes both
    `codex` and `rg`
    
    ## Testing
    - `bash -n scripts/install/install.sh`
    - local macOS `curl | sh` smoke test against a locally served copy of
    the script
  • Remove steer feature flag (#12026)
    All code should go in the direction that steer is enabled
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • feat: scope execve session approvals by approved skill metadata (#12814)
    Previous to this change, `determine_action()` would
    
    1. check if `program` is associated with a skill
    2. if so, check if `program` is in `execve_session_approvals` to see
    whether the user needs to be prompted
    
    This PR flips the order of these checks to try to set us up so that
    "session approvals" are always consulted first (which should soon extend
    to include session approvals derived from `prefix_rule()`s, as well).
    
    Though to make the new ordering work, we need to record any relevant
    metadata to associate with the approval, which in the case of a
    skill-based approval is the `SkillMetadata` so that we can derive the
    `PermissionProfile` to include with the escalation. (Though as noted by
    the `TODO`, this `PermissionProfile` is not honored yet.)
    
    The new `ExecveSessionApproval` struct is used to retain the necessary
    metadata.
    
    ## What Changed
    
    - Replace the `execve_session_approvals` `HashSet` with a map that
    stores an `ExecveSessionApproval` alongside each approved `program`.
    - When a user chooses `ApprovedForSession` for a skill script, capture
    the matched `SkillMetadata` in the session approval entry.
    - Consult that cache before re-running `find_skill()`, and reuse the
    originally approved skill metadata and permission profile when allowing
    later execve callbacks in the same session.
  • Enable request_user_input in Default mode (#12735)
    ## Summary
    - allow `request_user_input` in Default collaboration mode as well as
    Plan
    - update the Default-mode instructions to prefer assumptions first and
    use `request_user_input` only when a question is unavoidable
    - update request_user_input and app-server tests to match the new
    Default-mode behavior
    - refactor collaboration-mode availability plumbing into
    `CollaborationModesConfig` for future mode-related flags
    
    ## Codex author
    `codex resume 019c9124-ed28-7c13-96c6-b916b1c97d49`
  • Revert "Ensure shell command skills trigger approval (#12697)" (#12721)
    This reverts commit daf0f03ac8.
    
    # External (non-OpenAI) Pull Request Requirements
    
    Before opening this Pull Request, please read the dedicated
    "Contributing" markdown file or your PR may be closed:
    https://github.com/openai/codex/blob/main/docs/contributing.md
    
    If your PR conforms to our contribution guidelines, replace this text
    with a detailed and high quality description of your changes.
    
    Include a link to a bug report or enhancement request.
  • only use preambles for realtime (#12806)
    # External (non-OpenAI) Pull Request Requirements
    
    Before opening this Pull Request, please read the dedicated
    "Contributing" markdown file or your PR may be closed:
    https://github.com/openai/codex/blob/main/docs/contributing.md
    
    If your PR conforms to our contribution guidelines, replace this text
    with a detailed and high quality description of your changes.
    
    Include a link to a bug report or enhancement request.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • feat(app-server): thread/unsubscribe API (#10954)
    Adds a new v2 app-server API for a client to be able to unsubscribe to a
    thread:
    - New RPC method: `thread/unsubscribe`
    - New server notification: `thread/closed`
    
    Today clients can start/resume/archive threads, but there wasn’t a way
    to explicitly unload a live thread from memory without archiving it.
    With `thread/unsubscribe`, a client can indicate it is no longer
    actively working with a live Thread. If this is the only client
    subscribed to that given thread, the thread will be automatically closed
    by app-server, at which point the server will send `thread/closed` and
    `thread/status/changed` with `status: notLoaded` notifications.
    
    This gives clients a way to prevent long-running app-server processes
    from accumulating too many thread (and related) objects in memory.
    
    Closed threads will also be removed from `thread/loaded/list`.
  • make 5.3-codex visible in cli for api users (#12808)
    5.3-codex released in api, mark it visible for API users via bundled
    `models.json`.
  • fix: harden zsh fork tests and keep subcommand approvals deterministic (#12809)
    ## Why
    The prior
    `turn_start_shell_zsh_fork_subcommand_decline_marks_parent_declined_v2`
    assertion was brittle under Bazel: command approval payloads in the test
    could include environment-dependent wrapper/command formatting
    differences, which makes exact command-string matching flaky even when
    behavior is correct.
    
    (This regression was knowingly introduced in
    https://github.com/openai/codex/pull/12800, but it was urgent to land
    that PR.)
    
    ## What changed
    - Hardened
    `turn_start_shell_zsh_fork_subcommand_decline_marks_parent_declined_v2`
    in
    [`turn_start_zsh_fork.rs`](https://github.com/openai/codex/blob/main/codex-rs/app-server/tests/suite/v2/turn_start_zsh_fork.rs):
    - Replaced strict `approval_command.starts_with("/bin/rm")` checks with
    intent-based subcommand matching.
    - Subcommand approvals are now recognized by file-target semantics
    (`first.txt` or `second.txt`) plus `rm` intent.
    - Parent approval recognition is now more tolerant of command-format
    differences while still requiring a definitive parent command context.
    - Uses a defensive loop that waits for all target subcommand decisions
    and the parent approval request.
    - Preserved the existing regression and unit test fixes from earlier
    commits in `unix_escalation.rs` and `skill_approval.rs`.
    
    ## Verification
    - Ran the zsh fork subcommand decline regression under this change:
    -
    `turn_start_shell_zsh_fork_subcommand_decline_marks_parent_declined_v2`
    - Confirmed the test is now robust against approval-command-string
    variation instead of hardcoding one expected command shape.
  • Update Codex docs success link (#12805)
    Fix a stale documentation link in the sign-in flow