Commit Graph

952 Commits

Author SHA1 Message Date
Channing Conger
7d8906b478 [codex] wire process-owned code mode host into core (#30142)
## Summary

- add the `code_mode_host` feature flag and select
`ProcessOwnedCodeModeSessionProvider` in `CodeModeService` when enabled
- initialize code-mode sessions lazily so a missing host reports a tool
error without failing thread startup
- resolve `codex-code-mode-host` beside the running Codex binary by
default while preserving `CODEX_CODE_MODE_HOST_PATH` as an override
- add unit and end-to-end coverage for host resolution and graceful
missing-host behavior

## Why

This wires the process-owned session client from #30112 into the core
service behind an opt-in rollout gate. Packaged Codex installations can
place the helper in the same `bin` directory as the main executable
without relying on `PATH`, while development and custom installations
can continue to override the helper path.

## Stack

- Depends on #30112
- Base branch: `cconger/process-owned-session-runtime-4-client`

## Validation

Build `codex` and `codex-code-mode-host`
`CODEX_CODE_MODE_HOST_PATH="$PWD/target/debug/codex-code-mode-host"
./target/debug/codex --enable code_mode_host`
2026-06-26 00:23:33 -07:00
Won Park
0d4351c1b8 [codex] allow CCA image generation and web search extensions (#29909)
## Summary

- allow the standalone image-generation and web-search extensions for
the actor-authorized provider shape used by CCA
- preserve builtin `image_generation` and `web_search` for older models
and existing flows
- keep ordinary non-OpenAI providers excluded from both extensions
- remove only the image extension local managed-AuthManager requirement
that CCA cannot satisfy
- share actor-authorization detection through `ModelProviderInfo`
- keep Core tests focused on routing behavior and cover header-shape
edge cases in `model-provider-info`
- add a Responses Lite regression that verifies both
`image_gen.imagegen` and `web.run`

## Why

CCA uses a provider named `local` with `requires_openai_auth: false` and
a non-empty `x-openai-actor-authorization` header. Core accepts that
provider shape, but both extension provider-name gates rejected it;
image generation additionally required a Codex-managed login.

The standalone paths must coexist with existing builtin tools. New
Responses Lite models can receive `image_gen.imagegen` and `web.run`,
while older models continue using builtin tools.

## Impact

This enables both standalone extensions for CCA once installed
downstream, without removing or changing builtin-tool compatibility for
older models.

## Validation

- `just test -p codex-core
responses_lite_exposes_standalone_tools_for_actor_authorized_provider`
- `just test -p codex-core
responses_lite_uses_standalone_web_search_and_image_generation`
- `just test -p codex-core
hosted_tools_follow_provider_auth_model_and_config_gates`
- `just test -p codex-image-generation-extension`
- `just test -p codex-web-search-extension`
- `just test -p codex-model-provider-info`
- `just fmt`
- `git diff --check`
2026-06-25 18:34:35 -07:00
Martin Au-Yeung
ec300bc7bd Expose MCP app identity in app context (#29934)
## Why

MCP tool-call events need to expose trusted app identity and action
metadata directly so v2 clients do not have to infer it from tool names
or resource URIs.

## What changed

- Add optional `appName`, `templateId`, and `actionName` fields to MCP
tool-call `appContext`.
- Populate `appName` and `templateId` from trusted Codex Apps metadata,
and derive `actionName` from the trusted app resource metadata.
- Preserve all three fields through core events, legacy protocol events,
persisted thread history, resume redaction, and app-server v2 responses.
- Document the public `appContext` fields in
`codex-rs/app-server/README.md`.
- Regenerate app-server JSON and TypeScript schemas and add coverage for
serialization, persistence, redaction, and metadata propagation.

## Validation

- `just test -p codex-app-server-protocol mcp_tool_call`
- `just test -p codex-core
mcp_tool_call_item_metadata_only_trusts_codex_apps_identity
mcp_tool_call_item_includes_app_identity`
- `just write-app-server-schema`

---------

Co-authored-by: Martin Au-Yeung <280153141+martinauyeung-oai@users.noreply.github.com>
2026-06-25 18:31:10 -07:00
jif
ee9e0f6387 Pin MCP runtimes to model steps (#30101)
## Why

An MCP refresh can replace the session's current manager while a model
step is still running. The step must execute calls through the same
manager whose tools it advertised.

## Boundary

```text
current session MCP runtime
          |
          | capture once for this model step
          v
StepContext.mcp
  - exact MCP config
  - exact connection manager
  - exact runtime environment context
```

```rust
pub struct McpRuntimeSnapshot {
    config: Arc<McpConfig>,
    manager: Arc<McpConnectionManager>,
    runtime_context: McpRuntimeContext,
}
```

## Example

```text
step A captures runtime A and advertises A's tools
refresh publishes runtime B
step A tool call -> runtime A
next step        -> runtime B
```

Capturing the snapshot is only an `Arc` clone. It does not restart MCPs
or make an RPC.

## What changes

- Captures one MCP runtime in `StepContext`.
- Uses it for tool planning, tool calls, resources, approvals, connector
attribution, and elicitation.
- Publishes replacement runtimes atomically.
- Lets an old runtime live only while an in-flight step or request still
holds its `Arc`.

Most of this diff is mechanical routing from the session-global manager
to `step_context.mcp`; it does not introduce selected-plugin discovery
yet.

## What does not change

- No plugin or extension migration.
- No new MCP cache policy.
- No environment file watching.
- No client sharing between separate managers.

## Stack

1. Extension-owned World State sections.
2. Project executor skills through World State.
3. **This PR:** pin one MCP runtime to each model step.
4. Project selected MCP/app/connector metadata by environment
availability.
5. One end-to-end integration scenario.
2026-06-26 00:53:07 +01:00
Michael Bolin
c65cfeab14 core: expose permission profile to shell tools (#29941)
## tl;dr

Inject a `CODEX_PERMISSION_PROFILE` environment variable with the name
of the current permission profile when invoking a shell tool.

## Why

Shell tool owners may need to launch nested commands under the same
named permission profile, including through `codex sandbox -P PROFILE
--include-managed-config`. Until now, child processes could observe
sandbox and network metadata but could not identify the active named
permission profile.

The `--include-managed-config` flag is essential when a helper
reconstructs the sandbox from a profile name: it ensures the nested
sandbox also loads managed enterprise requirements. Without it, using
the inherited profile could unintentionally create a sandbox that does
not enforce the organization's managed restrictions.

The new environment value is intentionally informational and **must not
be treated as trusted input**. Any process in the ancestry can overwrite
an environment variable, so a consumer that passes this value to `codex
sandbox -P` must first validate it against the profiles that helper is
authorized to use.

## Example Use Case

Suppose an organization provides a trusted `remote-bash` wrapper that
lets Codex run a command on an approved build host. The local shell
command uses the named `:workspace` permission profile:

```toml
default_permissions = ":workspace"
```

The command exposed to the model is a small zsh wrapper. It deliberately
delegates with `exec`, preserving the original arguments and process
environment:

```zsh
#!/usr/bin/env zsh
exec /opt/codex-tools/remote_bash.py "$@"
```

The model invokes the public wrapper, not its Python implementation:

```sh
/opt/codex-tools/remote-bash \
  --host builder.example.com \
  -- printf '%s' 'hello world'
```

Only the inner implementation is authorized to escape the local sandbox:

```starlark
prefix_rule(
    pattern=["/opt/codex-tools/remote_bash.py"],
    decision="allow",
)
```

With zsh-fork, execution begins with `remote-bash` inside the
`:workspace` sandbox. When the wrapper calls `exec`, the exact prefix
rule matches `remote_bash.py`, so that inner script is restarted
unsandboxed. The escalated process inherits:

```text
CODEX_PERMISSION_PROFILE=:workspace
```

Inheritance does not make the value trustworthy. `remote_bash.py`
independently allowlists both the remote host and the permission profile
before using either value. In particular, a forged value such as
`:danger-full-access` is rejected before it can reach `codex sandbox
-P`:

```python
import argparse
import os
import shlex
import sys

ALLOWED_HOSTS = {"builder.example.com"}
ALLOWED_PROFILES = {":workspace"}

parser = argparse.ArgumentParser()
parser.add_argument("--host", required=True)
separator = sys.argv.index("--")
args = parser.parse_args(sys.argv[1:separator])
command = sys.argv[separator + 1:]

if args.host not in ALLOWED_HOSTS:
    parser.error("host is not allowlisted")
if not command:
    parser.error("the remote command must not be empty")

profile = os.environ.get("CODEX_PERMISSION_PROFILE")
if not profile:
    raise SystemExit("CODEX_PERMISSION_PROFILE must not be empty")
if profile not in ALLOWED_PROFILES:
    raise SystemExit("CODEX_PERMISSION_PROFILE is not allowlisted")

remote_command = shlex.join(command)
sandbox_command = shlex.join([
    "codex", "sandbox", "-P", profile,
    "--include-managed-config", "--",
    "bash", "-lc", remote_command,
])
print(shlex.join(["ssh", args.host, sandbox_command]))
```

This builds each command layer as an argument vector and uses
`shlex.join()` at the boundary, rather than interpolating untrusted
shell text. After validation and parsing, the nested command has this
structure:

```text
ssh argv:
  ["ssh", "builder.example.com", SANDBOX_COMMAND]

SANDBOX_COMMAND argv:
  ["codex", "sandbox", "-P", ":workspace",
   "--include-managed-config", "--",
   "bash", "-lc", "printf %s 'hello world'"]

bash -lc payload argv:
  ["printf", "%s", "hello world"]
```

A production implementation could execute that SSH command. The
integration fixture prints it and parses the result back into arguments,
verifying the complete flow:

```text
model invokes outer wrapper
  -> zsh-fork starts wrapper under :workspace
  -> wrapper execs allowlisted Python script
  -> prefix rule restarts Python script unsandboxed
  -> Python script inherits CODEX_PERMISSION_PROFILE=:workspace
  -> Python script verifies :workspace is allowlisted
  -> remote command runs codex sandbox -P :workspace
     with --include-managed-config
  -> nested sandbox honors managed enterprise requirements
```

This gives the trusted helper access to resources outside the local
sandbox—such as SSH credentials—while ensuring that it can select only
an explicitly authorized profile and that work on the remote host
remains subject to the organization's managed requirements.

## What changed

- Inject `CODEX_PERMISSION_PROFILE` after shell environment policy
evaluation so the active profile wins over inherited or configured stale
values.
- Apply the variable to both `shell_command` and unified `exec_command`,
including local, zsh-fork, and remote exec-server paths.
- Remove stale values when the session has no active named profile.
- Preserve the current profile value when loading a shell snapshot so a
parent snapshot cannot restore an older profile.

## Testing

- Added classic-shell integration coverage proving an exact prefix rule
can run a `require_escalated` script outside the `:workspace` sandbox
while preserving `CODEX_PERMISSION_PROFILE=:workspace`.
- Added zsh-fork integration coverage in which the model invokes an
outer zsh wrapper, an inner allowlisted `remote_bash.py` runs
unsandboxed, and its printed SSH command reconstructs the inherited
`:workspace` sandbox with `--include-managed-config` while preserving
every argument after `--`.
- The example helper treats `CODEX_PERMISSION_PROFILE` as untrusted and
validates it against `ALLOWED_PROFILES` before constructing the nested
command.
- Assert that the reconstructed sandbox command includes
`--include-managed-config` so nested use of the inherited profile cannot
bypass managed enterprise requirements.
- Added coverage for overriding and removing stale profile values.
- Verified `shell_command` receives the selected active profile.
- Added shell snapshot coverage using `printenv
CODEX_PERMISSION_PROFILE`.
2026-06-25 19:00:23 +00:00
jif
8f02973d25 Persist selected capability roots and resolve availability per model step (#29856)
## Why

`selectedCapabilityRoots` is durable thread intent: “use this capability
root from environment `worker`.”

The important product assumption is:

> One environment ID always names the same logical executor and stable
contents.

`worker` does not silently change from executor A to an unrelated
executor B. The process-local connection handle for `worker` can still
be replaced while Codex is running, though, for example when
`environment/add` registers a fresh handle for the same logical
environment.

The thread should persist only the stable selection. Each model step
should pair that selection with the exact ready handle captured for that
step.

## The boundary

```text
persisted thread intent
  plugin@1 -> environment "worker"
                |
                | capture the current step
                v
model-step view
  unavailable, or
  plugin@1 + worker's exact captured ready handle
```

The environment ID is the stable identity and cache key. The
`Arc<Environment>` is only a process-local handle retained so consumers
of one model step use the same captured environment. It is never
persisted and it does not imply different environment contents.

## What changes

### Persist the stable selection

Selected roots are written into `SessionMeta` and restored with the
thread. Forked subagents inherit the same selections, including
bounded-history forks.

Only stable data is persisted: root ID, environment ID, and root path.

### Capture readiness together with the exact handle

The environment snapshot records:

```rust
environment_id -> Some(Arc<Environment>) // ready in this step
environment_id -> None                   // still starting in this step
```

This prevents readiness and execution from coming from different
registry snapshots.

For example:

```text
step snapshot: worker -> handle A, ready
environment/add: worker -> fresh handle B for the same logical environment
current step: plugin@1 still uses captured handle A
```

Without carrying handle A in the snapshot, the resolver could combine “A
was ready” with handle B and treat B as ready before it had finished
starting.

This does not change cache invalidation. Stable capability metadata
remains identified by environment ID and capability root. Replacing a
process-local handle under the same stable environment ID does not
invalidate or rediscover that metadata.

### Resolve availability per model step

- A ready captured environment produces resolved roots using its
captured handle.
- A starting, missing, or failed environment is omitted from that step.
- A selected lazy environment that is outside the turn's captured
environment set is asked to start, and a later step can observe it as
ready.
- No capability files are scanned here.

Transient transport disconnects remain the remote client's reconnect
concern. This PR models initial attachment/readiness; it does not add
live socket-connectivity state.

## Example

```text
thread selection: plugin@1 -> environment "worker"

step 1: worker is starting -> plugin@1 unavailable
step 2: worker is ready    -> plugin@1 resolves through worker's captured handle
step 3: fresh local handle -> current step remains pinned; a later step captures its own view
```

Temporary unavailability does not discard the durable selection. Later
PRs can retain stable metadata caches while projecting only currently
available capabilities into model-visible World State.

## Compatibility

The app-server request shape does not change. Older rollouts without
`selected_capability_roots` deserialize to an empty list.

## Stack

1. **This PR:** persist stable selected roots and resolve them through
an exact model-step handle.
2. #29960: cache stable skill metadata and project available skills into
World State.
3. #29946: cache stable plugin declarations and manage the separate live
MCP runtime.
2026-06-25 17:49:43 +00:00
sayan-oai
f2f80ef442 core: make AGENTS.md react to environment changes (#29810)
## Why

With deferred executors, a turn can begin before a remote environment
attaches. AGENTS.md discovery previously ran only during session setup,
so instructions from a later environment never reached the model or the
session instruction sources.

WorldState persistence has now landed, so this uses the durable
model-visible baseline directly instead of carrying a temporary
resume/fork compatibility path.

## What

- Add an `AgentsMdManager` in `SessionServices` to own host
instructions, loaded state, and refresh caching.
- When `DeferredExecutor` is enabled, refresh AGENTS.md when attached
environment selections change and freeze the result in the corresponding
`StepContext`.
- Represent AGENTS.md as a persisted WorldState section for every
session, with bounded initial, replacement, and removal updates.
- Remove duplicate AGENTS.md state and rendering from
`SessionConfiguration` and `TurnContext`.
- Build initial context, per-request updates, and compaction context
from the same step-scoped value.
- On resume and fork, compare current instructions with the restored
WorldState baseline and inject a replacement exactly once when they
differ.

Builds on #29833, #29835, and #29837.

## Tests

- Covers a remote environment becoming ready mid-turn, with AGENTS.md
appearing on the next request exactly once and updating canonical
instruction sources.
- Covers full, unchanged, replaced, and removed AGENTS.md WorldState
rendering.
- Covers changed instructions across cold resume and fork without
duplicate reinjection.
- Covers remote-v2 compaction retaining creation-time instructions in
the live session and cold resume appending one replacement when the
source changed.
- Ran focused `codex-core` AGENTS.md, WorldState, and context-update
test suites.
2026-06-24 22:57:42 -07:00
rka-oai
f66d793a2d [codex] route sleep through time providers (#29973)
## Summary

- add a cancellable sleep operation to `TimeProvider`
- route `clock.sleep` through the configured provider
- extend the supported sleep duration to 12 hours
- complete the sleep turn item before propagating provider failures

## Why

This isolates the core clock abstraction needed by external clock
integrations. Existing system and app-server behavior remains wall-clock
based in this PR; the stacked follow-up supplies app-server sleeps from
an external clock.
2026-06-24 22:17:43 -07:00
Shijie Rao
df1199fddb [codex] Add Ultra reasoning effort (#29899)
## Why

Ultra should be one user-facing reasoning selection for work that
benefits from both maximum reasoning and proactive multi-agent
delegation. Without it, clients must coordinate maximum reasoning with
the experimental `multiAgentMode` setting, even though the inference
backend still expects its existing `max` effort value.

This change makes reasoning effort the source of truth: clients select
`ultra`, core derives proactive multi-agent behavior when the turn is
eligible for multi-agent V2, and inference requests continue to use the
backend-compatible `max` value.

## What changed

- Add `ultra` as a first-class reasoning effort and preserve
model-catalog ordering when exposing it to clients.
- Convert `ultra` to `max` at the inference request boundary, including
Responses HTTP/WebSocket requests, startup prewarm, compaction, and
memory summarization.
- Derive effective multi-agent mode per turn from effective reasoning
effort:
  - eligible multi-agent V2 + `ultra` → `proactive`
  - eligible multi-agent V2 + any other effort → `explicitRequestOnly`
- V1 or otherwise ineligible sessions → no multi-agent mode instruction
- Keep the derived effective mode in turn context history so successive
turns can emit a developer-message update only when the effective mode
changes.
- Remove selected multi-agent mode from core session configuration, turn
construction, thread settings, resume/fork restoration, and subagent
spawn plumbing. Subagents inherit reasoning effort and derive their own
effective mode.
- Retain the experimental app-server `multiAgentMode` fields for wire
compatibility while marking them deprecated. Request values are accepted
but ignored; compatibility response fields report `explicitRequestOnly`.
- Display Ultra in the TUI using the order supplied by `model/list`.

## Validation

- `just test -p codex-core ultra_reasoning_uses_max_for_requests`
- `just test -p codex-tui model_reasoning_selection_popup`
2026-06-24 20:13:52 -07:00
rka-oai
35f5d02464 [codex] nest sleep config under current time reminder (#29910)
## Summary

- move sleep tool enablement from top-level `[features].sleep_tool` to
`[features.current_time_reminder].sleep_tool`
- remove the standalone `Feature::SleepTool` flag and gate `clock.sleep`
from resolved current-time configuration
- update config schema, config-lock materialization, and existing sleep
coverage

Stacked on #29907.
2026-06-24 17:49:00 -07:00
rka-oai
800529218a [codex] namespace sleep under clock (#29907)
## Summary

- expose the interruptible sleep tool as `clock.sleep` instead of
top-level `sleep`
- keep `clock.curr_time` and `clock.sleep` in the same model-visible
namespace when both features are enabled
- update existing core and app-server integration coverage to issue
namespaced sleep calls

## Why

Sleep is a clock operation. Grouping it with `clock.curr_time` gives the
model a more coherent tool surface without changing the sleep feature
gate or runtime behavior.

## Validation

- `just test -p codex-core sleep_tool_follows_feature_gate`
- `just test -p codex-core any_new_input_interrupts_sleep`
- `just test -p codex-app-server
sleep_emits_started_and_completed_items`
2026-06-24 17:17:28 -07:00
Alex Daley
24423f5712 [plugins] Track plugin install requests by ID (#29684)
Summary
- Emit `codex_plugin_install_requested` when a validated plugin install
request is made, before the user accepts or declines the elicitation.
- Record the exact model-visible plugin ID, remote plugin ID, required
connector IDs, stable suggestion ID, and `endpoint_recommendation` vs
`legacy_discovery` source.
- Keep `suggest_reason` out of telemetry and leave connector-only
install requests unchanged.

Rollout
- Backend/schema dependency:
https://github.com/openai/openai/pull/1065270
- Land the backend PR before this producer starts sending the event.

Validation
- `just test -p codex-analytics` (83 passed)
- `just test -p codex-core request_plugin_install` (17 passed)
- `just fix -p codex-analytics`
- `just fix -p codex-core`
- `just fmt`
- `git diff --check`
2026-06-24 21:29:11 +00:00
Adam Perry @ OpenAI
df1ee09ec5 mcp: keep elicitation requests below app wire types (#29724)
## Why

Core and tools need to request MCP elicitation without constructing
app-server wire payloads. The request should remain a neutral protocol
concept until app-server serializes it for a client.

## What changed

- Switched core and tools to
`codex_protocol::approvals::ElicitationRequest`.
- Derived turn and server context inside core instead of carrying
app-server request types through lower layers.
- Kept the app-server payload unchanged through an explicit boundary
conversion.
- Removed the remaining production app-server-protocol dependency from
tools.

## Stack

This is PR 5 of 6, stacked on [PR
#29723](https://github.com/openai/codex/pull/29723). Review only the
delta from `codex/split-connector-metadata-types`. Next: [PR
#29725](https://github.com/openai/codex/pull/29725).

## Validation

- `codex-core` MCP coverage passed: 87 tests.
- Tools elicitation and app-server round-trip coverage passed.
2026-06-24 20:53:27 +00:00
Drew
a33ad93996 [apps] Thread structured icon assets through app list (#29889)
## Summary

- Add `iconAssets` and `iconDarkAssets` to the app-list protocol.
- Preserve structured icons through directory merging and the connector,
app-
  server, and TUI boundaries.
- Keep legacy logo URLs unchanged as compatibility fallbacks.
- Update generated protocol schemas and TypeScript types.
2026-06-24 13:25:44 -07:00
Tom
ece1dfece0 [codex] Inject agent graph store into ThreadManager (#29736)
Pick up the AgentGraphStore migration.

- Inject an explicit optional agent graph store into `ThreadManager` 
- Move all calls to spawn, close, recursive resume, and
subtree/archive/delete/feedback traversal through it
- Keep using  `LocalAgentGraphStore` when SQLite is available

This required some changes to the interface to deal with futures:

- The interface now matches `ThreadStore`'s object-safe pattern by
returning a boxed `AgentGraphStoreFuture` directly, allowing
`ThreadManager` to hold `Arc<dyn AgentGraphStore>`

*Slight behavior change!* Unfiltered subtree enumeration now performs a
single all-status breadth-first traversal, so a closed grandchild
beneath an open edge is included; the previous Open-then-Closed
traversals could not cross mixed-status paths and silently omitted it.
2026-06-24 13:24:10 -07:00
rhan-oai
2a320fedb5 [codex] Remove auto-compaction opt-out (#29815)
## Summary

- remove the default-on `auto_compaction` feature flag and generated
config schema entries
- restore unconditional pre-turn, model-switch/hash, and mid-turn
automatic compaction
- expose `new_context` whenever token-budget tooling is enabled
- remove the disabled-auto-compaction integration coverage introduced by
#28260

## Motivation

Roll back the internal auto-compaction escape hatch added in #28260.
Automatic compaction should no longer be suppressible with `--disable
auto_compaction`; existing manual `/compact` behavior remains unchanged.

## Testing

- `just write-config-schema`
- `just test -p codex-features` — 53 passed
- `just test -p codex-core 'suite::compact::'` — 36 passed
- `just test -p codex-core
suite::token_budget::new_context_tool_starts_new_window_before_follow_up`
— 1 passed
- `just fix -p codex-core -p codex-features`
- `just fmt`
- `just test -p codex-core` — 2,778 passed, 59 failed, 16 skipped;
failures were outside the changed compaction paths and were dominated by
missing first-party test binaries and shell-snapshot timeouts
2026-06-24 00:15:04 -07:00
Adam Perry @ OpenAI
e639e8c4bd connectors: own app metadata types (#29723)
## Why

Connector metadata is consumed by connector discovery, ChatGPT
integration, core, and TUI code. Treating app-server's wire DTO as the
shared domain model reverses the intended dependency direction.

## What changed

- Added connector-owned app branding, review, screenshot, metadata, and
info types.
- Added explicit conversions in app-server and TUI while preserving
app-server's wire payloads.
- Removed production app-server-protocol dependencies from connectors
and ChatGPT connector code.

## Stack

This is PR 4 of 6, stacked on [PR
#29722](https://github.com/openai/codex/pull/29722). Review only the
delta from `codex/split-config-layer-types`. Next: [PR
#29724](https://github.com/openai/codex/pull/29724).

## Validation

- Connector and tools coverage passed.
- App-server app-list coverage passed: 13 tests.
2026-06-23 22:08:23 -07:00
xl-openai
4fe02f4fcf [plugins] Enforce marketplace source admission requirements (#29753)
## Why

Managed marketplace source requirements only become effective when every
local marketplace mutation path applies the same admission decision.
This change centralizes that decision so CLI, app-server, and
external-agent migration flows cannot add, install from, or refresh a
disallowed source.

## What changed

- Match exact normalized Git repository URLs with an optional exact
`ref`.
- Match Git hosts with managed regular expressions.
- Match local marketplaces by exact absolute path.
- Preserve the expected path/name boundary for managed OpenAI
marketplaces.
- Enforce source admission during marketplace add, plugin install, and
configured Git marketplace upgrade.
- Continue upgrading independent marketplaces when one source is
rejected and return a per-marketplace error.
- Load the effective requirements stack at CLI, app-server, and
external-agent migration entry points.

This PR does not filter already configured marketplaces at runtime; that
remains in draft follow-up #29691.

## Stack

This is PR 2 of 3 and is based on #29690, which introduces the
requirements data shape and merge behavior.

## Test plan

- Source matcher coverage for Git URL/ref, host-pattern, local-path, and
managed marketplace cases.
- Marketplace add and plugin install coverage for allowed and rejected
sources.
- Marketplace upgrade coverage for rejection and per-marketplace
continuation.
2026-06-23 20:13:11 -07:00
Won Park
61f5a84930 Let image generation extension hosts control output persistence (#29711)
## Why

Some extension hosts need generated images returned without writing them
to the local filesystem or giving the model a local path.

## What changed

**tl;dr**: we now conduct all extension operations in the image gen
extension

- Let hosts provide an optional image save root when installing the
extension.
- Save images and return path hints only when a save root is configured.
- Return image data without saving or adding a path hint when no save
root is configured.
- Preserve the extension-provided `saved_path` instead of persisting
extension images again in core.
- Leave built-in image generation unchanged.

## Validation

- `just test -p codex-image-generation-extension`
- `just test -p codex-app-server
standalone_image_generation_returns_saved_path_hint_to_model`
- `just test -p codex-core
extension_tool_uses_granted_turn_permissions_without_local_persistence`
- `just test -p codex-core tools::handlers::extension_tools::tests`
- tested on CODEX CLI on both save_root: CODEX_HOME and None 
- tested on CODEX APP on both as well
2026-06-23 18:51:49 -07:00
sayan-oai
61ff4d087e core: add wait_for_environment for starting environments (#29745)
## Why

With `DeferredExecutor`, a sampling request can begin while an
environment is still starting. The model can see that pending state, but
needs a way to wait for the environment within the same turn before
continuing.

Environment startup is owned by Core, so the wait tool should use the
same request-frozen `StepContext` that advertised the starting
environment. This keeps tool registration and execution tied to the
exact startup operation the model saw, even if live thread state later
changes.

Supersedes #29735.

## What

- register `wait_for_environment` when the current `StepContext`
contains starting environments
- wait on the selected `StartingTurnEnvironment` shared resolution and
return a bounded ready or failed result
- rebuild the next request normally, removing the wait tool and exposing
ready environment tools, or reporting the environment as unavailable
after failure

## Testing

- `just test -p codex-core deferred_executor_`
- verifies the wait tool is replaced by environment-backed tools after
startup
- verifies startup failure removes both the wait tool and unavailable
environment tools while notifying the model
2026-06-24 00:35:34 +00:00
Andrey Mishchenko
3b4186986f Update new_context_window instructions (#29739) 2026-06-23 16:52:40 -07:00
Michael Bolin
77e7ce1374 fix: scope context remaining to body window (#29665)
## Why

With `model_auto_compact_token_limit_scope = "body_after_prefix"`, the
persistent prefix should not count against the active body window.
`get_context_remaining` and the token-budget reminder should report the
same usable body-after-prefix window that auto-compaction uses, rather
than the total token count since the session began.

This is stacked on #29664 so the mechanical move from `turn.rs` is
isolated from the behavior fix.

## What

- Extends `ContextWindowTokenStatus` with `context_remaining_tokens`.
- Updates `get_context_remaining` to use the shared context-window
accounting.
- Adds integration coverage for body-after-prefix reminder timing and
`get_context_remaining` output.

## Testing

- `just test -p codex-core body_after_prefix_window`
- `just test -p codex-core auto_compact_body_after_prefix`
- `just fix -p codex-core`
2026-06-23 23:08:54 +00:00
Channing Conger
7b40e3523f code-mode: Rename codex_code_mode::CodeModeService (#29716)
Mechanical rename of CodeModeService => InProcessCodeModeSession

This already implements a CodeModeSession as its prime interface to
Core. The name was vestigial _and_ confusing af when embedded inside
core::tools::code_mode::CodeModeService
2026-06-23 14:17:51 -07:00
sayan-oai
4cc6a4bab5 core: use current step environments for tools (#29547)
## Why

With deferred executors, an environment can become ready between two
sampling requests in the same turn. The model-visible environment
update, advertised tools, and eventual tool execution must all describe
the same request-time view.

Otherwise, a request built while only environment B is ready can
advertise a tool without an `environment_id`; if higher-priority
environment A becomes ready before execution, that call could silently
run in A instead.

This PR is stacked on #29527.

## Design

`run_turn` captures one `Arc<StepContext>` at each sampling-request
boundary. That step owns the request's `TurnContext` and environment
snapshot.

- World-state environment updates and tool planning borrow that same
step.
- `ToolCallRuntime` retains the `Arc` while asynchronous tool calls
execute.
- `ToolInvocation` carries the step to handlers; its temporary `turn`
compatibility field is derived from the same object.
- `ToolRouter` does not retain `StepContext`; it only uses it while
constructing the request's tool set.
- With `DeferredExecutor` disabled, step capture keeps using the
environments frozen at turn start.

Simply: every sampling request gets one consistent picture of its
environments, from what the model sees through where its tool calls run.

## What changed

- Build environment-dependent tool specs from the current request's
`StepContext`.
- Use that same step for unified exec, legacy shell, `apply_patch`,
`view_image`, and `request_permissions` execution.
- Hide environment-backed tools, including `request_permissions`, while
no environment is attached.
- Resolve legacy shell paths and metadata from the selected step
environment instead of the stale turn-start environment.
- Capture explicit steps at non-turn-loop boundaries such as compaction,
prompt debug, and startup prewarm.
- Reconcile prompt-debug history from the same step used to build its
tools.

## Follow-up

- Bind yielded code-mode cells to the tool runtime that created them, so
nested calls made after yielding continue to use the originating
request's `StepContext`.

## Test plan

- `just test -p codex-core
deferred_executor_updates_context_and_tools_after_startup`
- `just test -p codex-core
environment_count_controls_environment_backed_tools`
- `just test -p codex-core
build_prompt_input_includes_context_and_user_message`
2026-06-23 20:21:13 +00:00
Adam Perry @ OpenAI
510bce9927 core: resolve view_image paths in selected environment (#29526)
## Why

view_image needs to support foreign OS remote executors.

## What

- resolve image paths against the selected environment as `PathUri` and
read them through that environment's filesystem
- keep app-server's public path field wire-compatible as
`LegacyAppPathString`, with purpose-specific UI rendering
- cover relative and absolute target-native paths in the core
integration test and run the full `view_image` suite under wine-exec
without skips
2026-06-23 19:52:37 +00:00
richardopenai
c660e2b644 [codex] allow image generation with provider auth (#29513)
## Summary

- allow the native Responses API `image_generation` tool when the active
provider carries CCA's non-empty `x-openai-actor-authorization` header
- preserve the Codex-managed ChatGPT auth path, scoped to providers that
actually require OpenAI auth
- keep generic custom providers excluded, including when unrelated
ChatGPT credentials are cached
- retain the existing feature, provider-capability, and
image-input-modality gates

## Why

CCA authenticates its inference requests through the active provider's
`x-openai-actor-authorization` and `ChatGPT-Account-ID` headers, so it
does not have a Codex-managed login session. The previous gate therefore
hid the native hosted image-generation tool despite an authenticated
codex-backend path.

This change is intentionally limited to the native hosted tool. It adds
no extension, MCP, plugin-service, session-source, token plumbing, or
new provider configuration surface.

## Tests

- `cargo test -p codex-core
hosted_tools_follow_provider_auth_model_and_config_gates`
- `cargo fmt --all -- --check`
- `git diff --check origin/main`
2026-06-23 12:40:54 -07:00
Dylan Hurd
2cf2a6a844 chore(core) rm AskForApproval::OnFailure (#28418)
## Summary
Deletes the OnFailure variant of the `AskForApproval` enum. This option
has been deprecated since #11631.

## Testing
- [x] Tests pass
2026-06-23 12:13:54 -07:00
jif
e476fc16ce Prepare managed network sandbox context (#29456)
## Why

Managed network configures commands to use local HTTP and SOCKS proxies.
For commands delegated to the exec server, the proxy environment and the
sandbox policy were prepared separately. On macOS, that meant a command
could receive `HTTPS_PROXY=http://127.0.0.1:43123` while Seatbelt still
denied access to port `43123`.

## What changed

`NetworkProxy` now prepares the command environment and sandbox context
together from the same runtime snapshot:

```text
Prepared managed network
├── command environment: HTTPS_PROXY=http://127.0.0.1:43123
└── sandbox context: allow outbound to 127.0.0.1:43123
```

That context travels with remote exec requests. The exec server
preserves the managed proxy and CA environment, and macOS Seatbelt
allows only the prepared loopback proxy ports without enabling broad
network access or local binding.

The protocol field is optional and the existing enforcement flag remains
in place, preserving compatibility with callers that do not send the new
context.
2026-06-23 20:07:09 +01:00
jif
49614a0391 Namespace multi-agent v2 tools under collaboration (#29067)
## Summary

Multi-agent v2 tools now use the fixed `collaboration` namespace when
namespace tools are available. This keeps the model-visible hint and the
actual tool surface aligned around `functions.collaboration.*`, without
exposing an unshipped namespace knob to users.

The PR also removes the old `features.multi_agent_v2.tool_namespace`
config/schema surface, updates the MAv2 test fixtures for namespaced
calls, and fixes stale `TurnContext.features` references that were
breaking `codex-core` builds.

## Changes

- Expose MAv2 tools under `collaboration` instead of relying on a
configurable namespace.
- Remove `tool_namespace` from MAv2 TOML config, resolved config,
validation, schema, and tests.
- Update tool-planning and integration fixtures to assert or emit
namespaced MAv2 tool calls.
- Read feature state through `TurnContext.config.features` in the
multi-agent mode context paths.

## Testing

- `just write-config-schema`
- `just test -p codex-features`
2026-06-23 14:15:20 +02:00
Adam Perry @ OpenAI
11fab432be path-uri: clarify host-native path conversion (#29501)
## Why

Downstream refactors are producing confusing code with this
functionality having a very generic name. Encoding the specific
conversion approach in the method name makes it clearer.

## What

Rename `PathUri::from_path` to `PathUri::from_host_native_path` and
update its Rust call sites.
2026-06-23 00:02:33 +00:00
sayan-oai
c53b1dae09 [codex] Use tool search for MCP tools by default (#29486)
## Why

MCP tools were only placed behind `tool_search` when a feature flag was
enabled or when there were at least 100 tools. That made the model's
tool flow depend on both rollout configuration and the number of
installed tools.

The searched-tool flow is now the intended behavior. Making it
unconditional when the model and provider support it gives every
supported setup the same behavior and lets us retire the feature flag
safely.

## What changed

- Defer all effective MCP tools when `tool_search` and namespaced tools
are supported.
- Keep exposing MCP tools directly when search cannot be used, so older
or unsupported model/provider combinations still work.
- Mark `tool_search_always_defer_mcp_tools` as removed and ignore old
configured values.
- Keep plugin filtering, app-only filtering, file handling, and MCP
calls working through the searched-tool flow.

## Why many tests changed

Many tests used to act as if the model could see MCP tools in its first
request and call them immediately. That is no longer the real flow: the
model first receives `tool_search`, searches for a tool, receives the
matching MCP tool, and then calls it in the next request.

The tests therefore needed an extra search step, and checks for tool
names, descriptions, and input fields had to move from the first request
to the search result. These are not separate product changes; they make
the tests follow what the model will actually see after this change. The
plugin tests still check which tools are allowed and where they came
from, the file tests still check upload fields and behavior, and the MCP
round-trip test still checks a successful call from start to finish.

## Tests

- `just test -p codex-features`
- Focused `codex-core` tests for MCP exposure and tool planning
- `just test -p codex-core explicit_plugin_mentions`
- `just test -p codex-core stdio_server_round_trip`
- Focused `codex-core` tests for tool search, app-only tools, and MCP
file uploads
2026-06-22 16:45:23 -07:00
Owen Lin
4a82ecc3c9 feat(core): store turn_id on ResponseItem metadata (#28360)
## Description

This PR is a followup to https://github.com/openai/codex/pull/28355 and
starts assigning `internal_chat_message_metadata_passthrough.turn_id` to
durable Responses API items created during a turn.

The goal is that those items keep the `turn_id` that introduced them
when Codex resends stateless HTTP context, reconstructs history for
resume/fork paths, or reuses websocket response state.

## What changed

- Set `internal_chat_message_metadata_passthrough.turn_id` when missing
as response items enter durable history, initial/replacement history,
inter-agent communication history, and local compaction summaries.
- Preserve existing item turn IDs instead of overwriting them during
persistence, resume reconstruction, compaction, forked history, and
websocket incremental reuse.
- Keep `compaction_trigger` fieldless because it is a request control,
not a durable response item.
- Update focused history/request assertions and fixtures for stateless
requests, websocket incrementals, compaction, thread injection, prompt
debug, and related CI coverage.
2026-06-22 16:45:14 -07:00
Owen Lin
5b95745eae core: rename metadata -> internal_chat_message_metadata_passthrough (#28968)
## Description
This PR cuts Codex over from generic `ResponseItem.metadata` (introduced
here: https://github.com/openai/codex/pull/28355) to
`ResponseItem.internal_chat_message_metadata_passthrough`, which is the
blessed path and has strongly-typed keys.

For now we have to drop this MAv2 usage of `metadata`:
https://github.com/openai/codex/pull/28561 until we figure out where
that should live.
2026-06-22 11:11:25 -07:00
rka-oai
e79d72d75d remove flag for image preparation (#29429)
## What

- make Fjord's centralized response-item image preparation unconditional
for new and resumed history
- have local user images and `view_image` outputs always defer decoding
and resizing to that path
- retain `resize_all_images` as an ignored, removed compatibility key
for released clients
- delete the flag-off producer paths and obsolete policy-specific tests

## Why

Centralized preparation is now the intended image path. Keeping the
runtime feature checks also kept two image-processing implementations
alive and allowed client config to select the legacy behavior.

This is a clean replacement for #28975, rebuilt from the latest `main`.

## How

`prepare_response_items` now runs whenever items enter history and
whenever persisted history is reconstructed. Producers emit deferred
image data, so malformed images become the existing model-visible
placeholder instead of failing the session at the producer.

## Test plan

- `just fmt`
- `just fix -p codex-core -p codex-features`
- `just test -p codex-features` — 52 passed
- focused affected `codex-core` set — 20 passed
- `just test -p codex-core handle_accepts_explicit_high_detail` — 1
passed
- full `just test -p codex-core` attempt — 2,723 passed; 88 unrelated
environment failures from read-only `~/.codex` SQLite state and
unavailable integration helper binaries
2026-06-22 10:05:11 -07:00
jif
9c3b10e5d4 Apply sandbox intent inside remote exec servers (#29113)
## Why

PR #29108 lets the orchestrator send sandbox intent with `process/start`
without wrapping the command for its own operating system.

This PR completes that boundary by making the executor interpret and
enforce the intent using its own filesystem paths and sandbox
implementation.

For example, a macOS TUI targeting a Linux devbox sends `/bin/bash -lc
pwd`. The Linux executor turns that into its own `codex-linux-sandbox
... /bin/bash -lc pwd` launch.

## What changes

- Keep `process/start` unchanged when no sandbox intent is present.
- Convert sandbox `PathUri` values into native paths on the executor.
- Bind symbolic `:workspace_roots` permissions to the executor's native
sandbox cwd.
- Select the sandbox implementation on the executor and wrap the
original command immediately before spawning it.
- Reject sandbox-required execution before spawning when the executor
cannot enforce the intent.
- Pass exec-server runtime paths into process creation so Linux can
locate `codex-linux-sandbox`.

The boundary is therefore:

```text
orchestrator                         executor
original argv + sandbox intent  ->  select and enforce local sandbox
```

This PR intentionally treats a denied remote command as an ordinary
command failure. Draft follow-up #29424 carries a semantic
`sandboxDenied` result back to unified exec for the existing approval
and retry flow.

## Platform scope

Linux and macOS use their existing direct-spawn sandbox transforms.

Windows sandboxed remote process launch is intentionally unsupported in
this PR. The current Windows direct-spawn wrapper does not correctly
preserve arbitrary argv, TTY behavior, or pass the full child
environment out of band. The executor rejects the request instead of
running it incorrectly or unsandboxed.

## Known follow-ups

- The transported permission profile can still contain
orchestrator-materialized helper or explicit paths. A `TODO(jif)` marks
where the executor boundary should receive pre-host-materialization
permission intent.
- The sandbox wrapper currently replaces a requested custom inner
`arg0`. A `TODO(jif)` marks where this must be preserved or rejected
explicitly.
- Draft PR #29424 contains the deferred sandbox-denial classification
and approval/retry behavior.

## Rollout assumption

This executor-sandbox stack is unreleased and its client and executor
are expected to move together. This PR does not add mixed-version
negotiation with older exec servers.
2026-06-22 12:45:37 +02:00
jif
c03742ca0a Simplify multi-agent mode controls (#29324)
## Why

Multi-agent delegation policy was split across `multiAgentMode`,
`features.multi_agent_mode`, and `usage_hint_enabled`. These controls
could disagree: a requested mode could be downgraded by the feature
flag, and disabling usage hints also disabled mode instructions.

Some clients also need multi-agent tools without adding
delegation-policy text to model context. The previous two-mode API could
not express that directly.

## What changed

`multiAgentMode` is now the only live delegation-policy control:

| Mode | Behavior |
| --- | --- |
| `none` | Keep multi-agent tools available without adding mode
instructions. |
| `explicitRequestOnly` | Only delegate after an explicit user request.
|
| `proactive` | Delegate when parallel work materially improves speed or
quality. |

- new threads default to `explicitRequestOnly`; omitting the mode on
later turns keeps the current value
- thread start, resume, fork, and settings responses always report the
concrete current mode instead of `null`
- mode selection remains sticky across turns and resume
- usage-hint text no longer controls whether mode instructions apply
- `features.multi_agent_mode` and `usage_hint_enabled` remain accepted
as ignored compatibility settings so existing configs continue to load
- app-server documentation and generated schemas describe the three-mode
API

## Tests

- `just test -p codex-core multi_agent_mode`
- `just test -p codex-core multi_agent_v2_config_from_feature_table`
- `just test -p codex-core spawn_agent_description`
- `just test -p codex-features`
- `just test -p codex-app-server-protocol`
- `just test -p codex-app-server multi_agent_mode`
2026-06-22 10:05:36 +02:00
rhan-oai
b21f0e7a98 [codex] Add internal auto-compaction opt-out (#28260)
## Summary

- add a default-on `auto_compaction` feature flag as an internal escape
hatch
- skip pre-turn, model-switch/hash, and mid-turn automatic compaction
when the flag is disabled
- preserve manual `/compact` behavior and surface the existing
context-window error when the provider runs out of room
- add integration coverage for disabled pre-turn and mid-turn compaction

## Motivation

Long-running SPO optimization rollouts need the option to preserve their
full context and fail on context exhaustion instead of entering another
compaction window. This deliberately uses the existing feature-flag
mechanism rather than adding a dedicated public config or app-server
API.

Disable it with:

```sh
codex --disable auto_compaction
```

## Testing

- `just test -p codex-features` — 51 passed
- `just test -p codex-core auto_compaction_feature_disabled` — 2 passed
- `just fix -p codex-core -p codex-features`
- `just write-config-schema`
- `just test -p codex-core` — the new compaction tests passed; the
overall local run had 54 unrelated environment failures, primarily
missing first-party test binaries and shell-snapshot timeouts
2026-06-21 20:11:50 -07:00
jif
bd2968a4db Carry sandbox intent to remote exec servers (#29108)
## What changed

PR #29099 stopped sending the orchestrator's concrete sandbox wrapper to
a remote exec-server. Remote commands now arrive as plain native argv.

This PR adds the next piece: Codex also sends portable sandbox intent
next to that plain argv.

For a remote unified-exec command, the request can now include:

- the canonical permission profile before local workspace-root
materialization
- the sandbox cwd and workspace roots as `PathUri` values
- Windows sandbox settings
- the legacy Landlock setting
- whether managed networking must be enforced

The important part is that symbolic entries such as `:workspace_roots`
stay symbolic while crossing the boundary. The executor can then bind
them to its own workspace-root paths instead of receiving
orchestrator-local absolute paths.

The data travels through `ExecRequest` into `ExecParams`. Older
exec-servers can still deserialize requests because the new fields have
defaults.

## Why

The orchestrator should not decide how another machine implements
sandboxing.

For example:

- a local macOS Codex would normally build a Seatbelt command
- a remote Linux executor needs a Linux sandbox command instead

The orchestrator now sends the plain command plus the policy it intended
to enforce. A later PR can let the exec-server choose and build the
correct sandbox for its own operating system.

## Important detail

This keeps the portable intent separate from the local `SandboxType`.

`SandboxType::None` is ambiguous:

- it can mean the command was explicitly approved to run without a
sandbox
- it can also mean the orchestrator host has no concrete sandbox
implementation available

Those cases are different for remote execution. This PR adds
`sandbox_requested` so an executor can still receive sandbox intent when
the orchestrator cannot build a local wrapper. Explicit unsandboxed
retries still send no sandbox context.

## Behavior today

This PR only transports the intent. The exec-server accepts the new
fields but does not apply them yet.

Remote commands therefore remain unsandboxed after this PR, just as they
are after PR #29099.

## Follow-up

The next PR will make exec-server read this portable intent, bind
symbolic workspace permissions to executor-native roots, choose the
sandbox for its own operating system, build the wrapper locally, and
then spawn the command.
2026-06-21 12:33:21 +02:00
jif
04483f4ce5 Keep remote exec commands native to the executor (#29099)
## Summary

- Remote unified-exec now sends the original command argv to exec-server
instead of materializing the orchestrator's sandbox wrapper first.
- Local unified-exec keeps the existing sandbox path unchanged.
- Add a focused regression test for a macOS-selected sandbox producing
plain remote argv.

Before:

    macOS orchestrator -> /usr/bin/sandbox-exec ... -> Linux exec-server

After:

    macOS orchestrator -> /bin/bash -lc pwd -> Linux exec-server

This is intentionally only the first cleanup step. Remote unified-exec
commands are sent without a process sandbox until the targeted
follow-ups below land. For the macOS-to-Linux path this is not a
practical regression: the old sandboxed attempt failed before process
launch because the Linux executor could not spawn macOS sandbox paths.

## Targeted follow-ups

1. Carry sandbox intent separately from argv.
   - Add an optional sandbox field to exec-server process params.
- Reuse FileSystemSandboxContext rather than introducing a new sandbox
model.
   - Carry managed-network enforcement as one explicit bit.
   - Keep argv plain.

2. Apply that intent inside exec-server.
   - Add a small process-start adapter before LocalProcess::exec.
- Reuse the existing codex-sandboxing SandboxManager and exec-server
runtime paths.
- Follow the same shape already used by exec-server filesystem
sandboxing.
   - Do not duplicate or move the sandbox implementations.

3. Report the sandbox actually used.
   - Return the executor-selected sandbox type from process/start.
- Use that value in core for sandbox-denial detection and retry
behavior.

## End state

The orchestrator sends plain commands plus portable sandbox intent. The
executor chooses and applies its own native sandbox: Linux executors use
Linux sandboxing, macOS executors use Seatbelt, and Windows executors
use Windows sandboxing. Concrete wrapper argv, helper paths, and sandbox
env markers never cross the executor boundary.
2026-06-19 17:05:51 +02:00
jif
81b000421d Add config toggles for orchestrator skills and MCP (#28942)
## Why

Orchestrator-provided skills and Codex Apps MCP tools add model-visible
instructions, resources, and tools beyond the local workspace. Hosts
need config-level switches to disable those orchestrator-owned surfaces
independently, without disabling regular skills or regular MCP servers.

## What changed

- Adds `[orchestrator.skills].enabled` and `[orchestrator.mcp].enabled`
config entries, both defaulting to `true`.
- Includes the new settings in `config.schema.json` and in the config
lock so resolved thread configuration preserves the same orchestrator
exposure decisions.
- Threads `orchestrator.skills.enabled` through the app-server skills
extension so disabled orchestrator skills do not expose the `skills`
namespace or inject orchestrator skill context.
- Gates Codex Apps MCP exposure, app instructions, and app auth
eligibility on `orchestrator.mcp.enabled` while leaving non-Codex-Apps
MCP tools available.
- Updates the thread-manager sample config to disable both
orchestrator-owned surfaces.

## Verification

- Added config parsing, loading, defaulting, and schema coverage for the
new settings.
- Added MCP exposure coverage that `orchestrator.mcp.enabled = false`
removes Codex Apps tools while preserving regular MCP tools.
- Added app-server coverage that `orchestrator.skills.enabled = false`
prevents orchestrator skill tools, prompts, and resource reads from
reaching the model turn.
2026-06-19 14:42:26 +02:00
Winston Howes
3a2712ea14 Add indexed web search mode (#28489)
## Summary

- Add `web_search = "indexed"` alongside `disabled`, `cached`, and
`live`.
- Use that same resolved mode for both hosted and standalone web search.
- For hosted search, send `index_gated_web_access: true` with external
web access enabled only when `indexed` is selected.
- For standalone search, preserve the existing boolean wire values for
existing modes (`cached` maps to `false` and `live` to `true`) and send
`"indexed"` only for `indexed`; `disabled` keeps the tool unavailable.
- Carry the mode through managed configuration requirements and
generated schemas.

## Why

Indexed search provides a middle ground between cached-only search and
unrestricted live page fetching. Search queries can remain live while
direct page fetches are limited to URLs admitted by the server.

The existing `web_search` setting remains the single source of truth, so
hosted and standalone executors cannot drift into different access
modes. Without an explicit `indexed` selection, the existing
model-visible tool and request shapes are unchanged.

```toml
web_search = "indexed"

[features]
standalone_web_search = true
```

## Validation

- `just fmt`
- `just test -p codex-api` (`126 passed`)
- `just test -p codex-web-search-extension` (`7 passed`)
- `just test -p codex-core
code_mode_can_call_indexed_standalone_web_search` (`1 passed`)
- Focused configuration, hosted request, standalone request, and
managed-requirement coverage is included in the PR; remaining suites run
in CI.

The full workspace test suite was not run locally.
2026-06-19 05:35:57 -07:00
jif
bd5d31b250 Scope network approvals by environment (#28899)
Stacked on #28766.

## Why

Network approvals are environment-scoped: allowing a host in one
execution environment should not allow the same host in another
environment.

#28766 adds the inert IDs and constructor plumbing. This PR applies the
behavior on top.

## What changed

- Route managed network traffic through per-environment HTTP and SOCKS
proxy listeners.
- Stamp HTTP, HTTPS CONNECT, SOCKS TCP, and SOCKS UDP policy requests
with the source environment at the proxy boundary.
- Carry the selected execution environment through shell, unified exec,
zsh-fork, and sandbox transform paths.
- Include the environment in pending, approved-for-session, and
denied-for-session network approval cache keys.
- Include the environment in approval IDs and approval prompts.
- Preserve legacy fallback for unattributed requests, but deny when
active-call attribution is ambiguous.
- Fail closed if an environment-specific proxy endpoint cannot be
prepared.

## Validation

- just fmt
- CI will run tests and clippy
2026-06-19 13:49:45 +02:00
Shijie Rao
7abfcf220b Expose thread-level multi-agent mode (#28792)
## Why

Once multi-agent mode can be selected per turn, clients also need to
choose the initial selection when creating a thread and observe that
selection through lifecycle and settings APIs.

The selected value is intentionally distinct from the effective
model-visible value: no client selection is represented as `null`, even
though an eligible multi-agent v2 turn derives `explicitRequestOnly` as
its effective default.

## What changed

- Add the optional experimental `thread/start.multiAgentMode` parameter
and pass it through thread creation.
- Preserve an omitted initial value as an unset selection rather than
eagerly storing `explicitRequestOnly`.
- Apply an explicit `thread/start` selection to the first turn through
the session configuration established at thread creation.
- Restore the latest persisted effective mode as the selected baseline
on cold resume when rollout history contains one.
- Inherit the optional selected mode from a loaded parent when creating
related runtime threads.
- Return the current selected `multiAgentMode` from `thread/start`,
`thread/resume`, `thread/fork`, and thread settings, using `null` when
no mode is selected.
- Keep lifecycle reporting independent from model capability and feature
eligibility; core turn construction remains responsible for calculating
and persisting the effective mode.

## Not covered

- Clearing an existing loaded-session selection back to unset through
`turn/start`; omitted or `null` currently retains the session's
selection.
- A TUI control, slash command, or `config.toml` preference.

## Verification

- `CARGO_INCREMENTAL=0 just test -p codex-app-server-protocol`
- `CARGO_INCREMENTAL=0 just test -p codex-app-server multi_agent_mode`

The focused app-server coverage verifies explicit `thread/start`
initialization, first-turn prompting, nullable reporting for an omitted
selection, and retention of selections that are not currently
runtime-eligible.

## Stack

Stacked on #28685. This PR contains only the thread initialization and
lifecycle/settings API layer.
2026-06-19 10:50:44 +02:00
rka-oai
73251b2f00 [codex] add clock current-time tool (#29011)
## Summary
- expose `clock.curr_time` when current-time reminders are enabled
- query the session's configured time provider with the calling thread
id
- return the existing UTC reminder text for direct model calls
- return `{ "current_time": "YYYY-MM-DD HH:MM:SS UTC" }` in Code Mode

Clock lookup failures remain fatal, matching pre-inference reminder
behavior.

## Testing
- `just test -p codex-core current_time_tool_returns_the_latest_time`
- `just test -p codex-core
code_mode_current_time_returns_structured_result`
- `just fix -p codex-core`
2026-06-19 01:46:57 +00:00
Alex Daley
7e37354a58 [plugins] Refresh plugin and tool caches after remote install (#28951)
Summary
- Refresh the installed remote-plugin snapshot and Codex Apps tools
after completing a remote JIT install.
- Gate `completed: true` on every expected `app_connector_id` appearing
after the uncached `tools/list` refresh, while continuing to skip local
bundle verification for server-side installs.
- Keep the cached recommendations response and filter refreshed
installed remote IDs locally, so this does not add another
recommendations fetch.
- Add regression coverage for tools appearing after the hard refresh and
remaining absent after the refresh. The resumed model request sees the
refreshed tool router when installation completes.

Root Cause
- Remote suggestions from `openai-curated-remote` returned `true` before
taking the existing connector refresh path, leaving the resumed turn
with the pre-install Apps tool catalog.

Validation
- `just test -p codex-core request_plugin_install`
- `just test -p codex-core-plugins
recommended_plugin_candidates_filter_installed_and_disabled_plugins`
- `just test -p codex-core-plugins`
- `just fix -p codex-core-plugins`
- `just fix -p codex-core`
- `just fmt`
- `just test -p codex-core` was not fully clean locally: 2,729 passed,
26 failed, and 16 skipped. The failures were dominated by local
Seatbelt/network/timing issues, including plugin-install timeouts under
full-suite contention; the focused plugin-install runs pass.
2026-06-18 20:08:04 -04:00
Adam Perry @ OpenAI
346d2c163f core: keep remote exec on reported shell (#28983)
## Why

We need to avoid resolving shells on the app-server's host for remote
environments. We might make it possible to do fancier shell resolution
from remote envs but for now just require the model to produce a shell
that matches the environment's default.

This gets my e2e demo working for shell commands after #28854 moved
shell resolution to PathUri and caused remote envs to hit the fallback
shell when the shell wasn't available on the host.

## What

Remote `exec_command` calls now accept only the environment's reported
default shell name or exact path, and execute with that reported path.
Other explicit shells return a concise error. A Wine-backed integration
test covers explicit PowerShell execution in the Windows cwd.
2026-06-18 23:39:21 +00:00
martinauyeung-oai
765309d5a6 Emit Trusted MCP App Identity on Tool-Call Items (#27132)
## Summary

- Add optional `appContext` to app-server MCP tool-call items with
trusted `connectorId`, `linkId`, and `mcpAppResourceUri` metadata.
- Preserve that context across tool-call events, persisted history,
reconnects, and thread resume.
- Keep the deprecated top-level `mcpAppResourceUri` temporarily for
client migration.

The consumer contract is `{ appContext: { connectorId, linkId,
mcpAppResourceUri }, tool }`.

## Validation

- Full GitHub Actions suite passes, including CLA, Bazel tests, clippy,
release builds, and argument-comment lint.

---------

Co-authored-by: martinauyeung-oai <280153141+martinauyeung-oai@users.noreply.github.com>
2026-06-18 14:02:54 -07:00
Adam Perry @ OpenAI
0f89dd768c apply-patch: carry paths as PathUri (#28854)
## Why

Allows the model to edit files that are hosted on a different OS than
where app-server is running.

## What

* Use `PathUri` for apply_patch-internal data structures
* Limit `PathUri` -> `AbsolutePathBuf` conversion to cases where the
inferred path convention matches the host OS, allows requiring valid
paths to pass to perms check
* Adds `PathConvention::path_segments()` for iterating over path
segments regardless of OS
* Handle cross-platform relative paths in path filename parsing for
sniffing a shell
* Ensure we can apply patches in the wine e2e test
2026-06-18 19:31:19 +00:00
rka-oai
752ed90d78 current time reminders impl for system clock (varlatency 2/n) (#28824)
Stacked on #28822.

## Summary

- add a host-injectable current-time provider with a built-in system
implementation
- record UTC developer reminders in history immediately before due model
requests
- keep cadence state per session and force a refresh after compaction

This does NOT include the app server client <-> server clock logic. This
PR is only for the reminder message & system clock that will be used in
prod.

## Testing

- `just test -p codex-core varlatency_`
- `just clippy -p codex-core -p codex-app-server -p codex-mcp-server -p
codex-thread-manager-sample`
- `just fmt`
2026-06-18 19:18:42 +00:00
Gabriel Peal
21a599fa56 Support openai/form extended form elicitations (#27500)
# Summary
Allow App Server clients to opt into `openai/form` MCP elicitations.
2026-06-18 11:54:49 -07:00