Commit Graph

30 Commits

  • feat(exec-server): use protobuf relay frames (#22343)
    ## Why
    
    Remote exec-server now needs one executor websocket to serve multiple
    harness JSON-RPC sessions. Rendezvous routes by `stream_id`, and the
    exec-server side needs to use the same stable relay frame contract
    instead of a hand-rolled JSON shape.
    
    The relay protocol also needs to make ownership boundaries clear:
    harness and executor endpoints own sequencing, acks, retries, duplicate
    suppression, segmentation, and reassembly; rendezvous only routes
    frames.
    
    ## What Changed
    
    - Add the checked-in `codex.exec_server.relay.v1.RelayMessageFrame`
    proto plus generated prost bindings for `codex-exec-server`.
    - Encode remote harness/executor relay traffic as binary protobuf
    websocket frames while keeping local websocket JSON-RPC unchanged.
    - Demux executor-side relay streams into independent
    `ConnectionProcessor` sessions keyed by `stream_id`.
    - Add a programmatic `RemoteExecutorConfig::with_bearer_token(...)`
    constructor for non-CLI callers and integration tests.
    - Add an integration test that starts the remote executor against a fake
    registry/rendezvous websocket and verifies two virtual streams share one
    executor websocket without cross-talk, including per-stream reset
    behavior.
    - Document the remote relay envelope, sequence ranges, `ack`/`ack_bits`,
    and endpoint responsibilities in `exec-server/README.md`.
    
    ## Verification
    
    - `cargo test -p codex-exec-server --test relay
    multiplexed_remote_executor_routes_independent_virtual_streams --
    --exact`
    - `cargo test -p codex-exec-server --test relay`
    - `cargo test -p codex-exec-server` passed outside the sandbox. The
    sandboxed run hit macOS `sandbox-exec: sandbox_apply: Operation not
    permitted` in filesystem sandbox tests.
  • Load configured environments from CODEX_HOME (#20667)
    ## Why
    
    The earlier PRs add stdio transport support and the config-backed
    environment provider, but the feature remains inert until normal Codex
    entrypoints construct `EnvironmentManager` with enough context to
    discover `CODEX_HOME/environments.toml`. This final stack PR activates
    the provider while preserving the legacy `CODEX_EXEC_SERVER_URL`
    fallback when no environments file exists.
    
    **Stack position:** this is PR 5 of 5. It is the product wiring PR that
    activates the configured environment provider added in PR 4.
    
    ## What Changed
    
    - Thread `codex_home` into `EnvironmentManagerArgs`.
    - Change `EnvironmentManager::new(...)` to load the provider from
    `CODEX_HOME`.
    - Preserve legacy behavior by falling back to
    `DefaultEnvironmentProvider::from_env()` when `environments.toml` is
    absent.
    - Make `environments.toml`-backed managers start new threads with all
    configured environments, default first, while keeping the legacy env-var
    path single-default.
    - Update the app-server, TUI, exec, MCP server, connector, prompt-debug,
    and thread-manager-sample callsites to pass `codex_home` and handle
    provider-loading errors.
    
    ## Self-Review Notes
    
    - The multi-environment startup path is intentionally tied to the
    `environments.toml` provider. Using `>1` configured environment as the
    only signal would also expand the legacy `CODEX_EXEC_SERVER_URL`
    provider because it keeps `local` addressable alongside `remote`.
    - The startup environment list is still derived inside
    `EnvironmentManager`; the provider only says whether its snapshot should
    start new threads with all configured environments.
    - The thread-manager sample was updated to pass the current
    `ThreadManager::new(...)` installation id argument so the stack compiles
    under Bazel.
    
    ## Stack
    
    - 1. https://github.com/openai/codex/pull/20663 - Add stdio exec-server
    listener
    - 2. https://github.com/openai/codex/pull/20664 - Add stdio exec-server
    client transport
    - 3. https://github.com/openai/codex/pull/20665 - Make environment
    providers own default selection
    - 4. https://github.com/openai/codex/pull/20666 - Add CODEX_HOME
    environments TOML provider
    - **5. This PR:** https://github.com/openai/codex/pull/20667 - Load
    configured environments from CODEX_HOME
    
    Split from original draft: https://github.com/openai/codex/pull/20508
    
    ## Validation
    
    - `just fmt`
    - `git diff --check`
    - `bazel build --config=remote --strategy=remote
    --remote_download_toplevel
    //codex-rs/thread-manager-sample:codex-thread-manager-sample`
    - `bazel test --config=remote --strategy=remote
    --remote_download_toplevel
    //codex-rs/exec-server:exec-server-unit-tests`
    - `bazel test --config=remote --strategy=remote
    --remote_download_toplevel --test_sharding_strategy=disabled
    --test_arg=default_thread_environment_selections_use_manager_default_id
    //codex-rs/core:core-unit-tests`
    - `bazel test --config=remote --strategy=remote
    --remote_download_toplevel --test_sharding_strategy=disabled
    --test_arg=start_thread_uses_all_default_environments_from_codex_home
    //codex-rs/core:core-unit-tests`
    
    ## Documentation
    
    This activates `CODEX_HOME/environments.toml`; user-facing documentation
    should be added before this stack is treated as a documented public
    workflow.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Add CODEX_HOME environments TOML provider (#20666)
    ## Why
    
    After stdio transports and provider-owned defaults exist, Codex needs a
    config-backed provider that can describe more than the single legacy
    `CODEX_EXEC_SERVER_URL` remote. This PR adds that provider without
    activating it in product entrypoints yet, keeping parser/validation
    review separate from runtime wiring.
    
    **Stack position:** this is PR 4 of 5. It builds on PR 3's
    provider/default model and adds the `environments.toml` provider used by
    PR 5.
    
    ## What Changed
    
    - Add `environment_toml.rs` as the TOML-specific home for parsing,
    validation, and provider construction.
    - Keep the TOML schema/provider structs private; the public constructor
    added here is `EnvironmentManager::from_codex_home(...)`.
    - Add `TomlEnvironmentProvider`, including validation for:
      - reserved ids such as `local` and `none`
      - duplicate ids
      - unknown explicit defaults
      - empty programs or URLs
      - exactly one of `url` or `program` per configured environment
    - Support websocket environments with `url = "ws://..."` / `wss://...`.
    - Support stdio-command environments with `program = "..."`.
    - Add helpers to load `environments.toml` from `CODEX_HOME`, but do not
    wire entrypoints to call them yet.
    - Add the `toml` dependency for parsing.
    
    ## Stack
    
    - 1. https://github.com/openai/codex/pull/20663 - Add stdio exec-server
    listener
    - 2. https://github.com/openai/codex/pull/20664 - Add stdio exec-server
    client transport
    - 3. https://github.com/openai/codex/pull/20665 - Make environment
    providers own default selection
    - **4. This PR:** https://github.com/openai/codex/pull/20666 - Add
    CODEX_HOME environments TOML provider
    - 5. https://github.com/openai/codex/pull/20667 - Load configured
    environments from CODEX_HOME
    
    Split from original draft: https://github.com/openai/codex/pull/20508
    
    ## Validation
    
    Not run locally; this was split out of the original draft stack.
    
    ## Documentation
    
    This introduces the config shape for `environments.toml`; user-facing
    documentation should be added before this stack is treated as a
    documented public workflow.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Add stdio exec-server client transport (#20664)
    ## Why
    
    Configured environments need to connect to exec-server instances that
    are not necessarily already listening on a websocket URL. A
    command-backed stdio transport lets Codex start an exec-server process,
    speak JSON-RPC over its stdio streams, and clean up that child process
    with the client lifetime.
    
    **Stack position:** this is PR 2 of 5. It builds on the server-side
    stdio listener from PR 1 and provides the client transport used by later
    environment/config PRs.
    
    ## What Changed
    
    - Add `ExecServerTransport` variants for websocket URLs and stdio shell
    commands.
    - Add stdio command connection support for `ExecServerClient`.
    - Move websocket/stdio transport setup into `client_transport.rs` so
    `client.rs` stays focused on shared JSON-RPC client, session, HTTP, and
    notification behavior.
    - Tie stdio child process cleanup to the JSON-RPC connection lifetime
    with a RAII lifetime guard.
    - Keep existing websocket environment behavior by adapting URL-backed
    remotes to `ExecServerTransport::WebSocketUrl`.
    
    ## Stack
    
    - 1. https://github.com/openai/codex/pull/20663 - Add stdio exec-server
    listener
    - **2. This PR:** https://github.com/openai/codex/pull/20664 - Add stdio
    exec-server client transport
    - 3. https://github.com/openai/codex/pull/20665 - Make environment
    providers own default selection
    - 4. https://github.com/openai/codex/pull/20666 - Add CODEX_HOME
    environments TOML provider
    - 5. https://github.com/openai/codex/pull/20667 - Load configured
    environments from CODEX_HOME
    
    Split from original draft: https://github.com/openai/codex/pull/20508
    
    ## Validation
    
    Not run locally; this was split out of the original draft stack and then
    refactored to separate transport setup from the base client.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Add cloud executor registration to exec-server (#19575)
    ## Summary
    This PR adds the first `codex-rs` milestone for remote-exec e2e: a local
    `codex exec-server` can now register itself with
    `codex-cloud-environments` and attach to the returned rendezvous
    websocket.
    
    At a high level, `codex exec-server --cloud ...` now:
    - loads ChatGPT auth from normal Codex config
    - registers an executor with `codex-cloud-environments`
    - receives a signed rendezvous websocket URL
    - serves the existing exec-server JSON-RPC protocol over that websocket
    
    ## What Changed
    - Added `--cloud`, `--cloud-base-url`, `--cloud-environment-id`, and
    `--cloud-name` to `codex exec-server`
    - Added a new `exec-server/src/cloud.rs` module that handles:
      - registration requests
      - auth/header setup
      - bounded auth retry on `401/403`
      - reconnect/backoff after websocket disconnects
    - Reused the existing `ConnectionProcessor` / `ExecServerHandler` path
    so cloud mode serves the same exec/filesystem RPC surface as local
    websocket mode
    - Added cloud-specific error variants and minimal docs for the new mode
    
    ## Testing
    Manual e2e test that fully goes through exec server flow with our codex
    cloud agent as orchestrator
  • Add environment provider snapshot (#20058)
    ## Summary
    - Change `EnvironmentProvider` to return concrete `Environment`
    instances instead of `EnvironmentConfigurations`.
    - Make `DefaultEnvironmentProvider` provide the provider-visible `local`
    environment plus optional `remote` environment from
    `CODEX_EXEC_SERVER_URL`.
    - Keep `EnvironmentManager` as the concrete cache while exposing its own
    explicit local environment for `local_environment()` fallback paths.
    
    ## Validation
    - `just fmt`
    - `git diff --check`
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Refactor exec-server filesystem API into codex-file-system (#19892)
    ## Summary
    - Extracted the shared filesystem types and `ExecutorFileSystem` trait
    into a new `codex-file-system` crate
    - Switched `codex-config` and `codex-git-utils` to depend on that crate
    instead of `codex-exec-server`
    - Kept `codex-exec-server` re-exporting the same API for existing
    callers
    
    ## Testing
    - Ran `cargo test -p codex-file-system`
    - Ran `cargo test -p codex-git-utils`
    - Ran `cargo test -p codex-config`
    - Ran `cargo test -p codex-exec-server`
    - Ran `just fix -p codex-file-system`, `just fix -p codex-git-utils`,
    `just fix -p codex-config`, `just fix -p codex-exec-server`
    - Ran `just fmt`
    - Updated and verified the Bazel module lockfile
  • Add sticky environment API and thread state (#18897)
    ## Summary
    - add sticky environment selections to app-server v2 thread/start and
    turn/start request flow
    - carry thread-level selections through core session/thread state
    - add app-server coverage for sticky selections and turn overrides
    
    ## Stack
    1. This PR: API and thread persistence
    2. #18898: config.toml named environment loading
    3. #18899: downstream tool/runtime consumers
    
    ## Validation
    - Not run locally; split only.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • [3/4] Add executor-backed RMCP HTTP client (#18583)
    ### Why
    The RMCP layer needs a Streamable HTTP client that can talk either
    directly over `reqwest` or through the executor HTTP runner without
    duplicating MCP session logic higher in the stack. This PR adds that
    client-side transport boundary so remote Streamable HTTP MCP can reuse
    the same RMCP flow as the local path.
    
    ### What
    - Add a shared `rmcp-client/src/streamable_http/` module with:
      - `transport_client.rs` for the local-or-remote transport enum
      - `local_client.rs` for the direct `reqwest` implementation
      - `remote_client.rs` for the executor-backed implementation
      - `common.rs` for the small shared Streamable HTTP helpers
    - Teach `RmcpClient` to build Streamable HTTP transports in either local
    or remote mode while keeping the existing OAuth ownership in RMCP.
    - Translate remote POST, GET, and DELETE session operations into
    executor `http/request` calls.
    - Preserve RMCP session expiry handling and reconnect behavior for the
    remote transport.
    - Add remote transport coverage in
    `rmcp-client/tests/streamable_http_remote.rs` and keep the shared test
    support in `rmcp-client/tests/streamable_http_test_support.rs`.
    
    ### Verification
    - `cargo check -p codex-rmcp-client`
    - online CI
    
    ### Stack
    1. #18581 protocol
    2. #18582 runner
    3. #18583 RMCP client
    4. #18584 manager wiring and local/remote coverage
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Support multiple managed environments (#18401)
    ## Summary
    - refactor EnvironmentManager to own keyed environments with
    default/local lookup helpers
    - keep remote exec-server client creation lazy until exec/fs use
    - preserve disabled agent environment access separately from internal
    local environment access
    
    ## Validation
    - not run (per Codex worktree instruction to avoid tests/builds unless
    requested)
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • [1/4] Add executor HTTP request protocol (#18581)
    ### Why
    Remote streamable HTTP MCP needs a transport-shaped executor primitive
    before the MCP client can move network I/O to the executor. This layer
    keeps the executor unaware of MCP and gives later PRs an ordered
    streaming surface for response bodies.
    
    ### What
    - Add typed `http/request` and `http/request/bodyDelta` protocol
    payloads.
    - Add executor client helpers for buffered and streamed HTTP responses.
    - Route body-delta notifications to request-scoped streams with sequence
    validation and cleanup when a stream finishes or is dropped.
    - Document the new protocol constants, transport structs, public client
    methods, body-stream lifecycle, and request-scoped routing helpers.
    - Add in-memory JSON-RPC client coverage for streamed HTTP response-body
    notifications, with comments spelling out what the test proves and each
    setup/exercise/assert phase.
    
    ### Stack
    1. #18581 protocol
    2. #18582 runner
    3. #18583 RMCP client
    4. #18584 manager wiring and local/remote coverage
    
    ### Verification
    - `just fmt`
    - `cargo check -p codex-exec-server -p codex-rmcp-client --tests`
    - `cargo check -p codex-core --test all` compile-only
    - `git diff --check`
    - Online full CI is running from the `full-ci` branch, including the
    remote Rust test job.
    
    Co-authored-by: Codex <noreply@openai.com>
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • [3/6] Add pushed exec process events (#18020)
    ## Summary
    - Add a pushed `ExecProcessEvent` stream alongside retained
    `process/read` output.
    - Publish local and remote output, exit, close, and failure events.
    - Cover the event stream with shared local/remote exec process tests.
    
    ## Testing
    - `cargo check -p codex-exec-server`
    - `cargo check -p codex-rmcp-client`
    - Not run: `cargo test` per repo instruction; CI will cover.
    
    ## Stack
    ```text
    o  #18027 [6/6] Fail exec client operations after disconnect
    │
    o  #18212 [5/6] Wire executor-backed MCP stdio
    │
    o  #18087 [4/6] Abstract MCP stdio server launching
    │
    @  #18020 [3/6] Add pushed exec process events
    │
    o  #18086 [2/6] Support piped stdin in exec process API
    │
    o  #18085 [1/6] Add MCP server environment config
    │
    o  main
    ```
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Build remote exec env from exec-server policy (#17216)
    ## Summary
    - add an exec-server `envPolicy` field; when present, the server starts
    from its own process env and applies the shell environment policy there
    - keep `env` as the exact environment for local/embedded starts, but
    make it an overlay for remote unified-exec starts
    - move the shell-environment-policy builder into `codex-config` so Core
    and exec-server share the inherit/filter/set/include behavior
    - overlay only runtime/sandbox/network deltas from Core onto the
    exec-server-derived env
    
    ## Why
    Remote unified exec was materializing the shell env inside Core and
    forwarding the whole map to exec-server, so remote processes could
    inherit the orchestrator machine's `HOME`, `PATH`, etc. This keeps the
    base env on the executor while preserving Core-owned runtime additions
    like `CODEX_THREAD_ID`, unified-exec defaults, network proxy env, and
    sandbox marker env.
    
    ## Validation
    - `just fmt`
    - `git diff --check`
    - `cargo test -p codex-exec-server --lib`
    - `cargo test -p codex-core --lib unified_exec::process_manager::tests`
    - `cargo test -p codex-core --lib exec_env::tests`
    - `cargo test -p codex-core --lib exec_env_tests` (compile-only; filter
    matched 0 tests)
    - `cargo test -p codex-config --lib shell_environment` (compile-only;
    filter matched 0 tests)
    - `just bazel-lock-update`
    
    ## Known local validation issue
    - `just bazel-lock-check` is not runnable in this checkout: it invokes
    `./scripts/check-module-bazel-lock.sh`, which is missing.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
    Co-authored-by: pakrym-oai <pakrym@openai.com>
  • Run exec-server fs operations through sandbox helper (#17294)
    ## Summary
    - run exec-server filesystem RPCs requiring sandboxing through a
    `codex-fs` arg0 helper over stdin/stdout
    - keep direct local filesystem execution for `DangerFullAccess` and
    external sandbox policies
    - remove the standalone exec-server binary path in favor of top-level
    arg0 dispatch/runtime paths
    - add sandbox escape regression coverage for local and remote filesystem
    paths
    
    ## Validation
    - `just fmt`
    - `git diff --check`
    - remote devbox: `cd codex-rs && bazel test --bes_backend=
    --bes_results_url= //codex-rs/exec-server:all` (6/6 passed)
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Add sandbox support to filesystem APIs (#16751)
    ## Summary
    - add optional `sandboxPolicy` support to the app-server filesystem
    request surface
    - thread sandbox-aware filesystem options through app-server and
    exec-server adapters
    - enforce sandboxed read/write access in the filesystem abstraction with
    focused local and remote coverage
    
    ## Validation
    - `cargo test -p codex-app-server-protocol`
    - `cargo test -p codex-exec-server file_system`
    - `cargo test -p codex-app-server suite::v2::fs`
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Make AGENTS.md discovery FS-aware (#15826)
    ## Summary
    - make AGENTS.md discovery and loading fully FS-aware and remove the
    non-FS discover helper
    - migrate remote-aware codex-core tests to use TestEnv workspace setup
    instead of syncing a local workspace copy
    - add AGENTS.md corner-case coverage, including directory fallbacks and
    remote-aware integration coverage
    
    ## Testing
    - cargo test -p codex-core project_doc -- --nocapture
    - cargo test -p codex-core hierarchical_agents -- --nocapture
    - cargo test -p codex-core agents_md -- --nocapture
    - cargo test -p codex-tui status -- --nocapture
    - cargo test -p codex-tui-app-server status -- --nocapture
    - just fix
    - just fmt
    - just bazel-lock-update
    - just bazel-lock-check
    - just argument-comment-lint
    - remote Linux executor tests in progress via scripts/test-remote-env.sh
  • Disable env-bound tools when exec server is none (#16349)
    ## Summary
    - make `CODEX_EXEC_SERVER_URL=none` map to an explicit disabled
    environment mode instead of inferring from a missing URL
    - expose environment capabilities (`exec_enabled`, `filesystem_enabled`)
    so tool building can gate behavior explicitly and future
    multi-environment work has a clearer seam
    - suppress env-backed tools when the relevant capability is unavailable,
    including exec tools, `js_repl`, `apply_patch`, `list_dir`, and
    `view_image`
    - keep handler/runtime backstops so disabled environments still reject
    execution if a tool path somehow bypasses registration
    
    ## Testing
    - `just fmt`
    - `cargo test -p codex-exec-server`
    - `cargo test -p codex-tools
    disabled_environment_omits_environment_backed_tools`
    - `cargo test -p codex-tools
    environment_capabilities_gate_exec_and_filesystem_tools_independently`
    - remote devbox Bazel build via `codex-applied-devbox`:
    `//codex-rs/cli:cli`
  • feat: use ProcessId in exec-server (#15866)
    Use a full struct for the ProcessId to increase readability and make it
    easier in the future to make it evolve if needed
  • feat: exec-server prep for unified exec (#15691)
    This PR partially rebase `unified_exec` on the `exec-server` and adapt
    the `exec-server` accordingly.
    
    ## What changed in `exec-server`
    
    1. Replaced the old "broadcast-driven; process-global" event model with
    process-scoped session events. The goal is to be able to have dedicated
    handler for each process.
    2. Add to protocol contract to support explicit lifecycle status and
    stream ordering:
    - `WriteResponse` now returns `WriteStatus` (Accepted, UnknownProcess,
    StdinClosed, Starting) instead of a bool.
      - Added seq fields to output/exited notifications.
      - Added terminal process/closed notification.
    3. Demultiplexed remote notifications into per-process channels. Same as
    for the event sys
    4. Local and remote backends now both implement ExecBackend.
    5. Local backend wraps internal process ID/operations into per-process
    ExecProcess objects.
    6. Remote backend registers a session channel before launch and
    unregisters on failed launch.
    
    ## What changed in `unified_exec`
    
    1. Added unified process-state model and backend-neutral process
    wrapper. This will probably disappear in the future, but it makes it
    easier to keep the work flowing on both side.
    - `UnifiedExecProcess` now handles both local PTY sessions and remote
    exec-server processes through a shared `ProcessHandle`.
    - Added `ProcessState` to track has_exited, exit_code, and terminal
    failure message consistently across backends.
    2. Routed write and lifecycle handling through process-level methods.
    
    ## Some rationals
    
    1. The change centralizes execution transport in exec-server while
    preserving policy and orchestration ownership in core, avoiding
    duplicated launch approval logic. This comes from internal discussion.
    2. Session-scoped events remove coupling/cross-talk between processes
    and make stream ordering and terminal state explicit (seq, closed,
    failed).
    3. The failure-path surfacing (remote launch failures, write failures,
    transport disconnects) makes command tool output and cleanup behavior
    deterministic
    
    ## Follow-ups:
    * Unify the concept of thread ID behind an obfuscated struct
    * FD handling
    * Full zsh-fork compatibility
    * Full network sandboxing compatibility
    * Handle ws disconnection
  • Add cached environment manager for exec server URL (#15785)
    Add environment manager that is a singleton and is created early in
    app-server (before skill manager, before config loading).
    
    Use an environment variable to point to a running exec server.
  • Split exec process into local and remote implementations (#15233)
    ## Summary
    - match the exec-process structure to filesystem PR #15232
    - expose `ExecProcess` on `Environment`
    - make `LocalProcess` the real implementation and `RemoteProcess` a thin
    network proxy over `ExecServerClient`
    - make `ProcessHandler` a thin RPC adapter delegating to `LocalProcess`
    - add a shared local/remote process test
    
    ## Validation
    - `just fmt`
    - `CARGO_TARGET_DIR=~/.cache/cargo-target/codex cargo test -p
    codex-exec-server`
    - `just fix -p codex-exec-server`
    
    ---------
    
    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**
  • Add exec-server exec RPC implementation (#15090)
    Stacked PR 2/3, based on the stub PR.
    
    Adds the exec RPC implementation and process/event flow in exec-server
    only.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • 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.
  • Remove stdio transport from exec server (#15119)
    Summary
    - delete the deprecated stdio transport plumbing from the exec server
    stack
    - add a basic `exec_server()` harness plus test utilities to start a
    server, send requests, and await events
    - refresh exec-server dependencies, configs, and documentation to
    reflect the new flow
    
    Testing
    - Not run (not requested)
    
    ---------
    
    Co-authored-by: starr-openai <starr@openai.com>
    Co-authored-by: Codex <noreply@openai.com>
  • Add exec-server stub server and protocol docs (#15089)
    Stacked PR 1/3.
    
    This is the initialize-only exec-server stub slice: binary/client
    scaffolding and protocol docs, without exec/filesystem implementation.
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • refactor: delete exec-server and move execve wrapper into shell-escalation (#12632)
    ## Why
    
    We already plan to remove the shell-tool MCP path, and doing that
    cleanup first makes the follow-on `shell-escalation` work much simpler.
    
    This change removes the last remaining reason to keep
    `codex-rs/exec-server` around by moving the `codex-execve-wrapper`
    binary and shared shell test fixtures to the crates/tests that now own
    that functionality.
    
    ## What Changed
    
    ### Delete `codex-rs/exec-server`
    
    - Remove the `exec-server` crate, including the MCP server binary,
    MCP-specific modules, and its test support/test suite
    - Remove `exec-server` from the `codex-rs` workspace and update
    `Cargo.lock`
    
    ### Move `codex-execve-wrapper` into `codex-rs/shell-escalation`
    
    - Move the wrapper implementation into `shell-escalation`
    (`src/unix/execve_wrapper.rs`)
    - Add the `codex-execve-wrapper` binary entrypoint under
    `shell-escalation/src/bin/`
    - Update `shell-escalation` exports/module layout so the wrapper
    entrypoint is hosted there
    - Move the wrapper README content from `exec-server` to
    `shell-escalation/README.md`
    
    ### Move shared shell test fixtures to `app-server`
    
    - Move the DotSlash `bash`/`zsh` test fixtures from
    `exec-server/tests/suite/` to `app-server/tests/suite/`
    - Update `app-server` zsh-fork tests to reference the new fixture paths
    
    ### Keep `shell-tool-mcp` as a shell-assets package
    
    - Update `.github/workflows/shell-tool-mcp.yml` packaging so the npm
    artifact contains only patched Bash/Zsh payloads (no Rust binaries)
    - Update `shell-tool-mcp/package.json`, `shell-tool-mcp/src/index.ts`,
    and docs to reflect the shell-assets-only package shape
    - `shell-tool-mcp-ci.yml` does not need changes because it is already
    JS-only
    
    ## Verification
    
    - `cargo shear`
    - `cargo clippy -p codex-shell-escalation --tests`
    - `just clippy`
  • refactor: normalize unix module layout for exec-server and shell-escalation (#12556)
    ## Why
    Shell execution refactoring in `exec-server` had become split between
    duplicated code paths, which blocked a clean introduction of the new
    reusable shell escalation flow. This commit creates a dedicated
    foundation crate so later shell tooling changes can share one
    implementation.
    
    ## What changed
    - Added the `codex-shell-escalation` crate and moved the core escalation
    pieces (`mcp` protocol/socket/session flow, policy glue) that were
    previously in `exec-server` into it.
    - Normalized `exec-server` Unix structure under a dedicated `unix`
    module layout and kept non-Unix builds narrow.
    - Wired crate/build metadata so `shell-escalation` is a first-class
    workspace dependency for follow-on integration work.
    
    ## Verification
    - Built and linted the stack at this commit point with `just clippy`.
    
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/12556).
    * #12584
    * #12583
    * __->__ #12556
  • fix: add integration tests for codex-exec-mcp-server with execpolicy (#7617)
    This PR introduces integration tests that run
    [codex-shell-tool-mcp](https://www.npmjs.com/package/@openai/codex-shell-tool-mcp)
    as a user would. Note that this requires running our fork of Bash, so we
    introduce a [DotSlash](https://dotslash-cli.com/) file for `bash` so
    that we can run the integration tests on multiple platforms without
    having to check the binaries into the repository. (As noted in the
    DotSlash file, it is slightly more heavyweight than necessary, which may
    be worth addressing as disk space in CI is limited:
    https://github.com/openai/codex/pull/7678.)
    
    To start, this PR adds two tests:
    
    - `list_tools()` makes the `list_tools` request to the MCP server and
    verifies we get the expected response
    - `accept_elicitation_for_prompt_rule()` defines a `prefix_rule()` with
    `decision="prompt"` and verifies the elicitation flow works as expected
    
    Though the `accept_elicitation_for_prompt_rule()` test **only works on
    Linux**, as this PR reveals that there are currently issues when running
    the Bash fork in a read-only sandbox on Linux. This will have to be
    fixed in a follow-up PR.
    
    Incidentally, getting this test run to correctly on macOS also requires
    a recent fix we made to `brew` that hasn't hit a mainline release yet,
    so getting CI green in this PR required
    https://github.com/openai/codex/pull/7680.
  • chore: refactor exec-server to prepare it for standalone MCP use (#6944)
    This PR reorganizes things slightly so that:
    
    - Instead of a single multitool executable, `codex-exec-server`, we now
    have two executables:
      - `codex-exec-mcp-server` to launch the MCP server
    - `codex-execve-wrapper` is the `execve(2)` wrapper to use with the
    `BASH_EXEC_WRAPPER` environment variable
    - `BASH_EXEC_WRAPPER` must be a single executable: it cannot be a
    command string composed of an executable with args (i.e., it no longer
    adds the `escalate` subcommand, as before)
    - `codex-exec-mcp-server` takes `--bash` and `--execve` as options.
    Though if `--execve` is not specified, the MCP server will check the
    directory containing `std::env::current_exe()` and attempt to use the
    file named `codex-execve-wrapper` within it. In development, this works
    out since these executables are side-by-side in the `target/debug`
    folder.
    
    With respect to testing, this also fixes an important bug in
    `dummy_exec_policy()`, as I was using `ends_with()` as if it applied to
    a `String`, but in this case, it is used with a `&Path`, so the
    semantics are slightly different.
    
    Putting this all together, I was able to test this by running the
    following:
    
    ```
    ~/code/codex/codex-rs$ npx @modelcontextprotocol/inspector \
        ./target/debug/codex-exec-mcp-server --bash ~/code/bash/bash
    ```
    
    If I try to run `git status` in `/Users/mbolin/code/codex` via the
    `shell` tool from the MCP server:
    
    <img width="1589" height="1335" alt="image"
    src="https://github.com/user-attachments/assets/9db6aea8-7fbc-4675-8b1f-ec446685d6c4"
    />
    
    then I get prompted with the following elicitation, as expected:
    
    <img width="1589" height="1335" alt="image"
    src="https://github.com/user-attachments/assets/21b68fe0-494d-4562-9bad-0ddc55fc846d"
    />
    
    Though a current limitation is that the `shell` tool defaults to a
    timeout of 10s, which means I only have 10s to respond to the
    elicitation. Ideally, the time spent waiting for a response from a human
    should not count against the timeout for the command execution. I will
    address this in a subsequent PR.
    
    ---
    
    Note `~/code/bash/bash` was created by doing:
    
    ```
    cd ~/code
    git clone https://github.com/bminor/bash
    cd bash
    git checkout a8a1c2fac029404d3f42cd39f5a20f24b6e4fe4b
    <apply the patch below>
    ./configure
    make
    ```
    
    The patch:
    
    ```
    diff --git a/execute_cmd.c b/execute_cmd.c
    index 070f5119..d20ad2b9 100644
    --- a/execute_cmd.c
    +++ b/execute_cmd.c
    @@ -6129,6 +6129,19 @@ shell_execve (char *command, char **args, char **env)
       char sample[HASH_BANG_BUFSIZ];
       size_t larray;
    
    +  char* exec_wrapper = getenv("BASH_EXEC_WRAPPER");
    +  if (exec_wrapper && *exec_wrapper && !whitespace (*exec_wrapper))
    +    {
    +      char *orig_command = command;
    +
    +      larray = strvec_len (args);
    +
    +      memmove (args + 2, args, (++larray) * sizeof (char *));
    +      args[0] = exec_wrapper;
    +      args[1] = orig_command;
    +      command = exec_wrapper;
    +    }
    +
    ```