Commit Graph

437 Commits

  • feat: support disable skills by name. (#15378)
    Support disabling skills by name, primarily for plugin skills. We can’t
    use the path, since plugin skill paths may change across versions.
  • tui: queue follow-ups during manual /compact (#15259)
    ## Summary
    - queue input after the user submits `/compact` until that manual
    compact turn ends
    - mirror the same behavior in the app-server TUI
    - add regressions for input queued before compact starts and while it is
    running
    
    Co-authored-by: Codex <noreply@openai.com>
  • fix: fall back to vendored bubblewrap when system bwrap lacks --argv0 (#15338)
    ## Why
    
    Fixes [#15283](https://github.com/openai/codex/issues/15283), where
    sandboxed tool calls fail on older distro `bubblewrap` builds because
    `/usr/bin/bwrap` does not understand `--argv0`. The upstream [bubblewrap
    v0.9.0 release
    notes](https://github.com/containers/bubblewrap/releases/tag/v0.9.0)
    explicitly call out `Add --argv0`. Flipping `use_legacy_landlock`
    globally works around that compatibility bug, but it also weakens the
    default Linux sandbox and breaks proxy-routed and split-policy cases
    called out in review.
    
    The follow-up Linux CI failure was in the new launcher test rather than
    the launcher logic: the fake `bwrap` helper stayed open for writing, so
    Linux would not exec it. This update also closes the user-visibility gap
    from review by surfacing the same startup warning when `/usr/bin/bwrap`
    is present but too old for `--argv0`, not only when it is missing.
    
    ## What Changed
    
    - keep `use_legacy_landlock` default-disabled
    - teach `codex-rs/linux-sandbox/src/launcher.rs` to fall back to the
    vendored bubblewrap build when `/usr/bin/bwrap` does not advertise
    `--argv0` support
    - add launcher tests for supported, unsupported, and missing system
    `bwrap`
    - write the fake `bwrap` test helper to a closed temp path so the
    supported-path launcher test works on Linux too
    - extend the startup warning path so Codex warns when `/usr/bin/bwrap`
    is missing or too old to support `--argv0`
    - mirror the warning/fallback wording across
    `codex-rs/linux-sandbox/README.md` and `codex-rs/core/README.md`,
    including that the fallback is the vendored bubblewrap compiled into the
    binary
    - cite the upstream `bubblewrap` release that introduced `--argv0`
    
    ## Verification
    
    - `bazel test --config=remote --platforms=//:rbe
    //codex-rs/linux-sandbox:linux-sandbox-unit-tests
    --test_filter=launcher::tests::prefers_system_bwrap_when_help_lists_argv0
    --test_output=errors`
    - `cargo test -p codex-core system_bwrap_warning`
    - `cargo check -p codex-exec -p codex-tui -p codex-tui-app-server -p
    codex-app-server`
    - `just argument-comment-lint`
  • Add realtime transcript notification in v2 (#15344)
    - emit a typed `thread/realtime/transcriptUpdated` notification from
    live realtime transcript deltas
    - expose that notification as flat `threadId`, `role`, and `text` fields
    instead of a nested transcript array
    - continue forwarding raw `handoff_request` items on
    `thread/realtime/itemAdded`, including the accumulated
    `active_transcript`
    - update app-server docs, tests, and generated protocol schema artifacts
    to match the delta-based payloads
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • 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
  • Add temporary app-server originator fallback for codex-tui (#15218)
    ## Summary
    - make app-server treat `clientInfo.name == "codex-tui"` as a legacy
    compatibility case
    - fall back to `DEFAULT_ORIGINATOR` instead of sending `codex-tui` as
    the originator header
    - add a TODO noting this is a temporary workaround that should be
    removed later
    
    ## Testing
    - Not run (not requested)
  • feat: Add One-Time Startup Remote Plugin Sync (#15264)
    For early users who have already enabled apps, we should enable plugins
    as part of the initial setup.
  • Split features into codex-features crate (#15253)
    - Split the feature system into a new `codex-features` crate.
    - Cut `codex-core` and workspace consumers over to the new config and
    warning APIs.
    
    Co-authored-by: Ahmed Ibrahim <219906144+aibrahim-oai@users.noreply.github.com>
    Co-authored-by: Codex <noreply@openai.com>
  • [plugins] Install MCPs when calling plugin/install (#15195)
    - [x] Auth MCPs when installing plugins.
  • Move auth code into login crate (#15150)
    - Move the auth implementation and token data into codex-login.
    - Keep codex-core re-exporting that surface from codex-login for
    existing callers.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Refactor ExecServer filesystem split between local and remote (#15232)
    For each feature we have:
    1. Trait exposed on environment
    2. **Local Implementation** of the trait
    3. Remote implementation that uses the client to proxy via network
    4. Handler implementation that handles PRC requests and calls into
    **Local Implementation**
  • feat(app-server): add mcpServer/startupStatus/updated notification (#15220)
    Exposes the legacy `codex/event/mcp_startup_update` event as an API v2
    notification.
    
    The legacy event has this shape:
    ```
    #[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)]
    pub struct McpStartupUpdateEvent {
        /// Server name being started.
        pub server: String,
        /// Current startup status.
        pub status: McpStartupStatus,
    }
    
    #[derive(Debug, Clone, Deserialize, Serialize, JsonSchema, TS)]
    #[serde(rename_all = "snake_case", tag = "state")]
    #[ts(rename_all = "snake_case", tag = "state")]
    pub enum McpStartupStatus {
        Starting,
        Ready,
        Failed { error: String },
        Cancelled,
    }
    ```
  • feat(tracing): tag app-server turn spans with turn_id (#15206)
    So we can find and filter spans by `turn.id`.
    
    We do this for the `turn/start`, `turn/steer`, and `turn/interrupt`
    APIs.
  • Add experimental exec server URL handling (#15196)
    Add a config and attempt to start the server.
  • [hooks] use a user message > developer message for prompt continuation (#14867)
    ## Summary
    
    Persist Stop-hook continuation prompts as `user` messages instead of
    hidden `developer` messages + some requested integration tests
    
    This is a followup to @pakrym 's comment in
    https://github.com/openai/codex/pull/14532 to make sure stop-block
    continuation prompts match training for turn loops
    
    - Stop continuation now writes `<hook_prompt hook_run_id="...">stop
    hook's user prompt<hook_prompt>`
    - Introduces quick-xml dependency, though we already indirectly depended
    on it anyway via syntect
    - This PR only has about 500 lines of actual logic changes, the rest is
    tests/schema
    
    ## Testing
    
    Example run (with a sessionstart hook and 3 stop hooks) - this shows
    context added by session start, then two stop hooks sending their own
    additional prompts in a new turn. The model responds with a single
    message addressing both. Then when that turn ends, the hooks detect that
    they just ran using `stop_hook_active` and decide not to infinite loop
    
    test files for this (unzip, move codex -> .codex):
    [codex.zip](https://github.com/user-attachments/files/26075806/codex.zip)
    
    ```
    › cats
    
    
    • Running SessionStart hook: lighting the observatory
    
    SessionStart hook (completed)
      warning: Hi, I'm a session start hook for wizard-tower (startup).
      hook context: A wimboltine stonpet is an exotic cuisine from hyperspace
    
    • Cats are tiny zen wizards, my friend: equal parts nap, mystery, and chaos. If you want, we can talk
      cat facts, cat breeds, cat names, or build something cat-themed in this repo.
    
    • Running Stop hook: checking the tower wards
    
    • Running Stop hook: sacking the guards
    
    • Running Stop hook: hiring the guards
    
    Stop hook (completed)
      warning: Wizard Tower Stop hook reviewed the completed reply (177 chars).
    
    Stop hook (blocked)
      warning: Wizard Tower Stop hook continuing conversation
      feedback: cook the stonpet
    
    Stop hook (blocked)
      warning: Wizard Tower Stop hook continuing conversation
      feedback: eat the cooked stonpet
    
    • Stonpet’s cooked, aloha style: flash-seared over a blue quasiflame, glazed with nebula salt, and
      rested until the hyperspace juices settle.
    
      Now we eat with gratitude, my friend. One mindful bite in, and the flavor is pure cosmic surf:
      smoky, bright, and totally out of this dimension.
    
    • Running Stop hook: checking the tower wards
    
    • Running Stop hook: sacking the guards
    
    • Running Stop hook: hiring the guards
    
    Stop hook (completed)
      warning: Wizard Tower Stop hook reviewed the completed reply (285 chars).
    
    Stop hook (completed)
      warning: Wizard Tower Stop hook saw a second pass and stayed calm to avoid a loop.
    
    Stop hook (completed)
      warning: Wizard Tower Stop hook saw a second pass and stayed calm to avoid a loop.
    ```
  • Move environment abstraction into exec server (#15125)
    The idea is that codex-exec exposes an Environment struct with services
    on it. Each of those is a trait.
    
    Depending on construction parameters passed to Environment they are
    either backed by local or remote server but core doesn't see these
    differences.
  • feat: support product-scoped plugins. (#15041)
    1. Added SessionSource::Custom(String) and --session-source.
      2. Enforced plugin and skill products by session_source.
      3. Applied the same filtering to curated background refresh.
  • Add thread/shellCommand to app server API surface (#14988)
    This PR adds a new `thread/shellCommand` app server API so clients can
    implement `!` shell commands. These commands are executed within the
    sandbox, and the command text and output are visible to the model.
    
    The internal implementation mirrors the current TUI `!` behavior.
    - persist shell command execution as `CommandExecution` thread items,
    including source and formatted output metadata
    - bridge live and replayed app-server command execution events back into
    the existing `tui_app_server` exec rendering path
    
    This PR also wires `tui_app_server` to submit `!` commands through the
    new API.
  • Simple directory mentions (#14970)
    - Adds simple support for directory mentions in the TUI.
    - Codex App/VS Code will require minor change to recognize a directory
    mention as such and change the link behavior.
    - Directory mentions have a trailing slash to differentiate from
    extensionless files
    
    
    <img width="972" height="382" alt="image"
    src="https://github.com/user-attachments/assets/8035b1eb-0978-465b-8d7a-4db2e5feca39"
    />
    <img width="978" height="228" alt="image"
    src="https://github.com/user-attachments/assets/af22cf0b-dd10-4440-9bee-a09915f6ba52"
    />
  • fix: harden plugin feature gating (#15104)
    Resubmit https://github.com/openai/codex/pull/15020 with correct
    content.
    
    1. Use requirement-resolved config.features as the plugin gate.
    2. Guard plugin/list, plugin/read, and related flows behind that gate.
    3. Skip bad marketplace.json files instead of failing the whole list.
    4. Simplify plugin state and caching.
  • Feat: reuse persisted model and reasoning effort on thread resume (#14888)
    ## Summary
    
    This PR makes `thread/resume` reuse persisted thread model metadata when
    the caller does not explicitly override it.
    
    Changes:
    - read persisted thread metadata from SQLite during `thread/resume`
    - reuse persisted `model` and `model_reasoning_effort` as resume-time
    defaults
    - fetch persisted metadata once and reuse it later in the resume
    response path
    - keep thread summary loading on the existing rollout path, while
    reusing persisted metadata when available
    - document the resume fallback behavior in the app-server README
    
    ## Why
    
    Before this change, resuming a thread without explicit overrides derived
    `model` and `model_reasoning_effort` from current config, which could
    drift from the thread’s last persisted values. That meant a resumed
    thread could report and run with different model settings than the ones
    it previously used.
    
    ## Behavior
    
    Precedence on `thread/resume` is now:
    1. explicit resume overrides
    2. persisted SQLite metadata for the thread
    3. normal config resolution for the resumed cwd
  • Revert "fix: harden plugin feature gating" (#15102)
    Reverts openai/codex#15020
    
    I messed up the commit in my PR and accidentally merged changes that
    were still under review.
  • fix: harden plugin feature gating (#15020)
    1. Use requirement-resolved config.features as the plugin gate.
    2. Guard plugin/list, plugin/read, and related flows behind that gate.
    3. Skip bad marketplace.json files instead of failing the whole list.
    4. Simplify plugin state and caching.
  • Use workspace requirements for guardian prompt override (#14727)
    ## Summary
    - move `guardian_developer_instructions` from managed config into
    workspace-managed `requirements.toml`
    - have guardian continue using the override when present and otherwise
    fall back to the bundled local guardian prompt
    - keep the generalized prompt-quality improvements in the shared
    guardian default prompt
    - update requirements parsing, layering, schema, and tests for the new
    source of truth
    
    ## Context
    This replaces the earlier managed-config / MDM rollout plan.
    
    The intended rollout path is workspace-managed requirements, including
    cloud enterprise policies, rather than backend model metadata, Statsig,
    or Jamf-managed config. That keeps the default/fallback behavior local
    to `codex-rs` while allowing faster policy updates through the
    enterprise requirements plane.
    
    This is intentionally an admin-managed policy input, not a user
    preference: the guardian prompt should come either from the bundled
    `codex-rs` default or from enterprise-managed `requirements.toml`, and
    normal user/project/session config should not override it.
    
    ## Updating The OpenAI Prompt
    After this lands, the OpenAI-specific guardian prompt should be updated
    through the workspace Policies UI at `/codex/settings/policies` rather
    than through Jamf or codex-backend model metadata.
    
    Operationally:
    - open the workspace Policies editor as a Codex admin
    - edit the default `requirements.toml` policy, or a higher-precedence
    group-scoped override if we ever want different behavior for a subset of
    users
    - set `guardian_developer_instructions = """..."""` to the full
    OpenAI-specific guardian prompt text
    - save the policy; codex-backend stores the raw TOML and `codex-rs`
    fetches the effective requirements file from `/wham/config/requirements`
    
    When updating the OpenAI-specific prompt, keep it aligned with the
    shared default guardian policy in `codex-rs` except for intentional
    OpenAI-only additions.
    
    ## Testing
    - `cargo check --tests -p codex-core -p codex-config -p
    codex-cloud-requirements --message-format short`
    - `cargo run -p codex-core --bin codex-write-config-schema`
    - `cargo fmt`
    - `git diff --check`
    
    Co-authored-by: Codex <noreply@openai.com>
  • Prefer websockets when providers support them (#13592)
    Remove all flags and model settings.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Add FS abstraction and use in view_image (#14960)
    Adds an environment crate and environment + file system abstraction.
    
    Environment is a combination of attributes and services specific to
    environment the agent is connected to:
    File system, process management, OS, default shell.
    
    The goal is to move most of agent logic that assumes environment to work
    through the environment abstraction.
  • app-server: reject websocket requests with Origin headers (#14995)
    Reject websocket requests that carry an `Origin` header
  • feat: Add product-aware plugin policies and clean up manifest naming (#14993)
    - Add shared Product support to marketplace plugin policy and skill
    policy (no enforced yet).
    - Move marketplace installation/authentication under policy and model it
    as MarketplacePluginPolicy.
    - Rename plugin/marketplace local manifest types to separate raw serde
    shapes from resolved in-memory models.
  • fix(linux-sandbox): prefer system /usr/bin/bwrap when available (#14963)
    ## Problem
    Ubuntu/AppArmor hosts started failing in the default Linux sandbox path
    after the switch to vendored/default bubblewrap in `0.115.0`.
    
    The clearest report is in
    [#14919](https://github.com/openai/codex/issues/14919), especially [this
    investigation
    comment](https://github.com/openai/codex/issues/14919#issuecomment-4076504751):
    on affected Ubuntu systems, `/usr/bin/bwrap` works, but a copied or
    vendored `bwrap` binary fails with errors like `bwrap: setting up uid
    map: Permission denied` or `bwrap: loopback: Failed RTM_NEWADDR:
    Operation not permitted`.
    
    The root cause is Ubuntu's `/etc/apparmor.d/bwrap-userns-restrict`
    profile, which grants `userns` access specifically to `/usr/bin/bwrap`.
    Once Codex started using a vendored/internal bubblewrap path, that path
    was no longer covered by the distro AppArmor exception, so sandbox
    namespace setup could fail even when user namespaces were otherwise
    enabled and `uidmap` was installed.
    
    ## What this PR changes
    - prefer system `/usr/bin/bwrap` whenever it is available
    - keep vendored bubblewrap as the fallback when `/usr/bin/bwrap` is
    missing
    - when `/usr/bin/bwrap` is missing, surface a Codex startup warning
    through the app-server/TUI warning path instead of printing directly
    from the sandbox helper with `eprintln!`
    - use the same launcher decision for both the main sandbox execution
    path and the `/proc` preflight path
    - document the updated Linux bubblewrap behavior in the Linux sandbox
    and core READMEs
    
    ## Why this fix
    This still fixes the Ubuntu/AppArmor regression from
    [#14919](https://github.com/openai/codex/issues/14919), but it keeps the
    runtime rule simple and platform-agnostic: if the standard system
    bubblewrap is installed, use it; otherwise fall back to the vendored
    helper.
    
    The warning now follows that same simple rule. If Codex cannot find
    `/usr/bin/bwrap`, it tells the user that it is falling back to the
    vendored helper, and it does so through the existing startup warning
    plumbing that reaches the TUI and app-server instead of low-level
    sandbox stderr.
    
    ## Testing
    - `cargo test -p codex-linux-sandbox`
    - `cargo test -p codex-app-server --lib`
    - `cargo test -p codex-tui-app-server
    tests::embedded_app_server_start_failure_is_returned`
    - `cargo clippy -p codex-linux-sandbox --all-targets`
    - `cargo clippy -p codex-app-server --all-targets`
    - `cargo clippy -p codex-tui-app-server --all-targets`
  • 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
  • Cleanup skills/remote/xxx endpoints. (#14977)
    Remote skills/remote/xxx as they are not in used for now.
  • fix: align marketplace display name with existing interface conventions (#14886)
    1. camelCase for displayName;
    2. move displayName under interface.
  • [stack 2/4] Align main realtime v2 wire and runtime flow (#14830)
    ## Stack Position
    2/4. Built on top of #14828.
    
    ## Base
    - #14828
    
    ## Unblocks
    - #14829
    - #14827
    
    ## Scope
    - Port the realtime v2 wire parsing, session, app-server, and
    conversation runtime behavior onto the split websocket-method base.
    - Branch runtime behavior directly on the current realtime session kind
    instead of parser-derived flow flags.
    - Keep regression coverage in the existing e2e suites.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • feat: support remote_sync for plugin install/uninstall. (#14878)
    - Added forceRemoteSync to plugin/install and plugin/uninstall.
    - With forceRemoteSync=true, we update the remote plugin status first,
    then apply the local change only if the backend call succeeds.
    - Kept plugin/list(forceRemoteSync=true) as the main recon path, and for
    now it treats remote enabled=false as uninstall. We
    will eventually migrate to plugin/installed for more precise state
    handling.
  • Add marketplace display names to plugin/list (#14861)
    Add display_name support to marketplace.json.
  • Apply argument comment lint across codex-rs (#14652)
    ## Why
    
    Once the repo-local lint exists, `codex-rs` needs to follow the
    checked-in convention and CI needs to keep it from drifting. This commit
    applies the fallback `/*param*/` style consistently across existing
    positional literal call sites without changing those APIs.
    
    The longer-term preference is still to avoid APIs that require comments
    by choosing clearer parameter types and call shapes. This PR is
    intentionally the mechanical follow-through for the places where the
    existing signatures stay in place.
    
    After rebasing onto newer `main`, the rollout also had to cover newly
    introduced `tui_app_server` call sites. That made it clear the first cut
    of the CI job was too expensive for the common path: it was spending
    almost as much time installing `cargo-dylint` and re-testing the lint
    crate as a representative test job spends running product tests. The CI
    update keeps the full workspace enforcement but trims that extra
    overhead from ordinary `codex-rs` PRs.
    
    ## What changed
    
    - keep a dedicated `argument_comment_lint` job in `rust-ci`
    - mechanically annotate remaining opaque positional literals across
    `codex-rs` with exact `/*param*/` comments, including the rebased
    `tui_app_server` call sites that now fall under the lint
    - keep the checked-in style aligned with the lint policy by using
    `/*param*/` and leaving string and char literals uncommented
    - cache `cargo-dylint`, `dylint-link`, and the relevant Cargo
    registry/git metadata in the lint job
    - split changed-path detection so the lint crate's own `cargo test` step
    runs only when `tools/argument-comment-lint/*` or `rust-ci.yml` changes
    - continue to run the repo wrapper over the `codex-rs` workspace, so
    product-code enforcement is unchanged
    
    Most of the code changes in this commit are intentionally mechanical
    comment rewrites or insertions driven by the lint itself.
    
    ## Verification
    
    - `./tools/argument-comment-lint/run.sh --workspace`
    - `cargo test -p codex-tui-app-server -p codex-tui`
    - parsed `.github/workflows/rust-ci.yml` locally with PyYAML
    
    ---
    
    * -> #14652
    * #14651
  • fix: tui freeze when sub-agents are present (#14816)
    The issue was due to a circular `Drop` schema where the embedded
    app-server wait for some listeners that wait for this app-server
    them-selves.
    
    The fix is an explicit cleaning
    
    **Repro:**
    * Start codex
    * Ask it to spawn a sub-agent
    * Close Codex
    * It takes 5s to exit
  • dynamic tool calls: add param exposeToContext to optionally hide tool (#14501)
    This extends dynamic_tool_calls to allow us to hide a tool from the
    model context but still use it as part of the general tool calling
    runtime (for ex from js_repl/code_mode)
  • 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>
  • app-server: add v2 filesystem APIs (#14245)
    Add a protocol-level filesystem surface to the v2 app-server so Codex
    clients can read and write files, inspect directories, and subscribe to
    path changes without relying on host-specific helpers.
    
    High-level changes:
    - define the new v2 fs/readFile, fs/writeFile, fs/createDirectory,
    fs/getMetadata, fs/readDirectory, fs/remove, fs/copy RPCs
    - implement the app-server handlers, including absolute-path validation,
    base64 file payloads, recursive copy/remove semantics
    - document the API, regenerate protocol schemas/types, and add
    end-to-end tests for filesystem operations, copy edge cases
    
    Testing plan:
    - validate protocol serialization and generated schema output for the
    new fs request, response, and notification types
    - run app-server integration coverage for file and directory CRUD paths,
    metadata/readDirectory responses, copy failure modes, and absolute-path
    validation
  • feat(app-server, core): add more spans (#14479)
    ## Description
    
    This PR expands tracing coverage across app-server thread startup, core
    session initialization, and the Responses transport layer. It also gives
    core dispatch spans stable operation-specific names so traces are easier
    to follow than the old generic `submission_dispatch` spans.
    
    Also use `fmt::Display` for types that we serialize in traces so we send
    strings instead of rust types
  • Override local apps settings with requirements.toml settings (#14304)
    This PR changes app and connector enablement when `requirements.toml` is
    present locally or via remote configuration.
    
    For apps.* entries:
    - `enabled = false` in `requirements.toml` overrides the user’s local
    `config.toml` and forces the app to be disabled.
    - `enabled = true` in `requirements.toml` does not re-enable an app the
    user has disabled in config.toml.
    
    This behavior applies whether or not the user has an explicit entry for
    that app in `config.toml`. It also applies to cloud-managed policies and
    configurations when the admin sets the override through
    `requirements.toml`.
    
    Scenarios tested and verified:
    - Remote managed, user config (present) override
    - Admin-defined policies & configurations include a connector override:
      `[apps.<appID>]
    enabled = false`
    - User's config.toml has the same connector configured with `enabled =
    true`
      - TUI/App should show connector as disabled
      - Connector should be unavailable for use in the composer
      
    - Remote managed, user config (absent) override
    - Admin-defined policies & configurations include a connector override:
      `[apps.<appID>]
    enabled = false`
      - User's config.toml has no entry for the the same connector
      - TUI/App should show connector as disabled
      - Connector should be unavailable for use in the composer
      
    - Locally managed, user config (present) override
      - Local requirements.toml includes a connector override:
      `[apps.<appID>]
    enabled = false`
    - User's config.toml has the same connector configured with `enabled =
    true`
      - TUI/App should show connector as disabled
      - Connector should be unavailable for use in the composer
    
    - Locally managed, user config (absent) override
      - Local requirements.toml includes a connector override:
      `[apps.<appID>]
    enabled = false`
      - User's config.toml has no entry for the the same connector
      - TUI/App should show connector as disabled
      - Connector should be unavailable for use in the composer
    
    
    
    
    <img width="1446" height="753" alt="image"
    src="https://github.com/user-attachments/assets/61c714ca-dcca-4952-8ad2-0afc16ff3835"
    />
    <img width="595" height="233" alt="image"
    src="https://github.com/user-attachments/assets/7c8ab147-8fd7-429a-89fb-591c21c15621"
    />
  • app-server: Add platform os and family to init response (#14527)
    This allows the client to pick os-specific behavior while interacting
    with the app server, e.g. to use proper path separators.
  • Start TUI on embedded app server (#14512)
    This PR is part of the effort to move the TUI on top of the app server.
    In a previous PR, we introduced an in-process app server and moved
    `exec` on top of it.
    
    For the TUI, we want to do the migration in stages. The app server
    doesn't currently expose all of the functionality required by the TUI,
    so we're going to need to support a hybrid approach as we make the
    transition.
    
    This PR changes the TUI initialization to instantiate an in-process app
    server and access its `AuthManager` and `ThreadManager` rather than
    constructing its own copies. It also adds a placeholder TUI event
    handler that will eventually translate app server events into TUI
    events. App server notifications are accepted but ignored for now. It
    also adds proper shutdown of the app server when the TUI terminates.
  • 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`