## 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
## 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
## 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
## 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
## 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
Preserve the watchdog runtime and prompt behavior on top of the refreshed inbox branch and collapse the branch back to a single commit for easier future restacks.
Co-authored-by: Codex <noreply@openai.com>
## 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
## 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
## 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.
## 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`
## 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::`
## 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
## 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::`
## 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
# External (non-OpenAI) Pull Request Requirements
Before opening this Pull Request, please read the dedicated
"Contributing" markdown file or your PR may be closed:
https://github.com/openai/codex/blob/main/docs/contributing.md
If your PR conforms to our contribution guidelines, replace this text
with a detailed and high quality description of your changes.
Include a link to a bug report or enhancement request.
---------
Co-authored-by: Codex <noreply@openai.com>
Moves Code Mode to a new crate with no dependencies on codex. This
create encodes the code mode semantics that we want for lifetime,
mounting, tool calling.
The model-facing surface is mostly unchanged. `exec` still runs raw
JavaScript, `wait` still resumes or terminates a `cell_id`, nested tools
are still available through `tools.*`, and helpers like `text`, `image`,
`store`, `load`, `notify`, `yield_control`, and `exit` still exist.
The major change is underneath that surface:
- Old code mode was an external Node runtime.
- New code mode is an in-process V8 runtime embedded directly in Rust.
- Old code mode managed cells inside a long-lived Node runner process.
- New code mode manages cells in Rust, with one V8 runtime thread per
active `exec`.
- Old code mode used JSON protocol messages over child stdin/stdout plus
Node worker-thread messages.
- New code mode uses Rust channels and direct V8 callbacks/events.
This PR also fixes the two migration regressions that fell out of that
substrate change:
- `wait { terminate: true }` now waits for the V8 runtime to actually
stop before reporting termination.
- synchronous top-level `exit()` now succeeds again instead of surfacing
as a script error.
---
- `core/src/tools/code_mode/*` is now mostly an adapter layer for the
public `exec` / `wait` tools.
- `code-mode/src/service.rs` owns cell sessions and async control flow
in Rust.
- `code-mode/src/runtime/*.rs` owns the embedded V8 isolate and
JavaScript execution.
- each `exec` spawns a dedicated runtime thread plus a Rust
session-control task.
- helper globals are installed directly into the V8 context instead of
being injected through a source prelude.
- helper modules like `tools.js` and `@openai/code_mode` are synthesized
through V8 module resolution callbacks in Rust.
---
Also added a benchmark for showing the speed of init and use of a code
mode env:
```
$ cargo bench -p codex-code-mode --bench exec_overhead -- --samples 30 --warm-iterations 25 --tool-counts 0,32,128
Finished [`bench` profile [optimized]](https://doc.rust-lang.org/cargo/reference/profiles.html#default-profiles) target(s) in 0.18s
Running benches/exec_overhead.rs (target/release/deps/exec_overhead-008c440d800545ae)
exec_overhead: samples=30, warm_iterations=25, tool_counts=[0, 32, 128]
scenario tools samples warmups iters mean/exec p95/exec rssΔ p50 rssΔ max
cold_exec 0 30 0 1 1.13ms 1.20ms 8.05MiB 8.06MiB
warm_exec 0 30 1 25 473.43us 512.49us 912.00KiB 1.33MiB
cold_exec 32 30 0 1 1.03ms 1.15ms 8.08MiB 8.11MiB
warm_exec 32 30 1 25 509.73us 545.76us 960.00KiB 1.30MiB
cold_exec 128 30 0 1 1.14ms 1.19ms 8.30MiB 8.34MiB
warm_exec 128 30 1 25 575.08us 591.03us 736.00KiB 864.00KiB
memory uses a fresh-process max RSS delta for each scenario
```
---------
Co-authored-by: Codex <noreply@openai.com>
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
- 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>
updated Windows shell/unified_exec tool descriptions:
`exec_command`
```text
Runs a command in a PTY, returning output or a session ID for ongoing interaction.
Windows safety rules:
- Do not compose destructive filesystem commands across shells. Do not enumerate paths in PowerShell and then pass them to `cmd /c`, batch builtins, or another shell for deletion or moving. Use one shell end-to-end, prefer native PowerShell cmdlets such as `Remove-Item` / `Move-Item` with `-LiteralPath`, and avoid string-built shell commands for file operations.
- Before any recursive delete or move on Windows, verify the resolved absolute target paths stay within the intended workspace or explicitly named target directory. Never issue a recursive delete or move against a computed path if the final target has not been checked.
```
`shell`
```text
Runs a Powershell command (Windows) and returns its output. Arguments to `shell` will be passed to CreateProcessW(). Most commands should be prefixed with ["powershell.exe", "-Command"].
Examples of valid command strings:
- ls -a (show hidden): ["powershell.exe", "-Command", "Get-ChildItem -Force"]
- recursive find by name: ["powershell.exe", "-Command", "Get-ChildItem -Recurse -Filter *.py"]
- recursive grep: ["powershell.exe", "-Command", "Get-ChildItem -Path C:\\myrepo -Recurse | Select-String -Pattern 'TODO' -CaseSensitive"]
- ps aux | grep python: ["powershell.exe", "-Command", "Get-Process | Where-Object { $_.ProcessName -like '*python*' }"]
- setting an env var: ["powershell.exe", "-Command", "$env:FOO='bar'; echo $env:FOO"]
- running an inline Python script: ["powershell.exe", "-Command", "@'\nprint('Hello, world!')\n'@ | python -"]
Windows safety rules:
- Do not compose destructive filesystem commands across shells. Do not enumerate paths in PowerShell and then pass them to `cmd /c`, batch builtins, or another shell for deletion or moving. Use one shell end-to-end, prefer native PowerShell cmdlets such as `Remove-Item` / `Move-Item` with `-LiteralPath`, and avoid string-built shell commands for file operations.
- Before any recursive delete or move on Windows, verify the resolved absolute target paths stay within the intended workspace or explicitly named target directory. Never issue a recursive delete or move against a computed path if the final target has not been checked.
```
`shell_command`
```text
Runs a Powershell command (Windows) and returns its output.
Examples of valid command strings:
- ls -a (show hidden): "Get-ChildItem -Force"
- recursive find by name: "Get-ChildItem -Recurse -Filter *.py"
- recursive grep: "Get-ChildItem -Path C:\\myrepo -Recurse | Select-String -Pattern 'TODO' -CaseSensitive"
- ps aux | grep python: "Get-Process | Where-Object { $_.ProcessName -like '*python*' }"
- setting an env var: "$env:FOO='bar'; echo $env:FOO"
- running an inline Python script: "@'\nprint('Hello, world!')\n'@ | python -"
Windows safety rules:
- Do not compose destructive filesystem commands across shells. Do not enumerate paths in PowerShell and then pass them to `cmd /c`, batch builtins, or another shell for deletion or moving. Use one shell end-to-end, prefer native PowerShell cmdlets such as `Remove-Item` / `Move-Item` with `-LiteralPath`, and avoid string-built shell commands for file operations.
- Before any recursive delete or move on Windows, verify the resolved absolute target paths stay within the intended workspace or explicitly named target directory. Never issue a recursive delete or move against a computed path if the final target has not been checked.
```
Add a representation of the agent graph. This is now used for:
* Cascade close agents (when I close a parent, it close the kids)
* Cascade resume (oposite)
Later, this will also be used for post-compaction stuffing of the
context
Direct fix for: https://github.com/openai/codex/issues/14458
Cleanup image semantics in code mode.
`view_image` now returns `{image_url:string, details?: string}`
`image()` now allows both string parameter and `{image_url:string,
details?: string}`
Summary
- document that code mode only exposes `exec` and the renamed `wait`
tool
- update code mode tool spec and descriptions to match the new tool name
- rename tests and helper references from `exec_wait` to `wait`
Testing
- Not run (not requested)
It now supports:
- Connectors that are from installed and enabled plugins that are not
installed yet
- Plugins that are on the allowlist that are not installed yet.