Commit Graph

144 Commits

  • chore(core) Remove Feature::PowershellUtf8 (#15128)
    ## Summary
    This feature has been enabled for powershell for a while now, let's get
    rid of the logic
    
    ## Testing
    - [x] Unit tests
  • feat: change multi-agent to use path-like system instead of uuids (#15313)
    This PR add an URI-based system to reference agents within a tree. This
    comes from a sync between research and engineering.
    
    The main agent (the one manually spawned by a user) is always called
    `/root`. Any sub-agent spawned by it will be `/root/agent_1` for example
    where `agent_1` is chosen by the model.
    
    Any agent can contact any agents using the path.
    
    Paths can be used either in absolute or relative to the calling agents
    
    Resume is not supported for now on this new path
  • feat(tui): add /title terminal title configuration (#12334)
    ## Problem
    
    When multiple Codex sessions are open at once, terminal tabs and windows
    are hard to distinguish from each other. The existing status line only
    helps once the TUI is already focused, so it does not solve the "which
    tab is this?" problem.
    
    This PR adds a first-class `/title` command so the terminal window or
    tab title can carry a short, configurable summary of the current
    session.
    
    ## Screenshot
    
    <img width="849" height="320" alt="image"
    src="https://github.com/user-attachments/assets/8b112927-7890-45ed-bb1e-adf2f584663d"
    />
    
    ## Mental model
    
    `/statusline` and `/title` are separate status surfaces with different
    constraints. The status line is an in-app footer that can be denser and
    more detailed. The terminal title is external terminal metadata, so it
    needs short, stable segments that still make multiple sessions easy to
    tell apart.
    
    The `/title` configuration is an ordered list of compact items. By
    default it renders `spinner,project`, so active sessions show
    lightweight progress first while idle sessions still stay easy to
    disambiguate. Each configured item is omitted when its value is not
    currently available rather than forcing a placeholder.
    
    ## Non-goals
    
    This does not merge `/title` into `/statusline`, and it does not add an
    arbitrary free-form title string. The feature is intentionally limited
    to a small set of structured items so the title stays short and
    reviewable.
    
    This also does not attempt to restore whatever title the terminal or
    shell had before Codex started. When Codex clears the title, it clears
    the title Codex last wrote.
    
    ## Tradeoffs
    
    A separate `/title` command adds some conceptual overlap with
    `/statusline`, but it keeps title-specific constraints explicit instead
    of forcing the status line model to cover two different surfaces.
    
    Title refresh can happen frequently, so the implementation now shares
    parsing and git-branch orchestration between the status line and title
    paths, and caches the derived project-root name by cwd. That keeps the
    hot path cheap without introducing background polling.
    
    ## Architecture
    
    The TUI gets a new `/title` slash command and a dedicated picker UI for
    selecting and ordering terminal-title items. The chosen ids are
    persisted in `tui.terminal_title`, with `spinner` and `project` as the
    default when the config is unset. `status` remains available as a
    separate text item, so configurations like `spinner,status` render
    compact progress like `⠋ Working`.
    
    `ChatWidget` now refreshes both status surfaces through a shared
    `refresh_status_surfaces()` path. That shared path parses configured
    items once, warns on invalid ids once, synchronizes shared cached state
    such as git-branch lookup, then renders the footer status line and
    terminal title from the same snapshot.
    
    Low-level OSC title writes live in `codex-rs/tui/src/terminal_title.rs`,
    which owns the terminal write path and last-mile sanitization before
    emitting OSC 0.
    
    ## Security
    
    Terminal-title text is treated as untrusted display content before Codex
    emits it. The write path strips control characters, removes invisible
    and bidi formatting characters that can make the title visually
    misleading, normalizes whitespace, and caps the emitted length.
    
    References used while implementing this:
    
    - [xterm control
    sequences](https://invisible-island.net/xterm/ctlseqs/ctlseqs.html)
    - [WezTerm escape sequences](https://wezterm.org/escape-sequences.html)
    - [CWE-150: Improper Neutralization of Escape, Meta, or Control
    Sequences](https://cwe.mitre.org/data/definitions/150.html)
    - [CERT VU#999008 (Trojan Source)](https://kb.cert.org/vuls/id/999008)
    - [Trojan Source disclosure site](https://trojansource.codes/)
    - [Unicode Bidirectional Algorithm (UAX
    #9)](https://www.unicode.org/reports/tr9/)
    - [Unicode Security Considerations (UTR
    #36)](https://www.unicode.org/reports/tr36/)
    
    ## Observability
    
    Unknown configured title item ids are warned about once instead of
    repeatedly spamming the transcript. Live preview applies immediately
    while the `/title` picker is open, and cancel rolls the in-memory title
    selection back to the pre-picker value.
    
    If terminal title writes fail, the TUI emits debug logs around set and
    clear attempts. The rendered status label intentionally collapses richer
    internal states into compact title text such as `Starting...`, `Ready`,
    `Thinking...`, `Working...`, `Waiting...`, and `Undoing...` when
    `status` is configured.
    
    ## Tests
    
    Ran:
    
    - `just fmt`
    - `cargo test -p codex-tui`
    
    At the moment, the red Windows `rust-ci` failures are due to existing
    `codex-core` `apply_patch_cli` stack-overflow tests that also reproduce
    on `main`. The `/title`-specific `codex-tui` suite is green.
  • Add experimental exec server URL handling (#15196)
    Add a config and attempt to start the server.
  • [plugins] Support configuration tool suggest allowlist. (#15022)
    - [x] Support configuration tool suggest allowlist.
    
    Supports both plugins and connectors.
  • Gate realtime audio interruption logic to v2 (#14984)
    - thread the realtime version into conversation start and app-server
    notifications
    - keep playback-aware mic gating and playback interruption behavior on
    v2 only, leaving v1 on the legacy path
  • fix(core): prevent hanging turn/start due to websocket warming issues (#14838)
    ## Description
    
    This PR fixes a bad first-turn failure mode in app-server when the
    startup websocket prewarm hangs. Before this change, `initialize ->
    thread/start -> turn/start` could sit behind the prewarm for up to five
    minutes, so the client would not see `turn/started`, and even
    `turn/interrupt` would block because the turn had not actually started
    yet.
    
    Now, we:
    - set a (configurable) timeout of 15s for websocket startup time,
    exposed as `websocket_startup_timeout_ms` in config.toml
    - `turn/started` is sent immediately on `turn/start` even if the
    websocket is still connecting
    - `turn/interrupt` can be used to cancel a turn that is still waiting on
    the websocket warmup
    - the turn task will wait for the full 15s websocket warming timeout
    before falling back
    
    ## Why
    
    The old behavior made app-server feel stuck at exactly the moment the
    client expects turn lifecycle events to start flowing. That was
    especially painful for external clients, because from their point of
    view the server had accepted the request but then went silent for
    minutes.
    
    ## Configuring the websocket startup timeout
    Can set it in config.toml like this:
    ```
    [model_providers.openai]
    supports_websockets = true
    websocket_connect_timeout_ms = 15000
    ```
  • Move TUI on top of app server (parallel code) (#14717)
    This PR replicates the `tui` code directory and creates a temporary
    parallel `tui_app_server` directory. It also implements a new feature
    flag `tui_app_server` to select between the two tui implementations.
    
    Once the new app-server-based TUI is stabilized, we'll delete the old
    `tui` directory and feature flag.
  • Reuse guardian session across approvals (#14668)
    ## Summary
    - reuse a guardian subagent session across approvals so reviews keep a
    stable prompt cache key and avoid one-shot startup overhead
    - clear the guardian child history before each review so prior guardian
    decisions do not leak into later approvals
    - include the `smart_approvals` -> `guardian_approval` feature flag
    rename in the same PR to minimize release latency on a very tight
    timeline
    - add regression coverage for prompt-cache-key reuse without
    prior-review prompt bleed
    
    ## Request
    - Bug/enhancement request: internal guardian prompt-cache and latency
    improvement request
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • [apps] Add tool call meta. (#14647)
    - [x] Add resource_uri and other things to _meta to shortcut resource
    lookup and speed things up.
  • Enforce errors on overriding built-in model providers (#12024)
    We receive bug reports from users who attempt to override one of the
    three built-in model providers (openai, ollama, or lmstuio). Currently,
    these overrides are silently ignored. This PR makes it an error to
    override them.
    
    ## Summary
    - add validation for `model_providers` so `openai`, `ollama`, and
    `lmstudio` keys now produce clear configuration errors instead of being
    silently ignored
  • Add openai_base_url config override for built-in provider (#12031)
    We regularly get bug reports from users who mistakenly have the
    `OPENAI_BASE_URL` environment variable set. This PR deprecates this
    environment variable in favor of a top-level config key
    `openai_base_url` that is used for the same purpose. By making it a
    config key, it will be more visible to users. It will also participate
    in all of the infrastructure we've added for layered and managed
    configs.
    
    Summary
    - introduce the `openai_base_url` top-level config key, update
    schema/tests, and route the built-in openai provider through it while
    - fall back to deprecated `OPENAI_BASE_URL` env var but warn user of
    deprecation when no `openai_base_url` config key is present
    - update CLI, SDK, and TUI code to prefer the new config path (with a
    deprecated env-var fallback) and document the SDK behavior change
  • Add Smart Approvals guardian review across core, app-server, and TUI (#13860)
    ## Summary
    - add `approvals_reviewer = "user" | "guardian_subagent"` as the runtime
    control for who reviews approval requests
    - route Smart Approvals guardian review through core for command
    execution, file changes, managed-network approvals, MCP approvals, and
    delegated/subagent approval flows
    - expose guardian review in app-server with temporary unstable
    `item/autoApprovalReview/{started,completed}` notifications carrying
    `targetItemId`, `review`, and `action`
    - update the TUI so Smart Approvals can be enabled from `/experimental`,
    aligned with the matching `/approvals` mode, and surfaced clearly while
    reviews are pending or resolved
    
    ## Runtime model
    This PR does not introduce a new `approval_policy`.
    
    Instead:
    - `approval_policy` still controls when approval is needed
    - `approvals_reviewer` controls who reviewable approval requests are
    routed to:
      - `user`
      - `guardian_subagent`
    
    `guardian_subagent` is a carefully prompted reviewer subagent that
    gathers relevant context and applies a risk-based decision framework
    before approving or denying the request.
    
    The `smart_approvals` feature flag is a rollout/UI gate. Core runtime
    behavior keys off `approvals_reviewer`.
    
    When Smart Approvals is enabled from the TUI, it also switches the
    current `/approvals` settings to the matching Smart Approvals mode so
    users immediately see guardian review in the active thread:
    - `approval_policy = on-request`
    - `approvals_reviewer = guardian_subagent`
    - `sandbox_mode = workspace-write`
    
    Users can still change `/approvals` afterward.
    
    Config-load behavior stays intentionally narrow:
    - plain `smart_approvals = true` in `config.toml` remains just the
    rollout/UI gate and does not auto-set `approvals_reviewer`
    - the deprecated `guardian_approval = true` alias migration does
    backfill `approvals_reviewer = "guardian_subagent"` in the same scope
    when that reviewer is not already configured there, so old configs
    preserve their original guardian-enabled behavior
    
    ARC remains a separate safety check. For MCP tool approvals, ARC
    escalations now flow into the configured reviewer instead of always
    bypassing guardian and forcing manual review.
    
    ## Config stability
    The runtime reviewer override is stable, but the config-backed
    app-server protocol shape is still settling.
    
    - `thread/start`, `thread/resume`, and `turn/start` keep stable
    `approvalsReviewer` overrides
    - the config-backed `approvals_reviewer` exposure returned via
    `config/read` (including profile-level config) is now marked
    `[UNSTABLE]` / experimental in the app-server protocol until we are more
    confident in that config surface
    
    ## App-server surface
    This PR intentionally keeps the guardian app-server shape narrow and
    temporary.
    
    It adds generic unstable lifecycle notifications:
    - `item/autoApprovalReview/started`
    - `item/autoApprovalReview/completed`
    
    with payloads of the form:
    - `{ threadId, turnId, targetItemId, review, action? }`
    
    `review` is currently:
    - `{ status, riskScore?, riskLevel?, rationale? }`
    - where `status` is one of `inProgress`, `approved`, `denied`, or
    `aborted`
    
    `action` carries the guardian action summary payload from core when
    available. This lets clients render temporary standalone pending-review
    UI, including parallel reviews, even when the underlying tool item has
    not been emitted yet.
    
    These notifications are explicitly documented as `[UNSTABLE]` and
    expected to change soon.
    
    This PR does **not** persist guardian review state onto `thread/read`
    tool items. The intended follow-up is to attach guardian review state to
    the reviewed tool item lifecycle instead, which would improve
    consistency with manual approvals and allow thread history / reconnect
    flows to replay guardian review state directly.
    
    ## TUI behavior
    - `/experimental` exposes the rollout gate as `Smart Approvals`
    - enabling it in the TUI enables the feature and switches the current
    session to the matching Smart Approvals `/approvals` mode
    - disabling it in the TUI clears the persisted `approvals_reviewer`
    override when appropriate and returns the session to default manual
    review when the effective reviewer changes
    - `/approvals` still exposes the reviewer choice directly
    - the TUI renders:
    - pending guardian review state in the live status footer, including
    parallel review aggregation
      - resolved approval/denial state in history
    
    ## Scope notes
    This PR includes the supporting core/runtime work needed to make Smart
    Approvals usable end-to-end:
    - shell / unified-exec / apply_patch / managed-network / MCP guardian
    review
    - delegated/subagent approval routing into guardian review
    - guardian review risk metadata and action summaries for app-server/TUI
    - config/profile/TUI handling for `smart_approvals`, `guardian_approval`
    alias migration, and `approvals_reviewer`
    - a small internal cleanup of delegated approval forwarding to dedupe
    fallback paths and simplify guardian-vs-parent approval waiting (no
    intended behavior change)
    
    Out of scope for this PR:
    - redesigning the existing manual approval protocol shapes
    - persisting guardian review state onto app-server `ThreadItem`s
    - delegated MCP elicitation auto-review (the current delegated MCP
    guardian shim only covers the legacy `RequestUserInput` path)
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Add code_mode_only feature (#14617)
    Summary
    - add the code_mode_only feature flag/config schema and wire its
    dependency on code_mode
    - update code mode tool descriptions to list nested tools with detailed
    headers
    - restrict available tools for prompt and exec descriptions when
    code_mode_only is enabled and test the behavior
    
    Testing
    - Not run (not requested)
  • Unify realtime v1/v2 session config (#14606)
    ## Summary
    - unify realtime websocket settings under `[realtime]` (`version` and
    `type`)
    - remove `realtime_conversation_v2` and select parser/session mode from
    config
    
    ## Testing
    - not run (per request)
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Use a private desktop for Windows sandbox instead of Winsta0\Default (#14400)
    ## Summary
    - launch Windows sandboxed children on a private desktop instead of
    `Winsta0\Default`
    - make private desktop the default while keeping
    `windows.sandbox_private_desktop=false` as the escape hatch
    - centralize process launch through the shared
    `create_process_as_user(...)` path
    - scope the private desktop ACL to the launching logon SID
    
    ## Why
    Today sandboxed Windows commands run on the visible shared desktop. That
    leaves an avoidable same-desktop attack surface for window interaction,
    spoofing, and related UI/input issues. This change moves sandboxed
    commands onto a dedicated per-launch desktop by default so the sandbox
    no longer shares `Winsta0\Default` with the user session.
    
    The implementation stays conservative on security with no silent
    fallback back to `Winsta0\Default`
    
    If private-desktop setup fails on a machine, users can still opt out
    explicitly with `windows.sandbox_private_desktop=false`.
    
    ## Validation
    - `cargo build -p codex-cli`
    - elevated-path `codex exec` desktop-name probe returned
    `CodexSandboxDesktop-*`
    - elevated-path `codex exec` smoke sweep for shell commands, nested
    `pwsh`, jobs, and hidden `notepad` launch
    - unelevated-path full private-desktop compatibility sweep via `codex
    exec` with `-c windows.sandbox=unelevated`
  • Add realtime transcription mode for websocket sessions (#14556)
    - add experimental_realtime_ws_mode (conversational/transcription) and
    plumb it into realtime conversation session config
    - switch realtime websocket intent and session.update payload shape
    based on mode
    - update config schema and realtime/config tests
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Add realtime v2 event parser behind feature flag (#14537)
    - Add a feature-flagged realtime v2 parser on the existing
    websocket/session pipeline.
    - Wire parser selection from core feature flags and map the codex
    handoff tool-call path into existing handoff events.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • rename spawn_csv feature flag to enable_fanout (#14475)
    ## Summary
    - rename the public feature flag for `spawn_agents_on_csv()` from
    `spawn_csv` to `enable_fanout`
    - regenerate the config schema so only `enable_fanout` is advertised
    - keep the behavior the same: enabling `enable_fanout` still pulls in
    `multi_agent`
    
    ## Notes
    - this is a hard rename with no `spawn_csv` compatibility alias
    - the internal enum remains `Feature::SpawnCsv` to keep the patch small
    
    ## Testing
    - `cd codex-rs && just fmt`
    - `cd codex-rs && cargo test -p codex-core` (running locally;
    `suite::agent_jobs::*` and rename-specific coverage passed so far)
  • fix(cli): support legacy use_linux_sandbox_bwrap flag (#14473)
    ## Summary
    - restore `use_linux_sandbox_bwrap` as a removed feature key so older
    `--enable` callers parse again
    - keep it as a no-op by leaving runtime behavior unchanged
    - add regression coverage for the legacy `--enable` path
    
    ## Testing
    - Not run (updated and pushed quickly)
  • refactor: make bubblewrap the default Linux sandbox (#13996)
    ## Summary
    - make bubblewrap the default Linux sandbox and keep
    `use_legacy_landlock` as the only override
    - remove `use_linux_sandbox_bwrap` from feature, config, schema, and
    docs surfaces
    - update Linux sandbox selection, CLI/config plumbing, and related
    tests/docs to match the new default
    - fold in the follow-up CI fixes for request-permissions responses and
    Linux read-only sandbox error text
  • [apps] Add tool_suggest tool. (#14287)
    - [x] Add tool_suggest tool.
    - [x] Move chatgpt/src/connectors.rs and core/src/connectors.rs into a
    dedicated mod so that we have all the logic and global cache in one
    place.
    - [x] Update TUI app link view to support rendering the installation
    view for mcp elicitation.
    
    ---------
    
    Co-authored-by: Shaqayeq <shaqayeq@openai.com>
    Co-authored-by: Eric Traut <etraut@openai.com>
    Co-authored-by: pakrym-oai <pakrym@openai.com>
    Co-authored-by: Ahmed Ibrahim <aibrahim@openai.com>
    Co-authored-by: guinness-oai <guinness@openai.com>
    Co-authored-by: Eugene Brevdo <ebrevdo@users.noreply.github.com>
    Co-authored-by: Charlie Guo <cguo@openai.com>
    Co-authored-by: Fouad Matin <fouad@openai.com>
    Co-authored-by: Fouad Matin <169186268+fouad-openai@users.noreply.github.com>
    Co-authored-by: xl-openai <xl@openai.com>
    Co-authored-by: alexsong-oai <alexsong@openai.com>
    Co-authored-by: Owen Lin <owenlin0@gmail.com>
    Co-authored-by: sdcoffey <stevendcoffey@gmail.com>
    Co-authored-by: Codex <noreply@openai.com>
    Co-authored-by: Won Park <won@openai.com>
    Co-authored-by: Dylan Hurd <dylan.hurd@openai.com>
    Co-authored-by: celia-oai <celia@openai.com>
    Co-authored-by: gabec-openai <gabec@openai.com>
    Co-authored-by: joeytrasatti-openai <joey.trasatti@openai.com>
    Co-authored-by: Leo Shimonaka <leoshimo@openai.com>
    Co-authored-by: Rasmus Rygaard <rasmus@openai.com>
    Co-authored-by: maja-openai <163171781+maja-openai@users.noreply.github.com>
    Co-authored-by: pash-openai <pash@openai.com>
    Co-authored-by: Josh McKinney <joshka@openai.com>
  • refactor: centralize filesystem permissions precedence (#14174)
    ## Stack
    
       fix: fail closed for unsupported split windows sandboxing #14172
       fix: preserve split filesystem semantics in linux sandbox #14173
       fix: align core approvals with split sandbox policies #14171
    -> refactor: centralize filesystem permissions precedence #14174
    
    ## Summary
    - add a shared per-path split filesystem precedence helper in
    `FileSystemSandboxPolicy`
    - derive readable, writable, and unreadable roots from the same
    most-specific resolution rules
    - add regression coverage for nested `write` / `read` / `none` carveouts
    and legacy bridge enforcement detection
    
    ## Testing
    - cargo test -p codex-protocol
    - cargo clippy -p codex-protocol --tests -- -D warnings
  • Split spawn_csv from multi_agent (#14282)
    - make `spawn_csv` a standalone feature for CSV agent jobs
    - keep `spawn_csv -> multi_agent` one-way and preserve restricted
    subagent disable paths
  • Add realtime start instructions config override (#14270)
    - add `realtime_start_instructions` config support
    - thread it into realtime context updates, schema, docs, and tests
  • chore: add a separate reject-policy flag for skill approvals (#14271)
    ## Summary
    - add `skill_approval` to `RejectConfig` and the app-server v2
    `AskForApproval::Reject` payload so skill-script prompts can be
    configured independently from sandbox and rule-based prompts
    - update Unix shell escalation to reject prompts based on the actual
    decision source, keeping prefix rules tied to `rules`, unmatched command
    fallbacks tied to `sandbox_approval`, and skill scripts tied to
    `skill_approval`
    - regenerate the affected protocol/config schemas and expand
    unit/integration coverage for the new flag and skill approval behavior
  • feat: support disabling bundled system skills (#13792)
    Support disable bundled system skills with a config:
    
    [skills.bundled]
    enabled = false
  • fix(core) default RejectConfig.request_permissions (#14165)
    ## Summary
    Adds a default here so existing config deserializes
    
    ## Testing
    - [x] Added a unit test
  • start of hooks engine (#13276)
    (Experimental)
    
    This PR adds a first MVP for hooks, with SessionStart and Stop
    
    The core design is:
    
    - hooks live in a dedicated engine under codex-rs/hooks
    - each hook type has its own event-specific file
    - hook execution is synchronous and blocks normal turn progression while
    running
    - matching hooks run in parallel, then their results are aggregated into
    a normalized HookRunSummary
    
    On the AppServer side, hooks are exposed as operational metadata rather
    than transcript-native items:
    
    - new live notifications: hook/started, hook/completed
    - persisted/replayed hook results live on Turn.hookRuns
    - we intentionally did not add hook-specific ThreadItem variants
    
    Hooks messages are not persisted, they remain ephemeral. The context
    changes they add are (they get appended to the user's prompt)
  • Add code_mode experimental feature (#13418)
    A much narrower and more isolated (no node features) version of js_repl
  • feat(approvals) RejectConfig for request_permissions (#14118)
    ## Summary
    We need to support allowing request_permissions calls when using
    `Reject` policy
    
    <img width="1133" height="588" alt="Screenshot 2026-03-09 at 12 06
    40 PM"
    src="https://github.com/user-attachments/assets/a8df987f-c225-4866-b8ab-5590960daec5"
    />
    
    Note that this is a backwards-incompatible change for Reject policy. I'm
    not sure if we need to add a default based on our current use/setup
    
    ## Testing
    - [x] Added tests
    - [x] Tested locally
  • Add request permissions tool (#13092)
    Adds a built-in `request_permissions` tool and wires it through the
    Codex core, protocol, and app-server layers so a running turn can ask
    the client for additional permissions instead of relying on a static
    session policy.
    
    The new flow emits a `RequestPermissions` event from core, tracks the
    pending request by call ID, forwards it through app-server v2 as an
    `item/permissions/requestApproval` request, and resumes the tool call
    once the client returns an approved subset of the requested permission
    profile.
  • Add guardian approval MVP (#13692)
    ## Summary
    - add the guardian reviewer flow for `on-request` approvals in command,
    patch, sandbox-retry, and managed-network approval paths
    - keep guardian behind `features.guardian_approval` instead of exposing
    a public `approval_policy = guardian` mode
    - route ordinary `OnRequest` approvals to the guardian subagent when the
    feature is enabled, without changing the public approval-mode surface
    
    ## Public model
    - public approval modes stay unchanged
    - guardian is enabled via `features.guardian_approval`
    - when that feature is on, `approval_policy = on-request` keeps the same
    approval boundaries but sends those approval requests to the guardian
    reviewer instead of the user
    - `/experimental` only persists the feature flag; it does not rewrite
    `approval_policy`
    - CLI and app-server no longer expose a separate `guardian` approval
    mode in this PR
    
    ## Guardian reviewer
    - the reviewer runs as a normal subagent and reuses the existing
    subagent/thread machinery
    - it is locked to a read-only sandbox and `approval_policy = never`
    - it does not inherit user/project exec-policy rules
    - it prefers `gpt-5.4` when the current provider exposes it, otherwise
    falls back to the parent turn's active model
    - it fail-closes on timeout, startup failure, malformed output, or any
    other review error
    - it currently auto-approves only when `risk_score < 80`
    
    ## Review context and policy
    - guardian mirrors `OnRequest` approval semantics rather than
    introducing a separate approval policy
    - explicit `require_escalated` requests follow the same approval surface
    as `OnRequest`; the difference is only who reviews them
    - managed-network allowlist misses that enter the approval flow are also
    reviewed by guardian
    - the review prompt includes bounded recent transcript history plus
    recent tool call/result evidence
    - transcript entries and planned-action strings are truncated with
    explicit `<guardian_truncated ... />` markers so large payloads stay
    bounded
    - apply-patch reviews include the full patch content (without
    duplicating the structured `changes` payload)
    - the guardian request layout is snapshot-tested using the same
    model-visible Responses request formatter used elsewhere in core
    
    ## Guardian network behavior
    - the guardian subagent inherits the parent session's managed-network
    allowlist when one exists, so it can use the same approved network
    surface while reviewing
    - exact session-scoped network approvals are copied into the guardian
    session with protocol/port scope preserved
    - those copied approvals are now seeded before the guardian's first turn
    is submitted, so inherited approvals are available during any immediate
    review-time checks
    
    ## Out of scope / follow-ups
    - the sandbox-permission validation split was pulled into a separate PR
    and is not part of this diff
    - a future follow-up can enable `serde_json` preserve-order in
    `codex-core` and then simplify the guardian action rendering further
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Allow full web search tool config (#13675)
    Previously, we could only configure whether web search was on/off.
    
    This PR enables sending along a web search config, which includes all
    the stuff responsesapi supports: filters, location, etc.
  • Add realtime startup context override (#13796)
    - add experimental_realtime_ws_startup_context to override or disable
    realtime websocket startup context
    - preserve generated startup context when unset and cover the new
    override paths in tests
  • config: add initial support for the new permission profile config language in config.toml (#13434)
    ## Why
    
    `SandboxPolicy` currently mixes together three separate concerns:
    
    - parsing layered config from `config.toml`
    - representing filesystem sandbox state
    - carrying basic network policy alongside filesystem choices
    
    That makes the existing config awkward to extend and blocks the new TOML
    proposal where `[permissions]` becomes a table of named permission
    profiles selected by `default_permissions`. (The idea is that if
    `default_permissions` is not specified, we assume the user is opting
    into the "traditional" way to configure the sandbox.)
    
    This PR adds the config-side plumbing for those profiles while still
    projecting back to the legacy `SandboxPolicy` shape that the current
    macOS and Linux sandbox backends consume.
    
    It also tightens the filesystem profile model so scoped entries only
    exist for `:project_roots`, and so nested keys must stay within a
    project root instead of using `.` or `..` traversal.
    
    This drops support for the short-lived `[permissions.network]` in
    `config.toml` because now that would be interpreted as a profile named
    `network` within `[permissions]`.
    
    ## What Changed
    
    - added `PermissionsToml`, `PermissionProfileToml`,
    `FilesystemPermissionsToml`, and `FilesystemPermissionToml` so config
    can parse named profiles under `[permissions.<profile>.filesystem]`
    - added top-level `default_permissions` selection, validation for
    missing or unknown profiles, and compilation from a named profile into
    split `FileSystemSandboxPolicy` and `NetworkSandboxPolicy` values
    - taught config loading to choose between the legacy `sandbox_mode` path
    and the profile-based path without breaking legacy users
    - introduced `codex-protocol::permissions` for the split filesystem and
    network sandbox types, and stored those alongside the legacy projected
    `sandbox_policy` in runtime `Permissions`
    - modeled `FileSystemSpecialPath` so only `ProjectRoots` can carry a
    nested `subpath`, matching the intended config syntax instead of
    allowing invalid states for other special paths
    - restricted scoped filesystem maps to `:project_roots`, with validation
    that nested entries are non-empty descendant paths and cannot use `.` or
    `..` to escape the project root
    - kept existing runtime consumers working by projecting
    `FileSystemSandboxPolicy` back into `SandboxPolicy`, with an explicit
    error for profiles that request writes outside the workspace root
    - loaded proxy settings from top-level `[network]`
    - regenerated `core/config.schema.json`
    
    ## Verification
    
    - added config coverage for profile deserialization,
    `default_permissions` selection, top-level `[network]` loading, network
    enablement, rejection of writes outside the workspace root, rejection of
    nested entries for non-`:project_roots` special paths, and rejection of
    parent-directory traversal in `:project_roots` maps
    - added protocol coverage for the legacy bridge rejecting non-workspace
    writes
    
    ## Docs
    
    - update the Codex config docs on developers.openai.com/codex to
    document named `[permissions.<profile>]` entries, `default_permissions`,
    scoped `:project_roots` syntax, the descendant-path restriction for
    nested `:project_roots` entries, and top-level `[network]` proxy
    configuration
    
    
    
    
    
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/13434).
    * #13453
    * #13452
    * #13451
    * #13449
    * #13448
    * #13445
    * #13440
    * #13439
    * __->__ #13434
  • [elicitations] Switch to use MCP style elicitation payload for mcp tool approvals. (#13621)
    - [x] Switch to use MCP style elicitation payload for mcp tool
    approvals.
    - [ ] TODO: Update the UI to support the full spec.
  • refactor: remove proxy admin endpoint (#13687)
    ## Summary
    - delete the network proxy admin server and its runtime listener/task
    plumbing
    - remove the admin endpoint config, runtime, requirement, protocol,
    schema, and debug-surface fields
    - update proxy docs to reflect the remaining HTTP and SOCKS listeners
    only
  • image-gen-core (#13290)
    Core tool-calling for image-gen, handles requesting and receiving logic
    for images using response API
  • Add role-specific subagent nickname overrides (#13218)
    ## Summary
    - add `nickname_candidates` to agent role config
    - use role-specific nickname pools for spawned and resumed subagents
    - validate and schema-generate the new config surface
    
    ## Testing
    - `just fmt`
    - `just write-config-schema`
    - `just fix -p codex-core`
    - `cargo test -p codex-core`
    - `cargo test`
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Add under-development original-resolution view_image support (#13050)
    ## Summary
    
    Add original-resolution support for `view_image` behind the
    under-development `view_image_original_resolution` feature flag.
    
    When the flag is enabled and the target model is `gpt-5.3-codex` or
    newer, `view_image` now preserves original PNG/JPEG/WebP bytes and sends
    `detail: "original"` to the Responses API instead of using the legacy
    resize/compress path.
    
    ## What changed
    
    - Added `view_image_original_resolution` as an under-development feature
    flag.
    - Added `ImageDetail` to the protocol models and support for serializing
    `detail: "original"` on tool-returned images.
    - Added `PromptImageMode::Original` to `codex-utils-image`.
      - Preserves original PNG/JPEG/WebP bytes.
      - Keeps legacy behavior for the resize path.
    - Updated `view_image` to:
    - use the shared `local_image_content_items_with_label_number(...)`
    helper in both code paths
      - select original-resolution mode only when:
        - the feature flag is enabled, and
        - the model slug parses as `gpt-5.3-codex` or newer
    - Kept local user image attachments on the existing resize path; this
    change is specific to `view_image`.
    - Updated history/image accounting so only `detail: "original"` images
    use the docs-based GPT-5 image cost calculation; legacy images still use
    the old fixed estimate.
    - Added JS REPL guidance, gated on the same feature flag, to prefer JPEG
    at 85% quality unless lossless is required, while still allowing other
    formats when explicitly requested.
    - Updated tests and helper code that construct
    `FunctionCallOutputContentItem::InputImage` to carry the new `detail`
    field.
    
    ## Behavior
    
    ### Feature off
    - `view_image` keeps the existing resize/re-encode behavior.
    - History estimation keeps the existing fixed-cost heuristic.
    
    ### Feature on + `gpt-5.3-codex+`
    - `view_image` sends original-resolution images with `detail:
    "original"`.
    - PNG/JPEG/WebP source bytes are preserved when possible.
    - History estimation uses the GPT-5 docs-based image-cost calculation
    for those `detail: "original"` images.
    
    
    #### [git stack](https://github.com/magus/git-stack-cli)
    - 👉 `1` https://github.com/openai/codex/pull/13050
    -  `2` https://github.com/openai/codex/pull/13331
    -  `3` https://github.com/openai/codex/pull/13049
  • Refactor plugin config and cache path (#13333)
    Update config.toml plugin entries to use
    <plugin_name>@<marketplace_name> as the key.
    Plugin now stays in
    [plugins/cache/marketplace-name/plugin-name/$version/]
    Clean up the plugin code structure.
    Add plugin install functionality (not used yet).
  • feat: presentation artifact p1 (#13341)
    Part 1 of presentation tool artifact
  • app-server service tier plumbing (plus some cleanup) (#13334)
    followup to https://github.com/openai/codex/pull/13212 to expose fast
    tier controls to app server
    (majority of this PR is generated schema jsons - actual code is +69 /
    -35 and +24 tests )
    
    - add service tier fields to the app-server protocol surfaces used by
    thread lifecycle, turn start, config, and session configured events
    - thread service tier through the app-server message processor and core
    thread config snapshots
    - allow runtime config overrides to carry service tier for app-server
    callers
    
    cleanup:
    - Removing useless "legacy" code supporting "standard" - we moved to
    None | "fast", so "standard" is not needed.
  • add fast mode toggle (#13212)
    - add a local Fast mode setting in codex-core (similar to how model id
    is currently stored on disk locally)
    - send `service_tier=priority` on requests when Fast is enabled
    - add `/fast` in the TUI and persist it locally
    - feature flag
  • Update realtime websocket API (#13265)
    - migrate the realtime websocket transport to the new session and
    handoff flow
    - make the realtime model configurable in config.toml and use API-key
    auth for the websocket
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>