## Why
When MCP tools are deferred behind `tool_search`, Code mode keeps them
callable but omits their individual declarations from the initial `exec`
description. The shared MCP `CallToolResult` types were derived only
from directly rendered tools, so deferring every MCP tool also removed
the common response contract that models need to interpret MCP results.
This restores that contract without undoing the context savings from
deferred tool definitions. This is a follow-up to #29486.
## What changed
- Track deferred Code-mode tool definitions separately from directly
rendered definitions.
- Render the shared MCP type preamble when either direct or deferred MCP
tools are available.
- Keep deferred tool declarations out of the initial prompt.
- Add unit and integration coverage for deferred MCP tools.
## Testing
- `just test -p codex-code-mode-protocol`
- `just test -p codex-core
code_mode_only_guides_all_tools_search_and_calls_deferred_app_tools`
## Summary
- add an `EncodedFrame` type so IPC payloads are serialized and
size-checked before entering bounded queues
- add the V1 `operation/cancel` client-to-host message
- pin the new wire shape with protocol tests
## Why
The process-owned code-mode host needs bounded, pre-encoded outbound
messages and a best-effort cancellation signal. Keeping these wire
primitives in a protocol-only change lets their compatibility contract
be reviewed independently from either endpoint.
## Stack
This is **1 of 4** in the process-owned code-mode session stack. The
next PR targets this branch.
## Validation
- `just test -p codex-code-mode-protocol` — 22 passed
- `just fix -p codex-code-mode-protocol`
- `just fmt`
## Why
The process-owned code mode implementation needs an explicit, bounded
wire contract before either side depends on it. Keeping framing and
message semantics in `codex-code-mode-protocol` gives the client and
sidecar one shared source of truth and makes compatibility failures
detectable during connection setup.
## What changed
- adds a versioned client/host handshake with required and optional
capabilities
- defines operation requests and responses for session lifecycle and
cell control
- defines reverse delegate request, response, cancellation, and
cell-closure messages
- adds a four-byte little-endian length-prefixed JSON codec with a hard
frame cap
- rejects malformed frames, unknown fields, invalid identifiers, and
unsupported protocol states
- locks the wire representation down with explicit JSON round-trip tests
## Testing
- `just test -p codex-code-mode-protocol`
## Stack
Part 1 of 6. Followed by
[#29805](https://github.com/openai/codex/pull/29805).
Remove this unused API. This API is insidious in that it implies that
alive state should be determinable from the caller, and implies that a
preflight should indicate routing. Lets drop this, and handle errors
correctly from a failed session in the future.
## Summary
- add validated protocol-version, capability, and session identifier
types
- define explicit `ClientToHost` and `HostToClient` JSON envelopes for
connection negotiation and session open/close acknowledgements
- reject invalid states and unknown fields during decoding, with
explicit wire-format and round-trip coverage
## Why
This establishes the transport-neutral encoding shape needed to build
and test the new code-mode host incrementally. Cell, tool callback, and
failure-domain messages are intentionally deferred until their actors
and behavior tests establish the required semantics.
This is additive protocol scaffolding and does not change the current
production code-mode implementation.
## Validation
## Summary
- reject HTTP(S) image URLs from the shared code-mode output-image
normalization path
- return a concise model-visible tool error so the model can recover on
its next turn
- apply the targeted rejection to both `image()` and `generatedImage()`
- leave other non-empty image URL values to existing downstream handling
The returned error is:
> Tool call failed: remote image URLs are not supported in tool outputs.
Pass a base64 data URI instead
## Why
Responses Lite cannot lower a remote image URL emitted from a structured
tool output. Rejecting HTTP(S) values in the Codex harness preserves the
tool-call metadata and gives the model a recoverable next turn instead
of invalidating the sample.
## Test coverage
The regression is covered primarily by a `test_codex()` agent
integration test that simulates the Responses API exchange and asserts
the failed model-visible exec output. A supplemental runtime test covers
both `http://` and `https://` inputs across both image output helpers.
## Test plan
- `cd codex-rs && just test -p codex-code-mode`
- `cd codex-rs && just test -p codex-code-mode-protocol`
- `cd codex-rs && just test -p codex-core
code_mode_image_helper_rejects_remote_url`
- `cd codex-rs && just fmt`
- `git diff --check origin/main...HEAD`
Related context: https://github.com/openai/openai/pull/1022346
This is phase 1 of a 4 phase stack:
1. **Add protocol and host crates for new IPC code mode implementation**
2. Create the new standalone binary
3. Create a new IPC `CodeModeSessionProvider` to use new binary
4. Remove v8 from core and only use IPC provider
## Add protocol and host crates for new IPC code mode implementation
Establish a clean process boundary without changing the existing
in-process behavior.
- Add the codex-code-mode-protocol crate for shared session, runtime,
response, and tool-definition types.
- Move protocol-facing code out of the V8-backed implementation.
- Add a buildable codex-code-mode-host crate as the foundation for the
standalone process.
- Keep the existing in-process runtime as the active implementation.