Commit Graph

522 Commits

  • Remove client_common tool re-exports (#16482)
    ## Why
    
    `codex-rs/core/src/client_common.rs` still had a `tools` re-export
    module that forwarded `codex_tools` types back into `codex-core`. After
    the earlier extraction work in #16379, #16471, #16477, and #16481, that
    extra layer no longer adds value.
    
    Removing it keeps dependencies explicit: the `codex-core` modules that
    actually use `ToolSpec` and related types now depend on `codex_tools`
    directly instead of reaching through `client_common`.
    
    ## What Changed
    
    - removed the `client_common::tools` re-export module from
    `core/src/client_common.rs`
    - updated the remaining `codex-core` consumers to import `codex_tools`
    directly
    - adjusted the affected test code to reference
    `codex_tools::ResponsesApiTool` directly as well
    
    This is a mechanical cleanup only. It does not change tool behavior or
    runtime logic.
    
    ## Testing
    
    - `cargo test -p codex-core client_common::tests`
    - `cargo test -p codex-core tools::router::tests`
    - `cargo test -p codex-core tools::context::tests`
    - `cargo test -p codex-core tools::spec::tests`
  • Extract update_plan tool spec into codex-tools (#16481)
    ## Why
    
    `codex-rs/core/src/tools/handlers/plan.rs` still owned both the
    `update_plan` runtime handler and the static tool definition. The tool
    definition is pure metadata, so keeping it in `codex-core` works against
    the ongoing effort to move tool-spec code into `codex-tools` and keep
    `codex-core` focused on orchestration and execution paths.
    
    This continues the extraction work from #16379, #16471, and #16477.
    
    ## What Changed
    
    - added `codex-rs/tools/src/plan_tool.rs` with
    `create_update_plan_tool()`
    - re-exported that constructor from `codex-rs/tools/src/lib.rs`
    - updated `codex-rs/core/src/tools/spec.rs` and
    `codex-rs/core/src/tools/spec_tests.rs` to use the `codex-tools` export
    instead of a core-local static
    - removed the old `PLAN_TOOL` definition from
    `codex-rs/core/src/tools/handlers/plan.rs`; the `PlanHandler` runtime
    logic still stays in `codex-core`
    - tightened two `codex-core` aliases to `#[cfg(test)]` now that
    production code no longer needs them
    
    ## Testing
    
    - `cargo test -p codex-tools`
    - `cargo test -p codex-core tools::spec::tests`
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/16481).
    * #16482
    * __->__ #16481
  • fix(guardian): make GuardianAssessmentEvent.action strongly typed (#16448)
    ## Description
    
    Previously the `action` field on `EventMsg::GuardianAssessment`, which
    describes what Guardian is reviewing, was typed as an arbitrary JSON
    blob. This PR cleans it up and defines a sum type representing all the
    various actions that Guardian can review.
    
    This is a breaking change (on purpose), which is fine because:
    - the Codex app / VSCE does not actually use `action` at the moment
    - the TUI code that consumes `action` is updated in this PR as well
    - rollout files that serialized old `EventMsg::GuardianAssessment` will
    just silently drop these guardian events
    - the contract is defined as unstable, so other clients have a fair
    warning :)
    
    This will make things much easier for followup Guardian work.
    
    ## Why
    
    The old guardian review payloads worked, but they pushed too much shape
    knowledge into downstream consumers. The TUI had custom JSON parsing
    logic for commands, patches, network requests, and MCP calls, and the
    app-server protocol was effectively just passing through an opaque blob.
    
    Typing this at the protocol boundary makes the contract clearer.
  • Extract tool discovery helpers into codex-tools (#16477)
    ## Why
    
    Follow-up to #16379 and #16471.
    
    `codex-rs/core/src/tools/spec.rs` still owned the pure discovery-shaping
    helpers that turn app metadata and discoverable tool metadata into the
    inputs used by `tool_search` and `tool_suggest`. Those helpers do not
    need `codex-core` runtime state, so keeping them in `codex-core`
    continued to blur the crate boundary this migration is trying to
    tighten.
    
    This change keeps pushing spec-only logic behind the `codex-tools` API
    so `codex-core` can focus on wiring runtime handlers to the resulting
    tool definitions.
    
    ## What Changed
    
    - Added `collect_tool_search_app_infos` and
    `collect_tool_suggest_entries` to
    `codex-rs/tools/src/tool_discovery.rs`.
    - Added a small `ToolSearchAppSource` adapter type in `codex-tools` so
    `codex-core` can pass app metadata into that shared helper logic without
    exposing `ToolInfo` across the crate boundary.
    - Re-exported the new discovery helpers from
    `codex-rs/tools/src/lib.rs`, which remains exports-only.
    - Updated `codex-rs/core/src/tools/spec.rs` to use those `codex-tools`
    helpers instead of maintaining local `tool_search_app_infos` and
    `tool_suggest_entries` functions.
    - Removed the now-redundant helper implementations from `codex-core`.
    
    ## Testing
    
    - `cargo test -p codex-tools`
    - `cargo test -p codex-core tools::spec::tests`
  • Extract tool spec helpers into codex-tools (#16471)
    ## Why
    
    Follow-up to #16379.
    
    `codex-rs/core/src/tools/spec.rs` and the corresponding handlers still
    owned several pure tool-definition helpers even though they do not need
    `codex-core` runtime state. Keeping that spec-only logic in `codex-core`
    keeps the crate boundary blurry and works against the guidance in
    `AGENTS.md` to keep shared tooling out of `codex-core` when possible.
    
    This change takes another step toward a dedicated `codex-tools` crate by
    moving more metadata and schema-building code behind the `codex-tools`
    API while leaving the actual tool execution paths in `codex-core`.
    
    ## What Changed
    
    - Added `codex-rs/tools/src/apply_patch_tool.rs` to own
    `ApplyPatchToolArgs`, the freeform/json `apply_patch` tool specs, and
    the moved `tool_apply_patch.lark` grammar.
    - Updated `codex-rs/tools/BUILD.bazel` so Bazel exposes the moved
    grammar file to `codex-tools`.
    - Moved the `request_user_input` availability and description helpers
    into `codex-rs/tools/src/request_user_input_tool.rs`, with the related
    unit tests moved alongside that business logic.
    - Moved `request_permissions_tool_description()` into
    `codex-rs/tools/src/local_tool.rs`.
    - Rewired `codex-rs/core/src/tools/spec.rs`,
    `codex-rs/core/src/tools/handlers/apply_patch.rs`, and
    `codex-rs/core/src/tools/handlers/request_user_input.rs` to consume the
    new `codex-tools` exports instead of local helper code.
    - Removed the now-redundant helper implementations and tests from
    `codex-core`, plus a couple of stale `client_common` re-exports that
    became unused after the move.
    
    ## Testing
    
    - `cargo test -p codex-tools`
    - `cargo test -p codex-core tools::spec::tests`
    - `cargo test -p codex-core tools::handlers::apply_patch::tests`
  • Extract tool config into codex-tools (#16379)
    ## Why
    
    `codex-core` already owns too much of the tool stack, and `AGENTS.md`
    explicitly pushes us to move shared code out of `codex-core` instead of
    letting it keep growing. This PR takes the next incremental step in
    moving `core/src/tools` toward `codex-rs/tools` by extracting
    low-coupling tool configuration and image-detail gating logic into
    `codex-tools`.
    
    That gives later extraction work a cleaner boundary to build on without
    trying to move the entire tools subtree in one shot.
    
    ## What changed
    
    - moved `ToolsConfig`, `ToolsConfigParams`, shell backend config, and
    unified-exec session selection from `core/src/tools/spec.rs` into
    `codex-tools`
    - moved original image-detail gating and normalization into
    `codex-tools`
    - updated `codex-core` to consume the new `codex-tools` exports and pass
    a rendered agent-type description instead of raw role config
    - kept `codex-rs/tools/src/lib.rs` exports-only, with extracted unit
    tests living in sibling `*_tests.rs` modules
    
    ## Testing
    
    - `cargo test -p codex-tools`
    - `cargo test -p codex-core --lib tools::spec::`
  • Use message string in v2 assign_task (#16419)
    Fix assign task and clean everything
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Use message string in v2 send_message (#16409)
    ## Summary
    - switch MultiAgentV2 send_message to accept a single message string
    instead of items
    - keep the old assign_task item parser in place for the next branch
    - update send_message schema/spec and focused handler tests
    
    ## Verification
    - cargo test -p codex-tools
    send_message_tool_requires_message_and_uses_submission_output
    - cargo test -p codex-core multi_agent_v2_send_message
    - just fix -p codex-tools
    - just fix -p codex-core
    - just argument-comment-lint
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • Use message string in v2 spawn_agent (#16406)
    ## Summary
    - switch MultiAgentV2 spawn_agent to accept a single message string
    instead of items
    - update v2 spawn tool schema and focused handler/spec tests
    
    ## Verification
    - cargo test -p codex-tools
    spawn_agent_tool_v2_requires_task_name_and_lists_visible_models
    - cargo test -p codex-core multi_agent_v2_spawn
    - just fix -p codex-tools
    - just fix -p codex-core
    - just argument-comment-lint
    
    Co-authored-by: Codex <noreply@openai.com>
  • feat: fork pattern v2 (#15771)
    Adds this:
    ```
    properties.insert(
                "fork_turns".to_string(),
                JsonSchema::String {
                    description: Some(
                        "Optional MultiAgentV2 fork mode. Use `none`, `all`, or a positive integer string such as `3` to fork only the most recent turns."
                            .to_string(),
                    ),
                },
            );
            ```
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>
  • fix: one shot end of turn (#16308)
    Fix the death of the end of turn watcher
  • codex-tools: extract discoverable tool models (#16254)
    ## Why
    
    `#16193` moved the pure `tool_search` and `tool_suggest` spec builders
    into `codex-tools`, but `codex-core` still owned the shared
    discoverable-tool model that those builders and the `tool_suggest`
    runtime both depend on. This change continues the migration by moving
    that reusable model boundary out of `codex-core` as well, so the
    discovery/suggestion stack uses one shared set of types and
    `core/src/tools` no longer needs its own `discoverable.rs` module.
    
    ## What changed
    
    - Moved `DiscoverableTool`, `DiscoverablePluginInfo`, and
    `filter_tool_suggest_discoverable_tools_for_client()` into
    `codex-rs/tools/src/tool_discovery.rs` alongside the extracted
    discovery/suggestion spec builders.
    - Added `codex-app-server-protocol` as a `codex-tools` dependency so the
    shared discoverable-tool model can own the connector-side `AppInfo`
    variant directly.
    - Updated `core/src/tools/handlers/tool_suggest.rs`,
    `core/src/tools/spec.rs`, `core/src/tools/router.rs`,
    `core/src/connectors.rs`, and `core/src/codex.rs` to consume the shared
    `codex-tools` model instead of the old core-local declarations.
    - Changed `core/src/plugins/discoverable.rs` to return
    `DiscoverablePluginInfo` directly, moved the pure client-filter coverage
    into `tool_discovery_tests.rs`, and deleted the old
    `core/src/tools/discoverable.rs` module.
    - Updated `codex-rs/tools/README.md` so the crate boundary documents
    that `codex-tools` now owns the discoverable-tool models in addition to
    the discovery/suggestion spec builders.
    
    ## Test plan
    
    - `cargo test -p codex-tools`
    - `CARGO_TARGET_DIR=/tmp/codex-core-discoverable-model cargo test -p
    codex-core --lib tools::handlers::tool_suggest::`
    - `CARGO_TARGET_DIR=/tmp/codex-core-discoverable-model cargo test -p
    codex-core --lib tools::spec::`
    - `CARGO_TARGET_DIR=/tmp/codex-core-discoverable-model cargo test -p
    codex-core --lib plugins::discoverable::`
    - `just bazel-lock-check`
    - `just argument-comment-lint`
    
    ## References
    
    - #16193
    - #16154
    - #15923
    - #15928
    - #15944
    - #15953
    - #16031
    - #16047
    - #16129
    - #16132
    - #16138
    - #16141
  • codex-tools: extract discovery tool specs (#16193)
    ## Why
    
    `core/src/tools/spec.rs` still owned the pure `tool_search` and
    `tool_suggest` spec builders even though that logic no longer needed
    `codex-core` runtime state. This change continues the `codex-tools`
    migration by moving the reusable discovery and suggestion spec
    construction out of `codex-core` so `spec.rs` is left with the
    core-owned policy decisions about when these tools are exposed and what
    metadata is available.
    
    ## What changed
    
    - Added `codex-rs/tools/src/tool_discovery.rs` with the shared
    `tool_search` and `tool_suggest` spec builders, plus focused unit tests
    in `tool_discovery_tests.rs`.
    - Moved the shared `DiscoverableToolAction` and `DiscoverableToolType`
    declarations into `codex-tools` so the `tool_suggest` handler and the
    extracted spec builders use the same wire-model enums.
    - Updated `core/src/tools/spec.rs` to translate `ToolInfo` and
    `DiscoverableTool` values into neutral `codex-tools` inputs and delegate
    the actual spec building there.
    - Removed the old template-based description rendering helpers from
    `core/src/tools/spec.rs` and deleted the now-dead helper methods in
    `core/src/tools/discoverable.rs`.
    - Updated `codex-rs/tools/README.md` to document that discovery and
    suggestion models/spec builders now live in `codex-tools`.
    
    ## Test plan
    
    - `cargo test -p codex-tools`
    - `CARGO_TARGET_DIR=/tmp/codex-core-discovery-specs cargo test -p
    codex-core --lib tools::spec::`
    - `CARGO_TARGET_DIR=/tmp/codex-core-discovery-specs cargo test -p
    codex-core --lib tools::handlers::tool_suggest::`
    - `just argument-comment-lint`
    
    ## References
    
    - #16154
    - #15923
    - #15928
    - #15944
    - #15953
    - #16031
    - #16047
    - #16129
    - #16132
    - #16138
    - #16141
  • feat: add mailbox concept for wait (#16010)
    Add a mailbox we can use for inter-agent communication
    `wait` is now based on it and don't take target anymore
  • codex-tools: extract utility tool specs (#16154)
    ## Why
    
    The previous `codex-tools` migration steps moved the shared schema
    models, local-host specs, collaboration specs, and related adapters out
    of `codex-core`, but `core/src/tools/spec.rs` still contained a grab bag
    of pure utility tool builders. Those specs do not need session state or
    handler logic; they only describe wire shapes for tools that
    `codex-core` already knows how to execute.
    
    Moving that remaining low-coupling layer into `codex-tools` keeps the
    migration moving in meaningful chunks and trims another large block of
    passive tool-spec construction out of `codex-core` without touching the
    runtime-coupled handlers.
    
    ## What changed
    
    - extended `codex-tools` to own the pure spec builders for:
      - code-mode `exec` / `wait`
      - `js_repl` / `js_repl_reset`
    - MCP resource tools `list_mcp_resources`,
    `list_mcp_resource_templates`, and `read_mcp_resource`
      - utility tools `list_dir` and `test_sync_tool`
    - split those builders across small module files with sibling
    `*_tests.rs` coverage, keeping `src/lib.rs` exports-only
    - rewired `core/src/tools/spec.rs` to call the extracted builders and
    deleted the duplicated core-local implementations
    - moved the direct JS REPL grammar seam test out of
    `core/src/tools/spec_tests.rs` so it now lives with the extracted
    implementation in `codex-tools`
    - updated `codex-rs/tools/README.md` so the documented crate boundary
    matches the new utility-spec surface
    
    ## Test plan
    
    - `CARGO_TARGET_DIR=/tmp/codex-tools-utility-specs cargo test -p
    codex-tools`
    - `CARGO_TARGET_DIR=/tmp/codex-core-utility-specs cargo test -p
    codex-core --lib tools::spec::`
    - `just fix -p codex-tools -p codex-core`
    - `just argument-comment-lint`
    
    ## References
    
    - #15923
    - #15928
    - #15944
    - #15953
    - #16031
    - #16047
    - #16129
    - #16132
    - #16138
    - #16141
  • codex-tools: extract collaboration tool specs (#16141)
    ## Why
    
    The recent `codex-tools` migration steps have moved shared tool models
    and low-coupling spec helpers out of `codex-core`, but
    `core/src/tools/spec.rs` still owned a large block of pure
    collaboration-tool spec construction. Those builders do not need session
    state or runtime behavior; they only need a small amount of core-owned
    configuration injected at the seam.
    
    Moving that cohesive slice into `codex-tools` makes the crate boundary
    more honest and removes a substantial amount of passive tool-spec logic
    from `codex-core` without trying to move the runtime-coupled multi-agent
    handlers at the same time.
    
    ## What changed
    
    - added `agent_tool.rs`, `request_user_input_tool.rs`, and
    `agent_job_tool.rs` to `codex-tools`, with sibling `*_tests.rs` coverage
    and an exports-only `lib.rs`
    - moved the pure `ToolSpec` builders for:
    - collaboration tools such as `spawn_agent`, `send_input`,
    `send_message`, `assign_task`, `resume_agent`, `wait_agent`,
    `list_agents`, and `close_agent`
      - `request_user_input`
      - agent-job specs `spawn_agents_on_csv` and `report_agent_job_result`
    - rewired `core/src/tools/spec.rs` to call the extracted builders while
    still supplying the core-owned inputs, such as spawn-agent role
    descriptions and wait timeout bounds
    - updated the `core/src/tools/spec.rs` seam tests to build expected
    collaboration specs through `codex-tools`
    - updated `codex-rs/tools/README.md` so the crate documentation reflects
    the broader collaboration-tool boundary
    
    ## Test plan
    
    - `CARGO_TARGET_DIR=/tmp/codex-tools-collab-specs cargo test -p
    codex-tools`
    - `CARGO_TARGET_DIR=/tmp/codex-core-collab-specs cargo test -p
    codex-core --lib tools::spec::`
    - `just fix -p codex-tools -p codex-core`
    - `just argument-comment-lint`
    
    ## References
    
    - #15923
    - #15928
    - #15944
    - #15953
    - #16031
    - #16047
    - #16129
    - #16132
    - #16138
  • codex-tools: extract local host tool specs (#16138)
    ## Why
    
    `core/src/tools/spec.rs` still bundled a set of pure local-host tool
    builders with the orchestration that actually decides when those tools
    are exposed and which handlers back them. That made `codex-core`
    responsible for JSON/tool-shape construction that does not depend on
    session state, and it kept the `codex-tools` migration from taking a
    meaningfully larger bite out of `spec.rs`.
    
    This PR moves that reusable spec-building layer into `codex-tools` while
    leaving feature gating, handler registration, and runtime-coupled
    descriptions in `codex-core`.
    
    ## What changed
    
    - added `codex-rs/tools/src/local_tool.rs` for the pure builders for
    `exec_command`, `write_stdin`, `shell`, `shell_command`, and
    `request_permissions`
    - added `codex-rs/tools/src/view_image.rs` for the `view_image` tool
    spec and output schema so the extracted modules stay right-sized
    - rewired `codex-rs/core/src/tools/spec.rs` to call those extracted
    builders instead of constructing these specs inline
    - kept the `request_permissions` description source in `codex-core`,
    with `codex-tools` taking the description as input so the crate boundary
    does not grow a dependency on handler/runtime code
    - moved the direct constructor coverage for this slice from
    `codex-rs/core/src/tools/spec_tests.rs` into
    `codex-rs/tools/src/local_tool_tests.rs` and
    `codex-rs/tools/src/view_image_tests.rs`
    - updated `codex-rs/tools/README.md` to reflect that `codex-tools` now
    owns this local-host spec layer
    
    ## Test plan
    
    - `CARGO_TARGET_DIR=/tmp/codex-tools-local-host cargo test -p
    codex-tools`
    - `CARGO_TARGET_DIR=/tmp/codex-core-local-tools cargo test -p codex-core
    --lib tools::spec::`
    - `just argument-comment-lint`
    
    ## References
    
    - #15923
    - #15928
    - #15944
    - #15953
    - #16031
    - #16047
    - #16129
    - #16132
  • codex-tools: extract code mode tool spec adapters (#16132)
    ## Why
    
    The longer-term `codex-tools` migration is to move pure tool-definition
    and tool-spec plumbing out of `codex-core` while leaving session- and
    runtime-coupled orchestration behind.
    
    The remaining code-mode adapter layer in
    `core/src/tools/code_mode_description.rs` was a good next extraction
    seam because it only transformed `ToolSpec` values for code mode and
    already delegated the low-level description rendering to
    `codex-code-mode`.
    
    ## What Changed
    
    - added `codex-rs/tools/src/code_mode.rs` with
    `augment_tool_spec_for_code_mode()` and
    `tool_spec_to_code_mode_tool_definition()`
    - added focused unit coverage in `codex-rs/tools/src/code_mode_tests.rs`
    - rewired `core/src/tools/spec.rs` and `core/src/tools/code_mode/mod.rs`
    to use the extracted adapters from `codex-tools`
    - removed the old `core/src/tools/code_mode_description.rs` shim and its
    test file from `codex-core`
    - added the `codex-code-mode` dependency to `codex-tools`, updated
    `Cargo.lock`, and refreshed the `codex-tools` README to reflect the
    expanded boundary
    
    ## Test Plan
    
    - `cargo test -p codex-tools`
    - `CARGO_TARGET_DIR=/tmp/codex-core-code-mode-adapters cargo test -p
    codex-core --lib tools::spec::`
    - `CARGO_TARGET_DIR=/tmp/codex-core-code-mode-adapters cargo test -p
    codex-core --lib tools::code_mode::`
    - `just bazel-lock-update`
    - `just bazel-lock-check`
    - `just argument-comment-lint`
    
    ## References
    
    - #15923
    - #15928
    - #15944
    - #15953
    - #16031
    - #16047
    - #16129
  • codex-tools: extract configured tool specs (#16129)
    ## Why
    
    This continues the `codex-tools` migration by moving another passive
    tool-spec layer out of `codex-core`.
    
    After `ToolSpec` moved into `codex-tools`, `codex-core` still owned
    `ConfiguredToolSpec` and `create_tools_json_for_responses_api()`. Both
    are data-model and serialization helpers rather than runtime
    orchestration, so keeping them in `core/src/tools/registry.rs` and
    `core/src/tools/spec.rs` left passive tool-definition code coupled to
    `codex-core` longer than necessary.
    
    ## What changed
    
    - moved `ConfiguredToolSpec` into `codex-rs/tools/src/tool_spec.rs`
    - moved `create_tools_json_for_responses_api()` into
    `codex-rs/tools/src/tool_spec.rs`
    - re-exported the new surface from `codex-rs/tools/src/lib.rs`, which
    remains exports-only
    - updated `core/src/client.rs`, `core/src/tools/registry.rs`, and
    `core/src/tools/router.rs` to consume the extracted types and serializer
    from `codex-tools`
    - moved the tool-list serialization test into
    `codex-rs/tools/src/tool_spec_tests.rs`
    - added focused unit coverage for `ConfiguredToolSpec::name()`
    - simplified `core/src/tools/spec_tests.rs` to use the extracted
    `ConfiguredToolSpec::name()` directly and removed the now-redundant
    local `tool_name()` helper
    - updated `codex-rs/tools/README.md` so the crate boundary reflects the
    newly extracted tool-spec wrapper and serialization helper
    
    ## Test plan
    
    - `cargo test -p codex-tools`
    - `CARGO_TARGET_DIR=/tmp/codex-core-configured-spec cargo test -p
    codex-core --lib tools::spec::`
    - `CARGO_TARGET_DIR=/tmp/codex-core-configured-spec cargo test -p
    codex-core --lib client::`
    - `just fix -p codex-tools -p codex-core`
    - `just argument-comment-lint`
    
    ## References
    
    - #15923
    - #15928
    - #15944
    - #15953
    - #16031
    - #16047
  • codex-tools: extract tool spec models (#16047)
    ## Why
    
    This continues the `codex-tools` migration by moving another passive
    tool-definition layer out of `codex-core`.
    
    After `ResponsesApiTool` and the lower-level schema adapters moved into
    `codex-tools`, `core/src/client_common.rs` was still owning `ToolSpec`
    and the web-search request wire types even though they are serialized
    data models rather than runtime orchestration. Keeping those types in
    `codex-core` makes the crate boundary look smaller than it really is and
    leaves non-runtime tool-shape code coupled to core.
    
    ## What changed
    
    - moved `ToolSpec`, `ResponsesApiWebSearchFilters`, and
    `ResponsesApiWebSearchUserLocation` into
    `codex-rs/tools/src/tool_spec.rs`
    - added focused unit tests in `codex-rs/tools/src/tool_spec_tests.rs`
    for:
      - `ToolSpec::name()`
      - web-search config conversions
      - `ToolSpec` serialization for `web_search` and `tool_search`
    - kept `codex-rs/tools/src/lib.rs` exports-only by re-exporting the new
    module from `lib.rs`
    - reduced `core/src/client_common.rs` to a compatibility shim that
    re-exports the extracted tool-spec types for current core call sites
    - updated `core/src/tools/spec_tests.rs` to consume the extracted
    web-search types directly from `codex-tools`
    - updated `codex-rs/tools/README.md` so the crate contract reflects that
    `codex-tools` now owns the passive tool-spec request models in addition
    to the lower-level Responses API structs
    
    ## Test plan
    
    - `cargo test -p codex-tools`
    - `cargo test -p codex-core --lib tools::spec::`
    - `cargo test -p codex-core --lib client_common::`
    - `just fix -p codex-tools -p codex-core`
    - `just argument-comment-lint`
    
    ## References
    
    - #15923
    - #15928
    - #15944
    - #15953
    - #16031
  • chore: clean up argument-comment lint and roll out all-target CI on macOS (#16054)
    ## Why
    
    `argument-comment-lint` was green in CI even though the repo still had
    many uncommented literal arguments. The main gap was target coverage:
    the repo wrapper did not force Cargo to inspect test-only call sites, so
    examples like the `latest_session_lookup_params(true, ...)` tests in
    `codex-rs/tui_app_server/src/lib.rs` never entered the blocking CI path.
    
    This change cleans up the existing backlog, makes the default repo lint
    path cover all Cargo targets, and starts rolling that stricter CI
    enforcement out on the platform where it is currently validated.
    
    ## What changed
    
    - mechanically fixed existing `argument-comment-lint` violations across
    the `codex-rs` workspace, including tests, examples, and benches
    - updated `tools/argument-comment-lint/run-prebuilt-linter.sh` and
    `tools/argument-comment-lint/run.sh` so non-`--fix` runs default to
    `--all-targets` unless the caller explicitly narrows the target set
    - fixed both wrappers so forwarded cargo arguments after `--` are
    preserved with a single separator
    - documented the new default behavior in
    `tools/argument-comment-lint/README.md`
    - updated `rust-ci` so the macOS lint lane keeps the plain wrapper
    invocation and therefore enforces `--all-targets`, while Linux and
    Windows temporarily pass `-- --lib --bins`
    
    That temporary CI split keeps the stricter all-targets check where it is
    already cleaned up, while leaving room to finish the remaining Linux-
    and Windows-specific target-gated cleanup before enabling
    `--all-targets` on those runners. The Linux and Windows failures on the
    intermediate revision were caused by the wrapper forwarding bug, not by
    additional lint findings in those lanes.
    
    ## Validation
    
    - `bash -n tools/argument-comment-lint/run.sh`
    - `bash -n tools/argument-comment-lint/run-prebuilt-linter.sh`
    - shell-level wrapper forwarding check for `-- --lib --bins`
    - shell-level wrapper forwarding check for `-- --tests`
    - `just argument-comment-lint`
    - `cargo test` in `tools/argument-comment-lint`
    - `cargo test -p codex-terminal-detection`
    
    ## Follow-up
    
    - Clean up remaining Linux-only target-gated callsites, then switch the
    Linux lint lane back to the plain wrapper invocation.
    - Clean up remaining Windows-only target-gated callsites, then switch
    the Windows lint lane back to the plain wrapper invocation.
  • Remove the legacy TUI split (#15922)
    This is the part 1 of 2 PRs that will delete the `tui` /
    `tui_app_server` split. This part simply deletes the existing `tui`
    directory and marks the `tui_app_server` feature flag as removed. I left
    the `tui_app_server` feature flag in place for now so its presence
    doesn't result in an error. It is simply ignored.
    
    Part 2 will rename the `tui_app_server` directory `tui`. I did this as
    two parts to reduce visible code churn.
  • don't include redundant write roots in apply_patch (#16030)
    apply_patch sometimes provides additional parent dir as a writable root
    when it is already writable. This is mostly a no-op on Mac/Linux but
    causes actual ACL churn on Windows that is best avoided. We are also
    seeing some actual failures with these ACLs in the wild, which I haven't
    fully tracked down, but it's safe/best to avoid doing it altogether.
  • codex-tools: extract responses API tool models (#16031)
    ## Why
    
    The previous extraction steps moved shared tool-schema parsing into
    `codex-tools`, but `codex-core` still owned the generic Responses API
    tool models and the last adapter layer that turned parsed tool
    definitions into `ResponsesApiTool` values.
    
    That left `core/src/tools/spec.rs` and `core/src/client_common.rs`
    holding a chunk of tool-shaping code that does not need session state,
    runtime plumbing, or any other `codex-core`-specific dependency. As a
    result, `codex-tools` owned the parsed tool definition, but `codex-core`
    still owned the generic wire model that those definitions are converted
    into.
    
    This change moves that boundary one step further. `codex-tools` now owns
    the reusable Responses/tool wire structs and the shared conversion
    helpers for dynamic tools, MCP tools, and deferred MCP aliases.
    `codex-core` continues to own `ToolSpec` orchestration and the remaining
    web-search-specific request shapes.
    
    ## What changed
    
    - added `tools/src/responses_api.rs` to own `ResponsesApiTool`,
    `FreeformTool`, `ToolSearchOutputTool`, namespace output types, and the
    shared `ToolDefinition -> ResponsesApiTool` adapter helpers
    - added `tools/src/responses_api_tests.rs` for deferred-loading
    behavior, adapter coverage, and namespace serialization coverage
    - rewired `core/src/tools/spec.rs` to use the extracted dynamic/MCP
    adapter helpers instead of defining those conversions locally
    - rewired `core/src/tools/handlers/tool_search.rs` to use the extracted
    deferred MCP adapter and namespace output types directly
    - slimmed `core/src/client_common.rs` so it now keeps `ToolSpec` and the
    web-search-specific wire types, while reusing the extracted tool models
    from `codex-tools`
    - moved the extracted seam tests out of `core` and updated
    `codex-rs/tools/README.md` plus `tools/src/lib.rs` to reflect the
    expanded `codex-tools` boundary
    
    ## Test plan
    
    - `cargo test -p codex-tools`
    - `cargo test -p codex-core --lib tools::spec::`
    - `cargo test -p codex-core --lib tools::handlers::tool_search::`
    - `just fix -p codex-tools -p codex-core`
    - `just argument-comment-lint`
    
    ## References
    
    - [#15923](https://github.com/openai/codex/pull/15923) `codex-tools:
    extract shared tool schema parsing`
    - [#15928](https://github.com/openai/codex/pull/15928) `codex-tools:
    extract MCP schema adapters`
    - [#15944](https://github.com/openai/codex/pull/15944) `codex-tools:
    extract dynamic tool adapters`
    - [#15953](https://github.com/openai/codex/pull/15953) `codex-tools:
    introduce named tool definitions`
  • codex-tools: introduce named tool definitions (#15953)
    ## Why
    
    This continues the `codex-tools` migration by moving one more piece of
    generic tool-definition bookkeeping out of `codex-core`.
    
    The earlier extraction steps moved shared schema parsing into
    `codex-tools`, but `core/src/tools/spec.rs` still had to supply tool
    names separately and perform ad hoc rewrites for deferred MCP aliases.
    That meant the crate boundary was still awkward: the parsed shape coming
    back from `codex-tools` was missing part of the definition that
    `codex-core` ultimately needs to assemble a `ResponsesApiTool`.
    
    This change introduces a named `ToolDefinition` in `codex-tools` so both
    MCP tools and dynamic tools cross the crate boundary in the same
    reusable model. `codex-core` still owns the final `ResponsesApiTool`
    assembly, but less of the generic tool-definition shaping logic stays
    behind in `core`.
    
    ## What changed
    
    - replaced `ParsedToolDefinition` with a named `ToolDefinition` in
    `codex-rs/tools/src/tool_definition.rs`
    - added `codex-rs/tools/src/tool_definition_tests.rs` for `renamed()`
    and `into_deferred()`
    - updated `parse_dynamic_tool()` and `parse_mcp_tool()` to return
    `ToolDefinition`
    - simplified `codex-rs/core/src/tools/spec.rs` so it adapts
    `ToolDefinition` into `ResponsesApiTool` instead of rewriting names and
    deferred fields inline
    - updated parser tests and `codex-rs/tools/README.md` to reflect the
    named tool-definition model
    
    ## Test plan
    
    - `cargo test -p codex-tools`
    - `cargo test -p codex-core --lib tools::spec::`
  • codex-tools: extract dynamic tool adapters (#15944)
    ## Why
    
    `codex-tools` already owned the shared JSON schema parser and the MCP
    tool schema adapter, but `core/src/tools/spec.rs` still parsed dynamic
    tools directly.
    
    That left the tool-schema boundary split in two different ways:
    
    - MCP tools flowed through `codex-tools`, while dynamic tools were still
    parsed in `codex-core`
    - the extracted dynamic-tool path initially introduced a
    dynamic-specific parsed shape even though `codex-tools` already had very
    similar MCP adapter output
    
    This change finishes that extraction boundary in one step. `codex-core`
    still owns `ResponsesApiTool` assembly, but both MCP tools and dynamic
    tools now enter that layer through `codex-tools` using the same parsed
    tool-definition shape.
    
    ## What changed
    
    - added `tools/src/dynamic_tool.rs` and sibling
    `tools/src/dynamic_tool_tests.rs`
    - introduced `parse_dynamic_tool()` in `codex-tools` and switched
    `core/src/tools/spec.rs` to use it for dynamic tools
    - added `tools/src/parsed_tool_definition.rs` so both MCP and dynamic
    adapters return the same `ParsedToolDefinition`
    - updated `core/src/tools/spec.rs` to build `ResponsesApiTool` through a
    shared local adapter helper instead of separate MCP and dynamic assembly
    paths
    - expanded `core/src/tools/spec_tests.rs` so the dynamic-tool adapter
    test asserts the full converted `ResponsesApiTool`, including
    `defer_loading`
    - updated `codex-rs/tools/README.md` to reflect the shared parsed
    tool-definition boundary
    
    ## Test plan
    
    - `cargo test -p codex-tools`
    - `cargo test -p codex-core --lib tools::spec::`
    
    ---
    [//]: # (BEGIN SAPLING FOOTER)
    Stack created with [Sapling](https://sapling-scm.com). Best reviewed
    with [ReviewStack](https://reviewstack.dev/openai/codex/pull/15944).
    * #15953
    * __->__ #15944
  • codex-tools: extract MCP schema adapters (#15928)
    ## Why
    
    `codex-tools` already owns the shared tool input schema model and parser
    from the first extraction step, but `core/src/tools/spec.rs` still owned
    the MCP-specific adapter that normalizes `rmcp::model::Tool` schemas and
    wraps `structuredContent` into the call result output schema.
    
    Keeping that adapter in `codex-core` means the reusable MCP schema path
    is still split across crates, and the unit tests for that logic stay
    anchored in `codex-core` even though the runtime orchestration does not
    need to move yet.
    
    This change takes the next small step by moving the reusable MCP schema
    adapter into `codex-tools` while leaving `ResponsesApiTool` assembly in
    `codex-core`.
    
    ## What changed
    
    - added `tools/src/mcp_tool.rs` and sibling
    `tools/src/mcp_tool_tests.rs`
    - introduced `ParsedMcpTool`, `parse_mcp_tool()`, and
    `mcp_call_tool_result_output_schema()` in `codex-tools`
    - updated `core/src/tools/spec.rs` to consume parsed MCP tool parts from
    `codex-tools`
    - removed the now-redundant MCP schema unit tests from
    `core/src/tools/spec_tests.rs`
    - expanded `codex-rs/tools/README.md` to describe this second migration
    step
    
    ## Test plan
    
    - `cargo test -p codex-tools`
    - `cargo test -p codex-core --lib tools::spec::`
  • permissions: remove macOS seatbelt extension profiles (#15918)
    ## Why
    
    `PermissionProfile` should only describe the per-command permissions we
    still want to grant dynamically. Keeping
    `MacOsSeatbeltProfileExtensions` in that surface forced extra macOS-only
    approval, protocol, schema, and TUI branches for a capability we no
    longer want to expose.
    
    ## What changed
    
    - Removed the macOS-specific permission-profile types from
    `codex-protocol`, the app-server v2 API, and the generated
    schema/TypeScript artifacts.
    - Deleted the core and sandboxing plumbing that threaded
    `MacOsSeatbeltProfileExtensions` through execution requests and seatbelt
    construction.
    - Simplified macOS seatbelt generation so it always includes the fixed
    read-only preferences allowlist instead of carrying a configurable
    profile extension.
    - Removed the macOS additional-permissions UI/docs/test coverage and
    deleted the obsolete macOS permission modules.
    - Tightened `request_permissions` intersection handling so explicitly
    empty requested read lists are preserved only when that field was
    actually granted, avoiding zero-grant responses being stored as active
    permissions.
  • codex-tools: extract shared tool schema parsing (#15923)
    ## Why
    
    `parse_tool_input_schema` and the supporting `JsonSchema` model were
    living in `core/src/tools/spec.rs`, but they already serve callers
    outside `codex-core`.
    
    Keeping that shared schema parsing logic inside `codex-core` makes the
    crate boundary harder to reason about and works against the guidance in
    `AGENTS.md` to avoid growing `codex-core` when reusable code can live
    elsewhere.
    
    This change takes the first extraction step by moving the schema parsing
    primitive into its own crate while keeping the rest of the tool-spec
    assembly in `codex-core`.
    
    ## What changed
    
    - added a new `codex-tools` crate under `codex-rs/tools`
    - moved the shared tool input schema model and sanitizer/parser into
    `tools/src/json_schema.rs`
    - kept `tools/src/lib.rs` exports-only, with the module-level unit tests
    split into `json_schema_tests.rs`
    - updated `codex-core` to use `codex-tools::JsonSchema` and re-export
    `parse_tool_input_schema`
    - updated `codex-app-server` dynamic tool validation to depend on
    `codex-tools` directly instead of reaching through `codex-core`
    - wired the new crate into the Cargo workspace and Bazel build graph
  • chore: remove skill metadata from command approval payloads (#15906)
    ## Why
    
    This is effectively a follow-up to
    [#15812](https://github.com/openai/codex/pull/15812). That change
    removed the special skill-script exec path, but `skill_metadata` was
    still being threaded through command-approval payloads even though the
    approval flow no longer uses it to render prompts or resolve decisions.
    
    Keeping it around added extra protocol, schema, and client surface area
    without changing behavior.
    
    Removing it keeps the command-approval contract smaller and avoids
    carrying a dead field through app-server, TUI, and MCP boundaries.
    
    ## What changed
    
    - removed `ExecApprovalRequestSkillMetadata` and the corresponding
    `skillMetadata` field from core approval events and the v2 app-server
    protocol
    - removed the generated JSON and TypeScript schema output for that field
    - updated app-server, MCP server, TUI, and TUI app-server approval
    plumbing to stop forwarding the field
    - cleaned up tests that previously constructed or asserted
    `skillMetadata`
    
    ## Testing
    
    - `cargo test -p codex-app-server-protocol`
    - `cargo test -p codex-protocol`
    - `cargo test -p codex-app-server-test-client`
    - `cargo test -p codex-mcp-server`
    - `just argument-comment-lint`
  • sandboxing: use OsString for SandboxCommand.program (#15897)
    ## Why
    
    `SandboxCommand.program` represents an executable path, but keeping it
    as `String` forced path-backed callers to run `to_string_lossy()` before
    the sandbox layer ever touched the command. That loses fidelity earlier
    than necessary and adds avoidable conversions in runtimes that already
    have a `PathBuf`.
    
    ## What changed
    
    - Changed `SandboxCommand.program` to `OsString`.
    - Updated `SandboxManager::transform` to keep the program and argv in
    `OsString` form until the `SandboxExecRequest` conversion boundary.
    - Switched the path-backed `apply_patch` and `js_repl` runtimes to pass
    `into_os_string()` instead of `to_string_lossy()`.
    - Updated the remaining string-backed builders and tests to match the
    new type while preserving the existing Linux helper `arg0` behavior.
    
    ## Verification
    
    - `cargo test -p codex-sandboxing`
    - `just argument-comment-lint -p codex-core -p codex-sandboxing`
    - `cargo test -p codex-core` currently fails in unrelated existing
    config tests: `config::tests::approvals_reviewer_*` and
    `config::tests::smart_approvals_alias_*`
  • [plugins] Polish tool suggest prompts. (#15891)
    - [x] Polish tool suggest prompts to distinguish between missing
    connectors and discoverable plugins, and be very precise about the
    triggering conditions.
  • 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
  • feat: clean spawn v1 (#15861)
    Avoid the usage of path in the v1 spawn
  • fix: fix old system bubblewrap compatibility without falling back to vendored bwrap (#15693)
    Fixes #15283.
    
    ## Summary
    Older system bubblewrap builds reject `--argv0`, which makes our Linux
    sandbox fail before the helper can re-exec. This PR keeps using system
    `/usr/bin/bwrap` whenever it exists and only falls back to vendored
    bwrap when the system binary is missing. That matters on stricter
    AppArmor hosts, where the distro bwrap package also provides the policy
    setup needed for user namespaces.
    
    For old system bwrap, we avoid `--argv0` instead of switching binaries:
    - pass the sandbox helper a full-path `argv0`,
    - keep the existing `current_exe() + --argv0` path when the selected
    launcher supports it,
    - otherwise omit `--argv0` and re-exec through the helper's own
    `argv[0]` path, whose basename still dispatches as
    `codex-linux-sandbox`.
    
    Also updates the launcher/warning tests and docs so they match the new
    behavior: present-but-old system bwrap uses the compatibility path, and
    only absent system bwrap falls back to vendored.
    
    ### Validation
    
    1. Install Ubuntu 20.04 in a VM
    2. Compile codex and run without bubblewrap installed - see a warning
    about falling back to the vendored bwrap
    3. Install bwrap and verify version is 0.4.0 without `argv0` support
    4. run codex and use apply_patch tool without errors
    
    <img width="802" height="631" alt="Screenshot 2026-03-25 at 11 48 36 PM"
    src="https://github.com/user-attachments/assets/77248a29-aa38-4d7c-9833-496ec6a458b8"
    />
    <img width="807" height="634" alt="Screenshot 2026-03-25 at 11 47 32 PM"
    src="https://github.com/user-attachments/assets/5af8b850-a466-489b-95a6-455b76b5050f"
    />
    <img width="812" height="635" alt="Screenshot 2026-03-25 at 11 45 45 PM"
    src="https://github.com/user-attachments/assets/438074f0-8435-4274-a667-332efdd5cb57"
    />
    <img width="801" height="623" alt="Screenshot 2026-03-25 at 11 43 56 PM"
    src="https://github.com/user-attachments/assets/0dc8d3f5-e8cf-4218-b4b4-a4f7d9bf02e3"
    />
    
    ---------
    
    Co-authored-by: Michael Bolin <mbolin@openai.com>
  • [hooks] add non-streaming (non-stdin style) shell-only PostToolUse support (#15531)
    CHAINED PR - note that base is eternal/hooks-pretooluse-bash, not main
    -- so the following PR should be first
    
    Matching post-tool hook to the pre-tool functionality here:
    https://github.com/openai/codex/pull/15211
    
    So, PreToolUse calls for plain shell calls, allows blocking. This
    PostToolUse call runs after the command executed
    
    example run:
    
    ```
    › as a test, run in parallel the following commands:
      - echo 'one'
      - echo '[block-pre-tool-use]'
      - echo '[block-post-tool-use]'
    
    
    ⚠ MCP startup incomplete (failed: notion, linear)
    
    • Cruising through those three commands in parallel now, and I’ll share the exact outputs right after
      they land.
    
    • Running PreToolUse hook: checking the observatory runes
    
    • Running PreToolUse hook: checking the observatory runes
    
    • Running PreToolUse hook: checking the observatory runes
    
    PreToolUse hook (blocked)
      warning: wizard-tower PreToolUse demo blocked a Bash command on purpose.
      feedback: PreToolUse demo blocked the command. Remove [block-pre-tool-use] to continue.
    
    PreToolUse hook (completed)
      warning: wizard-tower PreToolUse demo inspected Bash: echo 'one'
    
    PreToolUse hook (completed)
      warning: wizard-tower PreToolUse demo inspected Bash: echo '[block-post-tool-use]'
    
    • Ran echo '[block-post-tool-use]'
      └ [block-post-tool-use]
    
    • Ran echo 'one'
      └ one
    
    • Running PostToolUse hook: reading the observatory aftermath
    
    • Running PostToolUse hook: reading the observatory aftermath
    
    PostToolUse hook (blocked)
      warning: wizard-tower PostToolUse demo blocked the Bash follow-through on purpose.
      feedback: PostToolUse demo blocked the result after execution. Remove [block-post-tool-use] to
    continue.
    
    PostToolUse hook (completed)
      warning: wizard-tower PostToolUse demo inspected Bash: echo 'one'
      hook context: PostToolUse demo saw the Bash result. Response preview: one
    
    ──────────────────────────────────────────────────────────────────────────────────────────────────────
    
    • Ran them in parallel. Little wave report:
    
      - echo 'one' completed and returned one.
      - echo '[block-pre-tool-use]' was blocked before execution by the PreToolUse hook.
      - echo '[block-post-tool-use]' ran, but its result was blocked afterward by the PostToolUse hook.
    
      The hook messages were:
    
      - PreToolUse demo blocked the command. Remove [block-pre-tool-use] to continue.
      - PostToolUse demo blocked the result after execution. Remove [block-post-tool-use] to continue.
    
    
    › for the blocked messages (correctly blocked in this test) did the tool output land back into
      context?
    
    
    • Yeah, from this run:
    
      - PreToolUse block: the command itself did not execute, so no command output landed in context. Only
        the block message did.
      - PostToolUse block: the command did execute, but the actual stdout did not come back into context.
        Only the post-tool block message did.
    
      So the blocked notifications landed in context, but the blocked command payloads themselves did not.
      Nice clean guardrail, aloha.
    ```
  • Extract codex-core-skills crate (#15749)
    ## Summary
    - move skill loading and management into codex-core-skills
    - leave codex-core with the thin integration layer and shared wiring
    
    ## Testing
    - CI
    
    ---------
    
    Co-authored-by: Codex <noreply@openai.com>