Commit Graph

640 Commits

Author SHA1 Message Date
pakrym-oai
ac82443d07 Use AbsolutePathBuf in skill loading and codex_home (#17407)
Helps with FS migration later
2026-04-13 10:26:51 -07:00
jif-oai
bacb92b1d7 Build remote exec env from exec-server policy (#17216)
## Summary
- add an exec-server `envPolicy` field; when present, the server starts
from its own process env and applies the shell environment policy there
- keep `env` as the exact environment for local/embedded starts, but
make it an overlay for remote unified-exec starts
- move the shell-environment-policy builder into `codex-config` so Core
and exec-server share the inherit/filter/set/include behavior
- overlay only runtime/sandbox/network deltas from Core onto the
exec-server-derived env

## Why
Remote unified exec was materializing the shell env inside Core and
forwarding the whole map to exec-server, so remote processes could
inherit the orchestrator machine's `HOME`, `PATH`, etc. This keeps the
base env on the executor while preserving Core-owned runtime additions
like `CODEX_THREAD_ID`, unified-exec defaults, network proxy env, and
sandbox marker env.

## Validation
- `just fmt`
- `git diff --check`
- `cargo test -p codex-exec-server --lib`
- `cargo test -p codex-core --lib unified_exec::process_manager::tests`
- `cargo test -p codex-core --lib exec_env::tests`
- `cargo test -p codex-core --lib exec_env_tests` (compile-only; filter
matched 0 tests)
- `cargo test -p codex-config --lib shell_environment` (compile-only;
filter matched 0 tests)
- `just bazel-lock-update`

## Known local validation issue
- `just bazel-lock-check` is not runnable in this checkout: it invokes
`./scripts/check-module-bazel-lock.sh`, which is missing.

---------

Co-authored-by: Codex <noreply@openai.com>
Co-authored-by: pakrym-oai <pakrym@openai.com>
2026-04-13 09:59:08 +01:00
Eric Traut
6550007cca Stabilize exec-server process tests (#17605)
Problem: After #17294 switched exec-server tests to launch the top-level
`codex exec-server` command, parallel remote exec-process cases can
flake while waiting for the child server's listen URL or transport
shutdown.

Solution: Serialize remote exec-server-backed process tests and harden
the harness so spawned servers are killed on drop and shutdown waits for
the child process to exit.
2026-04-13 00:31:13 -07:00
starr-openai
d626dc3895 Run exec-server fs operations through sandbox helper (#17294)
## Summary
- run exec-server filesystem RPCs requiring sandboxing through a
`codex-fs` arg0 helper over stdin/stdout
- keep direct local filesystem execution for `DangerFullAccess` and
external sandbox policies
- remove the standalone exec-server binary path in favor of top-level
arg0 dispatch/runtime paths
- add sandbox escape regression coverage for local and remote filesystem
paths

## Validation
- `just fmt`
- `git diff --check`
- remote devbox: `cd codex-rs && bazel test --bes_backend=
--bes_results_url= //codex-rs/exec-server:all` (6/6 passed)

---------

Co-authored-by: Codex <noreply@openai.com>
2026-04-12 18:36:03 -07:00
Eric Traut
66e13efd9c TUI: enforce core boundary (#17399)
Problem: The TUI still depended on `codex-core` directly in a number of
places, and we had no enforcement from keeping this problem from getting
worse.

Solution: Route TUI core access through
`codex-app-server-client::legacy_core`, add CI enforcement for that
boundary, and re-export this legacy bridge inside the TUI as
`crate::legacy_core` so the remaining call sites stay readable. There is
no functional change in this PR — just changes to import targets.

Over time, we can whittle away at the remaining symbols in this legacy
namespace with the eventual goal of removing them all. In the meantime,
this linter rule will prevent us from inadvertently importing new
symbols from core.
2026-04-10 20:25:31 -07:00
viyatb-oai
b114781495 fix(permissions): fix symlinked writable roots in sandbox permissions (#15981)
## Summary
- preserve logical symlink paths during permission normalization and
config cwd handling
- bind real targets for symlinked readable/writable roots in bwrap and
remap carveouts and unreadable roots there
- add regressions for symlinked carveouts and nested symlink escape
masking

## Root cause
Permission normalization canonicalized symlinked writable roots and cwd
to their real targets too early. That drifted policy checks away from
the logical paths the sandboxed process can actually address, while
bwrap still needed the real targets for mounts. The mismatch caused
shell and apply_patch failures on symlinked writable roots.

## Impact
Fixes #15781.

Also fixes #17079:
- #17079 is the protected symlinked carveout side: bwrap now binds the
real symlinked writable-root target and remaps carveouts before masking.

Related to #15157:
- #15157 is the broader permission-check side of this path-identity
problem. This PR addresses the shared logical-vs-canonical normalization
issue, but the reported Darwin prompt behavior should be validated
separately before auto-closing it.

This should also fix #14672, #14694, #14715, and #15725:
- #14672, #14694, and #14715 are the same Linux
symlinked-writable-root/bwrap family as #15781.
- #15725 is the protected symlinked workspace path variant; the PR
preserves the protected logical path in policy space while bwrap applies
read-only or unreadable treatment to the resolved target so
file-vs-directory bind mismatches do not abort sandbox setup.

## Notes
- Added Linux-only regressions for symlinked writable ancestors and
protected symlinked directory targets, including nested symlink escape
masking without rebinding the escape target writable.

---------

Co-authored-by: Codex <noreply@openai.com>
2026-04-10 17:00:58 -07:00
Shijie Rao
930e5adb7e Revert "Option to Notify Workspace Owner When Usage Limit is Reached" (#17391)
Reverts openai/codex#16969

#sev3-2026-04-10-accountscheckversion-500s-for-openai-workspace-7300
2026-04-10 23:33:13 +00:00
jif-oai
085ffb4456 feat: move exec-server ownership (#16344)
This introduces session-scoped ownership for exec-server so ws
disconnects no longer immediately kill running remote exec processes,
and it prepares the protocol for reconnect-based resume.
- add session_id / resume_session_id to the exec-server initialize
handshake
  - move process ownership under a shared session registry
- detach sessions on websocket disconnect and expire them after a TTL
instead of killing processes immediately (we will resume based on this)
- allow a new connection to resume an existing session and take over
notifications/ownership
- I use UUID to make them not predictable as we don't have auth for now
- make detached-session expiry authoritative at resume time so teardown
wins at the TTL boundary
- reject long-poll process/read calls that get resumed out from under an
older attachment

---------

Co-authored-by: Codex <noreply@openai.com>
2026-04-10 14:11:47 +01:00
richardopenai
9f2a585153 Option to Notify Workspace Owner When Usage Limit is Reached (#16969)
## Summary
- Replace the manual `/notify-owner` flow with an inline confirmation
prompt when a usage-based workspace member hits a credits-depleted
limit.
- Fetch the current workspace role from the live ChatGPT
`accounts/check/v4-2023-04-27` endpoint so owner/member behavior matches
the desktop and web clients.
- Keep owner, member, and spend-cap messaging distinct so we only offer
the owner nudge when the workspace is actually out of credits.

## What Changed
- `backend-client`
- Added a typed fetch for the current account role from
`accounts/check`.
  - Mapped backend role values into a Rust workspace-role enum.
- `app-server` and protocol
  - Added `workspaceRole` to `account/read` and `account/updated`.
- Derived `isWorkspaceOwner` from the live role, with a fallback to the
cached token claim when the role fetch is unavailable.
- `tui`
  - Removed the explicit `/notify-owner` slash command.
- When a member is blocked because the workspace is out of credits, the
error now prompts:
- `Your workspace is out of credits. Request more from your workspace
owner? [y/N]`
  - Choosing `y` sends the existing owner-notification request.
- Choosing `n`, pressing `Esc`, or accepting the default selection
dismisses the prompt without sending anything.
- Selection popups now honor explicit item shortcuts, which is how the
`y` / `n` interaction is wired.

## Reviewer Notes
- The main behavior change is scoped to usage-based workspace members
whose workspace credits are depleted.
- Spend-cap reached should not show the owner-notification prompt.
- Owners and admins should continue to see `/usage` guidance instead of
the member prompt.
- The live role fetch is best-effort; if it fails, we fall back to the
existing token-derived ownership signal.

## Testing
- Manual verification
  - Workspace owner does not see the member prompt.
- Workspace member with depleted credits sees the confirmation prompt
and can send the nudge with `y`.
- Workspace member with spend cap reached does not see the
owner-notification prompt.

### Workspace member out of usage

https://github.com/user-attachments/assets/341ac396-eff4-4a7f-bf0c-60660becbea1

### Workspace owner
<img width="1728" height="1086" alt="Screenshot 2026-04-09 at 11 48
22 AM"
src="https://github.com/user-attachments/assets/06262a45-e3fc-4cc4-8326-1cbedad46ed6"
/>
2026-04-09 21:15:17 -07:00
Eric Traut
36712d8546 Install rustls provider for remote websocket client (#17288)
Addresses #17283

Problem: `codex --remote wss://...` could panic because
app-server-client did not install rustls' process-level crypto provider
before opening TLS websocket connections.

Solution: Add the existing rustls provider utility dependency and
install it before the remote websocket connect.
2026-04-09 20:29:12 -07:00
Casey Chow
244b15c95d feat: add Codex Apps sediment file remapping (#15197)
## Summary
- bridge Codex Apps tools that declare `_meta["openai/fileParams"]`
through the OpenAI file upload flow
- mask those file params in model-visible tool schemas so the model
provides absolute local file paths instead of raw file payload objects
- rewrite those local file path arguments client-side into
`ProvidedFilePayload`-shaped objects before the normal MCP tool call

## Details
- applies to scalar and array file params declared in
`openai/fileParams`
- Codex uploads local files directly to the backend and uses the
uploaded file metadata to build the MCP tool arguments locally
- this PR is input-only

## Verification
- `just fmt`
- `cargo test -p codex-core mcp_tool_call -- --nocapture`

---------

Co-authored-by: Codex <noreply@openai.com>
2026-04-09 14:10:44 -04:00
Ahmed Ibrahim
4c2a1ae31b Move default realtime prompt into core (#17165)
- Adds a core-owned realtime backend prompt template and preparation
path.
- Makes omitted realtime start prompts use the core default, while null
or empty prompts intentionally send empty instructions.
- Covers the core realtime path and app-server v2 path with integration
coverage.

---------

Co-authored-by: Codex <noreply@openai.com>
2026-04-08 19:34:40 -07:00
pakrym-oai
e4d6702b87 [codex] Support remote exec cwd in TUI startup (#17142)
When running with remote executor the cwd is the remote path. Today we
check for existence of a local directory on startup and attempt to load
config from it.

For remote executors don't do that.
2026-04-08 13:09:28 -07:00
starr-openai
f383cc980d Add sandbox support to filesystem APIs (#16751)
## Summary
- add optional `sandboxPolicy` support to the app-server filesystem
request surface
- thread sandbox-aware filesystem options through app-server and
exec-server adapters
- enforce sandboxed read/write access in the filesystem abstraction with
focused local and remote coverage

## Validation
- `cargo test -p codex-app-server-protocol`
- `cargo test -p codex-exec-server file_system`
- `cargo test -p codex-app-server suite::v2::fs`

---------

Co-authored-by: Codex <noreply@openai.com>
2026-04-08 12:10:48 -07:00
Ahmed Ibrahim
d90a348870 Add WebRTC media transport to realtime TUI (#17058)
Adds the `[realtime].transport = "webrtc"` TUI media path using a new
`codex-realtime-webrtc` crate, while leaving app-server as the
signaling/event source.\n\nLocal checks: fmt, diff-check, dependency
tree only; test signal should come from CI.

---------

Co-authored-by: Codex <noreply@openai.com>
2026-04-08 10:26:55 -07:00
pakrym-oai
e9702411ab [codex] Migrate apply_patch to executor filesystem (#17027)
- Migrate apply-patch verification and application internals to use the
async `ExecutorFileSystem` abstraction from `exec-server`.
- Convert apply-patch `cwd` handling to `AbsolutePathBuf` through the
verifier/parser/handler boundary.

Doesn't change how the tool itself works.
2026-04-07 21:20:22 +00:00
pakrym-oai
f1a2b920f9 [codex] Make AbsolutePathBuf joins infallible (#16981)
Having to check for errors every time join is called is painful and
unnecessary.
2026-04-07 10:52:08 -07:00
pakrym-oai
4bb507d2c4 Make AGENTS.md discovery FS-aware (#15826)
## Summary
- make AGENTS.md discovery and loading fully FS-aware and remove the
non-FS discover helper
- migrate remote-aware codex-core tests to use TestEnv workspace setup
instead of syncing a local workspace copy
- add AGENTS.md corner-case coverage, including directory fallbacks and
remote-aware integration coverage

## Testing
- cargo test -p codex-core project_doc -- --nocapture
- cargo test -p codex-core hierarchical_agents -- --nocapture
- cargo test -p codex-core agents_md -- --nocapture
- cargo test -p codex-tui status -- --nocapture
- cargo test -p codex-tui-app-server status -- --nocapture
- just fix
- just fmt
- just bazel-lock-update
- just bazel-lock-check
- just argument-comment-lint
- remote Linux executor tests in progress via scripts/test-remote-env.sh
2026-04-06 20:26:21 -07:00
pakrym-oai
1f2411629f Refactor config types into a separate crate (#16962)
Move config types into a separate crate because their macros expand into
a lot of new code.
2026-04-07 00:32:41 +00:00
Ruslan Nigmatullin
73dab2046f app-server: Add transport for remote control (#15951) 2026-04-06 14:55:59 -07:00
Owen Lin
bd30bad96f fix(guardian): fix ordering of guardian events (#16462)
Guardian events were emitted a bit out of order for CommandExecution
items. This would make it hard for the frontend to render a guardian
auto-review, which has this payload:
```
pub struct ItemGuardianApprovalReviewStartedNotification {
    pub thread_id: String,
    pub turn_id: String,
    pub target_item_id: String,
    pub review: GuardianApprovalReview,
    // FYI this is no longer a json blob
    pub action: Option<JsonValue>,
}
```

There is a `target_item_id` the auto-approval review is referring to,
but the actual item had not been emitted yet.

Before this PR:
- `item/autoApprovalReview/started`
- `item/autoApprovalReview/completed`, and if approved...
- `item/started`
- `item/completed`

After this PR:
- `item/started`
- `item/autoApprovalReview/started`
- `item/autoApprovalReview/completed`
- `item/completed`

This lines up much better with existing patterns (i.e. human review in
`Default mode`, where app-server would send a server request to prompt
for user approval after `item/started`), and makes it easier for clients
to render what guardian is actually reviewing.

We do this following a similar pattern as `FileChange` (aka apply patch)
items, where we create a FileChange item and emit `item/started` if we
see the apply patch approval request, before the actual apply patch call
runs.
2026-04-06 19:14:27 +00:00
Eric Traut
54dbbb839e (tui): Decode percent-escaped bare local file links (#16810)
Addresses #16622

Problem: bare local file links in TUI markdown render percent-encoded
path bytes literally, unlike file:// links.

Solution: decode bare path targets before local-path expansion and add
regression coverage for spaces and Unicode.
2026-04-06 08:52:18 -07:00
Thibault Sottiaux
6edb865cc6 [codex] add responses proxy JSON dumps (#16753)
This makes Responses API proxy request/response dumping first-class by
adding an optional `--dump-dir` flag that emits paired JSON files with
shared sequence/timestamp prefixes, captures full request and response
headers and records parsed JSON bodies.
2026-04-03 16:51:18 -10:00
Eric Traut
1cc87019b4 Fix macOS sandbox panic in Codex HTTP client (#16670)
Addresses #15640

Problem: `codex exec` panicked on macOS when sandboxed proxy discovery
hit a NULL `SCDynamicStore` handle in `system-configuration`.

Solution: Bump `hyper-util` and `system-configuration` to versions that
handle denied `configd` lookups safely, and refresh the Bazel lockfile.

Testing: Verified using the manual `printf '(version 1) (allow default)
(deny mach-lookup (global-name
"com.apple.SystemConfiguration.configd"))' > /tmp/deny-configd.sb
sandbox-exec -f /tmp/deny-configd.sb codex exec -s danger-full-access
"echo test"`. Prior to the fix, this caused a panic.
2026-04-03 10:55:15 -07:00
Ahmed Ibrahim
af8a9d2d2b remove temporary ownership re-exports (#16626)
Stacked on #16508.

This removes the temporary `codex-core` / `codex-login` re-export shims
from the ownership split and rewrites callsites to import directly from
`codex-model-provider-info`, `codex-models-manager`, `codex-api`,
`codex-protocol`, `codex-feedback`, and `codex-response-debug-context`.

No behavior change intended; this is the mechanical import cleanup layer
split out from the ownership move.

---------

Co-authored-by: Codex <noreply@openai.com>
2026-04-03 00:33:34 -07:00
Ahmed Ibrahim
6fff9955f1 extract models manager and related ownership from core (#16508)
## Summary
- split `models-manager` out of `core` and add `ModelsManagerConfig`
plus `Config::to_models_manager_config()` so model metadata paths stop
depending on `core::Config`
- move login-owned/auth-owned code out of `core` into `codex-login`,
move model provider config into `codex-model-provider-info`, move API
bridge mapping into `codex-api`, move protocol-owned types/impls into
`codex-protocol`, and move response debug helpers into a dedicated
`response-debug-context` crate
- move feedback tag emission into `codex-feedback`, relocate tests to
the crates that now own the code, and keep broad temporary re-exports so
this PR avoids a giant import-only rewrite

## Major moves and decisions
- created `codex-models-manager` as the owner for model
cache/catalog/config/model info logic, including the new
`ModelsManagerConfig` struct
- created `codex-model-provider-info` as the owner for provider config
parsing/defaults and kept temporary `codex-login`/`codex-core`
re-exports for old import paths
- moved `api_bridge` error mapping + `CoreAuthProvider` into
`codex-api`, while `codex-login::api_bridge` temporarily re-exports
those symbols and keeps the `auth_provider_from_auth` wrapper
- moved `auth_env_telemetry` and `provider_auth` ownership to
`codex-login`
- moved `CodexErr` ownership to `codex-protocol::error`, plus
`StreamOutput`, `bytes_to_string_smart`, and network policy helpers to
protocol-owned modules
- created `codex-response-debug-context` for
`extract_response_debug_context`, `telemetry_transport_error_message`,
and related response-debug plumbing instead of leaving that behavior in
`core`
- moved `FeedbackRequestTags`, `emit_feedback_request_tags`, and
`emit_feedback_request_tags_with_auth_env` to `codex-feedback`
- deferred removal of temporary re-exports and the mechanical import
rewrites to a stacked follow-up PR so this PR stays reviewable

## Test moves
- moved auth refresh coverage from `core/tests/suite/auth_refresh.rs` to
`login/tests/suite/auth_refresh.rs`
- moved text encoding coverage from
`core/tests/suite/text_encoding_fix.rs` to
`protocol/src/exec_output_tests.rs`
- moved model info override coverage from
`core/tests/suite/model_info_overrides.rs` to
`models-manager/src/model_info_overrides_tests.rs`

---------

Co-authored-by: Codex <noreply@openai.com>
2026-04-02 23:00:02 -07:00
Michael Bolin
c1d18ceb6f [codex] Remove codex-core config type shim (#16529)
## Why

This finishes the config-type move out of `codex-core` by removing the
temporary compatibility shim in `codex_core::config::types`. Callers now
depend on `codex-config` directly, which keeps these config model types
owned by the config crate instead of re-expanding `codex-core` as a
transitive API surface.

## What Changed

- Removed the `codex-rs/core/src/config/types.rs` re-export shim and the
`core::config::ApprovalsReviewer` re-export.
- Updated `codex-core`, `codex-cli`, `codex-tui`, `codex-app-server`,
`codex-mcp-server`, and `codex-linux-sandbox` call sites to import
`codex_config::types` directly.
- Added explicit `codex-config` dependencies to downstream crates that
previously relied on the `codex-core` re-export.
- Regenerated `codex-rs/core/config.schema.json` after updating the
config docs path reference.
2026-04-02 01:19:44 -07:00
Michael Bolin
f32a5e84bf [codex] Move config types into codex-config (#16523)
## Why

`codex-rs/core/src/config/types.rs` is a plain config-type module with
no dependency on `codex-core`. Moving it into `codex-config` shrinks the
core crate and gives config-only consumers a more natural dependency
boundary.

## What Changed

- Added `codex_config::types` with the moved structs, enums, constants,
and unit tests.
- Kept `codex_core::config::types` as a compatibility re-export to avoid
a broad call-site migration in this PR.
- Switched notice-table writes in `core/src/config/edit.rs` to a local
`NOTICE_TABLE_KEY` constant.
- Added the `wildmatch` runtime dependency and `tempfile` test
dependency to `codex-config`.
2026-04-02 00:39:20 -07:00
Michael Bolin
52e779d35d fix: add update to Cargo.lock that was missed in #16512 (#16516)
This PR updates `Cargo.lock` to remove `codex-core` from
`mcp_test_support`, which corresponds to
`codex-rs/mcp-server/tests/common/Cargo.toml`. As noted in #16512, it
updated that crate to drop its `codex-core` dependency.
2026-04-01 23:33:41 -07:00
Michael Bolin
aa2403e2eb core: remove cross-crate re-exports from lib.rs (#16512)
## Why

`codex-core` was re-exporting APIs owned by sibling `codex-*` crates,
which made downstream crates depend on `codex-core` as a proxy module
instead of the actual owner crate.

Removing those forwards makes crate boundaries explicit and lets leaf
crates drop unnecessary `codex-core` dependencies. In this PR, this
reduces the dependency on `codex-core` to `codex-login` in the following
files:

```
codex-rs/backend-client/Cargo.toml
codex-rs/mcp-server/tests/common/Cargo.toml
```

## What

- Remove `codex-rs/core/src/lib.rs` re-exports for symbols owned by
`codex-login`, `codex-mcp`, `codex-rollout`, `codex-analytics`,
`codex-protocol`, `codex-shell-command`, `codex-sandboxing`,
`codex-tools`, and `codex-utils-path`.
- Delete the `default_client` forwarding shim in `codex-rs/core`.
- Update in-crate and downstream callsites to import directly from the
owning `codex-*` crate.
- Add direct Cargo dependencies where callsites now target the owner
crate, and remove `codex-core` from `codex-rs/backend-client`.
2026-04-01 23:06:24 -07:00
Michael Bolin
cc97982bbb core: use codex-mcp APIs directly (#16510)
## Why

`codex-mcp` already owns the shared MCP API surface, including `auth`,
`McpConfig`, `CODEX_APPS_MCP_SERVER_NAME`, and tool-name helpers in
[`codex-rs/codex-mcp/src/mcp/mod.rs`](f61e85dbfb/codex-rs/codex-mcp/src/mcp/mod.rs (L1-L35)).
Re-exporting that surface from `codex_core::mcp` gives downstream crates
two import paths for the same API and hides the real crate dependency.

This PR keeps `codex_core::mcp` focused on the local `McpManager`
wrapper in
[`codex-rs/core/src/mcp.rs`](f61e85dbfb/codex-rs/core/src/mcp.rs (L13-L40))
and makes consumers import shared MCP APIs from `codex_mcp` directly.

## What

- Remove the `codex_mcp::mcp` re-export surface from `core/src/mcp.rs`.
- Update `codex-core` internals plus `codex-app-server`, `codex-cli`,
and `codex-tui` test code to import MCP APIs from `codex_mcp::mcp`
directly.
- Add explicit `codex-mcp` dependencies where those crates now use that
API surface, and refresh `Cargo.lock`.

## Verification

- `just bazel-lock-check`
- `cargo test -p codex-core -p codex-cli -p codex-tui`
  - `codex-cli` passed.
- `codex-core` still fails five unrelated config tests in
`core/src/config/config_tests.rs` (`approvals_reviewer_*` and
`smart_approvals_alias_*`).
- A broader `cargo test -p codex-core -p codex-app-server -p codex-cli
-p codex-tui` run previously hung in `codex-app-server` test
`in_process_start_uses_requested_session_source_for_thread_start`.
2026-04-01 21:55:22 -07:00
Ahmed Ibrahim
59b68f5519 Extract MCP into codex-mcp crate (#15919)
- Split MCP runtime/server code out of `codex-core` into the new
`codex-mcp` crate. New/moved public structs/types include `McpConfig`,
`McpConnectionManager`, `ToolInfo`, `ToolPluginProvenance`,
`CodexAppsToolsCacheKey`, and the `McpManager` API
(`codex_mcp::mcp::McpManager` plus the `codex_core::mcp::McpManager`
wrapper/shim). New/moved functions include `with_codex_apps_mcp`,
`configured_mcp_servers`, `effective_mcp_servers`,
`collect_mcp_snapshot`, `collect_mcp_snapshot_from_manager`,
`qualified_mcp_tool_name_prefix`, and the MCP auth/skill-dependency
helpers. Why: this creates a focused MCP crate boundary and shrinks
`codex-core` without forcing every consumer to migrate in the same PR.

- Move MCP server config schema and persistence into `codex-config`.
New/moved structs/enums include `AppToolApproval`,
`McpServerToolConfig`, `McpServerConfig`, `RawMcpServerConfig`,
`McpServerTransportConfig`, `McpServerDisabledReason`, and
`codex_config::ConfigEditsBuilder`. New/moved functions include
`load_global_mcp_servers` and
`ConfigEditsBuilder::replace_mcp_servers`/`apply`. Why: MCP TOML
parsing/editing is config ownership, and this keeps config
validation/round-tripping (including per-tool approval overrides and
inline bearer-token rejection) in the config crate instead of
`codex-core`.

- Rewire `codex-core`, app-server, and plugin call sites onto the new
crates. Updated `Config::to_mcp_config(&self, plugins_manager)`,
`codex-rs/core/src/mcp.rs`, `codex-rs/core/src/connectors.rs`,
`codex-rs/core/src/codex.rs`,
`CodexMessageProcessor::list_mcp_server_status_task`, and
`utils/plugins/src/mcp_connector.rs` to build/pass the new MCP
config/runtime types. Why: plugin-provided MCP servers still merge with
user-configured servers, and runtime auth (`CodexAuth`) is threaded into
`with_codex_apps_mcp` / `collect_mcp_snapshot` explicitly so `McpConfig`
stays config-only.
2026-04-01 19:03:26 -07:00
Michael Bolin
a99d4845e3 Extract tool config into codex-tools (#16379)
## Why

`codex-core` already owns too much of the tool stack, and `AGENTS.md`
explicitly pushes us to move shared code out of `codex-core` instead of
letting it keep growing. This PR takes the next incremental step in
moving `core/src/tools` toward `codex-rs/tools` by extracting
low-coupling tool configuration and image-detail gating logic into
`codex-tools`.

That gives later extraction work a cleaner boundary to build on without
trying to move the entire tools subtree in one shot.

## What changed

- moved `ToolsConfig`, `ToolsConfigParams`, shell backend config, and
unified-exec session selection from `core/src/tools/spec.rs` into
`codex-tools`
- moved original image-detail gating and normalization into
`codex-tools`
- updated `codex-core` to consume the new `codex-tools` exports and pass
a rendered agent-type description instead of raw role config
- kept `codex-rs/tools/src/lib.rs` exports-only, with extracted unit
tests living in sibling `*_tests.rs` modules

## Testing

- `cargo test -p codex-tools`
- `cargo test -p codex-core --lib tools::spec::`
2026-04-01 13:21:50 -07:00
Michael Bolin
9f0be146db cloud-tasks: split the mock client out of cloud-tasks-client (#16456)
## Why

`codex-cloud-tasks-client` was mixing two different roles: the real HTTP
client and the mock implementation used by tests and local mock mode.
Keeping both in the same crate forced Cargo feature toggles and Bazel
`crate_features` just to pick an implementation.

This change keeps `codex-cloud-tasks-client` focused on the shared API
surface and real backend client, and moves the mock implementation into
its own crate so we can remove those feature permutations cleanly.

## What changed

- add a new `codex-cloud-tasks-mock-client` crate that owns `MockClient`
- remove the `mock` and `online` features from
`codex-cloud-tasks-client`
- make `codex-cloud-tasks-client` unconditionally depend on
`codex-backend-client` and export `HttpClient` directly
- gate the mock-mode path in `codex-cloud-tasks` behind
`#[cfg(debug_assertions)]`, so release builds always initialize the real
HTTP client
- update `codex-cloud-tasks` and its tests to use
`codex-cloud-tasks-mock-client::MockClient` wherever mock behavior is
needed
- remove the matching Bazel `crate_features` override and shrink the
manifest verifier allowlist accordingly

## How tested

- `cargo test -p codex-cloud-tasks-client`
- `cargo test -p codex-cloud-tasks-mock-client`
- `cargo test -p codex-cloud-tasks`

---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/16456).
* #16457
* __->__ #16456
2026-04-01 12:09:14 -07:00
rhan-oai
e8de4ea953 [codex-analytics] thread events (#15690)
- add event for thread initialization
- thread/start, thread/fork, thread/resume
- feature flagged behind `FeatureFlag::GeneralAnalytics`
- does not yet support threads started by subagents

PR stack:
- --> [[telemetry] thread events
#15690](https://github.com/openai/codex/pull/15690)
- [[telemetry] subagent events
#15915](https://github.com/openai/codex/pull/15915)
- [[telemetry] turn events
#15591](https://github.com/openai/codex/pull/15591)
- [[telemetry] steer events
#15697](https://github.com/openai/codex/pull/15697)
- [[telemetry] queued prompt data
#15804](https://github.com/openai/codex/pull/15804)


Sample extracted logs in Codex-backend
```
INFO     | 2026-03-29 16:39:37 | codex_backend.routers.analytics_events | analytics_events.track_analytics_events:398 | Tracked analytics event codex_thread_initialized thread_id=019d3bf7-9f5f-7f82-9877-6d48d1052531 product_surface=codex product_client_id=CODEX_CLI client_name=codex-tui client_version=0.0.0 rpc_transport=in_process experimental_api_enabled=True codex_rs_version=0.0.0 runtime_os=macos runtime_os_version=26.4.0 runtime_arch=aarch64 model=gpt-5.3-codex ephemeral=False thread_source=user initialization_mode=new subagent_source=None parent_thread_id=None created_at=1774827577 | 
INFO     | 2026-03-29 16:45:46 | codex_backend.routers.analytics_events | analytics_events.track_analytics_events:398 | Tracked analytics event codex_thread_initialized thread_id=019d3b84-5731-79d0-9b3b-9c6efe5f5066 product_surface=codex product_client_id=CODEX_CLI client_name=codex-tui client_version=0.0.0 rpc_transport=in_process experimental_api_enabled=True codex_rs_version=0.0.0 runtime_os=macos runtime_os_version=26.4.0 runtime_arch=aarch64 model=gpt-5.3-codex ephemeral=False thread_source=user initialization_mode=resumed subagent_source=None parent_thread_id=None created_at=1774820022 | 
INFO     | 2026-03-29 16:45:49 | codex_backend.routers.analytics_events | analytics_events.track_analytics_events:398 | Tracked analytics event codex_thread_initialized thread_id=019d3bfd-4cd6-7c12-a13e-48cef02e8c4d product_surface=codex product_client_id=CODEX_CLI client_name=codex-tui client_version=0.0.0 rpc_transport=in_process experimental_api_enabled=True codex_rs_version=0.0.0 runtime_os=macos runtime_os_version=26.4.0 runtime_arch=aarch64 model=gpt-5.3-codex ephemeral=False thread_source=user initialization_mode=forked subagent_source=None parent_thread_id=None created_at=1774827949 | 
INFO     | 2026-03-29 17:20:29 | codex_backend.routers.analytics_events | analytics_events.track_analytics_events:398 | Tracked analytics event codex_thread_initialized thread_id=019d3c1d-0412-7ed2-ad24-c9c0881a36b0 product_surface=codex product_client_id=CODEX_SERVICE_EXEC client_name=codex_exec client_version=0.0.0 rpc_transport=in_process experimental_api_enabled=True codex_rs_version=0.0.0 runtime_os=macos runtime_os_version=26.4.0 runtime_arch=aarch64 model=gpt-5.3-codex ephemeral=False thread_source=user initialization_mode=new subagent_source=None parent_thread_id=None created_at=1774830027 | 
```

Notes
- `product_client_id` gets canonicalized in codex-backend
- subagent threads are addressed in a following pr
2026-03-31 12:16:44 -07:00
rhan-oai
28a9807f84 [codex-analytics] refactor analytics to use reducer architecture (#16225)
- rework codex analytics crate to use reducer / publish architecture
- in anticipation of extensive codex analytics
2026-03-30 14:27:12 -07:00
Michael Bolin
258ba436f1 codex-tools: extract discoverable tool models (#16254)
## Why

`#16193` moved the pure `tool_search` and `tool_suggest` spec builders
into `codex-tools`, but `codex-core` still owned the shared
discoverable-tool model that those builders and the `tool_suggest`
runtime both depend on. This change continues the migration by moving
that reusable model boundary out of `codex-core` as well, so the
discovery/suggestion stack uses one shared set of types and
`core/src/tools` no longer needs its own `discoverable.rs` module.

## What changed

- Moved `DiscoverableTool`, `DiscoverablePluginInfo`, and
`filter_tool_suggest_discoverable_tools_for_client()` into
`codex-rs/tools/src/tool_discovery.rs` alongside the extracted
discovery/suggestion spec builders.
- Added `codex-app-server-protocol` as a `codex-tools` dependency so the
shared discoverable-tool model can own the connector-side `AppInfo`
variant directly.
- Updated `core/src/tools/handlers/tool_suggest.rs`,
`core/src/tools/spec.rs`, `core/src/tools/router.rs`,
`core/src/connectors.rs`, and `core/src/codex.rs` to consume the shared
`codex-tools` model instead of the old core-local declarations.
- Changed `core/src/plugins/discoverable.rs` to return
`DiscoverablePluginInfo` directly, moved the pure client-filter coverage
into `tool_discovery_tests.rs`, and deleted the old
`core/src/tools/discoverable.rs` module.
- Updated `codex-rs/tools/README.md` so the crate boundary documents
that `codex-tools` now owns the discoverable-tool models in addition to
the discovery/suggestion spec builders.

## Test plan

- `cargo test -p codex-tools`
- `CARGO_TARGET_DIR=/tmp/codex-core-discoverable-model cargo test -p
codex-core --lib tools::handlers::tool_suggest::`
- `CARGO_TARGET_DIR=/tmp/codex-core-discoverable-model cargo test -p
codex-core --lib tools::spec::`
- `CARGO_TARGET_DIR=/tmp/codex-core-discoverable-model cargo test -p
codex-core --lib plugins::discoverable::`
- `just bazel-lock-check`
- `just argument-comment-lint`

## References

- #16193
- #16154
- #15923
- #15928
- #15944
- #15953
- #16031
- #16047
- #16129
- #16132
- #16138
- #16141
2026-03-30 10:48:49 -07:00
Eric Traut
3bbc1ce003 Remove TUI voice transcription feature (#16114)
Removes the partially-completed TUI composer voice transcription flow,
including its feature flag, app events, and hold-to-talk state machine.
2026-03-29 00:20:25 +00:00
Michael Bolin
2238c16a91 codex-tools: extract code mode tool spec adapters (#16132)
## Why

The longer-term `codex-tools` migration is to move pure tool-definition
and tool-spec plumbing out of `codex-core` while leaving session- and
runtime-coupled orchestration behind.

The remaining code-mode adapter layer in
`core/src/tools/code_mode_description.rs` was a good next extraction
seam because it only transformed `ToolSpec` values for code mode and
already delegated the low-level description rendering to
`codex-code-mode`.

## What Changed

- added `codex-rs/tools/src/code_mode.rs` with
`augment_tool_spec_for_code_mode()` and
`tool_spec_to_code_mode_tool_definition()`
- added focused unit coverage in `codex-rs/tools/src/code_mode_tests.rs`
- rewired `core/src/tools/spec.rs` and `core/src/tools/code_mode/mod.rs`
to use the extracted adapters from `codex-tools`
- removed the old `core/src/tools/code_mode_description.rs` shim and its
test file from `codex-core`
- added the `codex-code-mode` dependency to `codex-tools`, updated
`Cargo.lock`, and refreshed the `codex-tools` README to reflect the
expanded boundary

## Test Plan

- `cargo test -p codex-tools`
- `CARGO_TARGET_DIR=/tmp/codex-core-code-mode-adapters cargo test -p
codex-core --lib tools::spec::`
- `CARGO_TARGET_DIR=/tmp/codex-core-code-mode-adapters cargo test -p
codex-core --lib tools::code_mode::`
- `just bazel-lock-update`
- `just bazel-lock-check`
- `just argument-comment-lint`

## References

- #15923
- #15928
- #15944
- #15953
- #16031
- #16047
- #16129
2026-03-28 15:32:35 -07:00
Eric Traut
d65deec617 Remove the legacy TUI split (#15922)
This is the part 1 of 2 PRs that will delete the `tui` /
`tui_app_server` split. This part simply deletes the existing `tui`
directory and marks the `tui_app_server` feature flag as removed. I left
the `tui_app_server` feature flag in place for now so its presence
doesn't result in an error. It is simply ignored.

Part 2 will rename the `tui_app_server` directory `tui`. I did this as
two parts to reduce visible code churn.
2026-03-27 22:56:44 +00:00
Michael Bolin
617475e54b codex-tools: extract dynamic tool adapters (#15944)
## Why

`codex-tools` already owned the shared JSON schema parser and the MCP
tool schema adapter, but `core/src/tools/spec.rs` still parsed dynamic
tools directly.

That left the tool-schema boundary split in two different ways:

- MCP tools flowed through `codex-tools`, while dynamic tools were still
parsed in `codex-core`
- the extracted dynamic-tool path initially introduced a
dynamic-specific parsed shape even though `codex-tools` already had very
similar MCP adapter output

This change finishes that extraction boundary in one step. `codex-core`
still owns `ResponsesApiTool` assembly, but both MCP tools and dynamic
tools now enter that layer through `codex-tools` using the same parsed
tool-definition shape.

## What changed

- added `tools/src/dynamic_tool.rs` and sibling
`tools/src/dynamic_tool_tests.rs`
- introduced `parse_dynamic_tool()` in `codex-tools` and switched
`core/src/tools/spec.rs` to use it for dynamic tools
- added `tools/src/parsed_tool_definition.rs` so both MCP and dynamic
adapters return the same `ParsedToolDefinition`
- updated `core/src/tools/spec.rs` to build `ResponsesApiTool` through a
shared local adapter helper instead of separate MCP and dynamic assembly
paths
- expanded `core/src/tools/spec_tests.rs` so the dynamic-tool adapter
test asserts the full converted `ResponsesApiTool`, including
`defer_loading`
- updated `codex-rs/tools/README.md` to reflect the shared parsed
tool-definition boundary

## Test plan

- `cargo test -p codex-tools`
- `cargo test -p codex-core --lib tools::spec::`

---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/15944).
* #15953
* __->__ #15944
2026-03-27 09:12:36 -07:00
jif-oai
2c85ca6842 Use codex-utils-template for sandbox mode prompts (#15998) 2026-03-27 14:50:36 +01:00
jif-oai
270b7655cd Use codex-utils-template for login error page (#16000) 2026-03-27 14:49:45 +01:00
jif-oai
2e849703cd chore: drop useless stuff (#15876) 2026-03-27 09:41:47 +01:00
Michael Bolin
be5afc65d3 codex-tools: extract MCP schema adapters (#15928)
## Why

`codex-tools` already owns the shared tool input schema model and parser
from the first extraction step, but `core/src/tools/spec.rs` still owned
the MCP-specific adapter that normalizes `rmcp::model::Tool` schemas and
wraps `structuredContent` into the call result output schema.

Keeping that adapter in `codex-core` means the reusable MCP schema path
is still split across crates, and the unit tests for that logic stay
anchored in `codex-core` even though the runtime orchestration does not
need to move yet.

This change takes the next small step by moving the reusable MCP schema
adapter into `codex-tools` while leaving `ResponsesApiTool` assembly in
`codex-core`.

## What changed

- added `tools/src/mcp_tool.rs` and sibling
`tools/src/mcp_tool_tests.rs`
- introduced `ParsedMcpTool`, `parse_mcp_tool()`, and
`mcp_call_tool_result_output_schema()` in `codex-tools`
- updated `core/src/tools/spec.rs` to consume parsed MCP tool parts from
`codex-tools`
- removed the now-redundant MCP schema unit tests from
`core/src/tools/spec_tests.rs`
- expanded `codex-rs/tools/README.md` to describe this second migration
step

## Test plan

- `cargo test -p codex-tools`
- `cargo test -p codex-core --lib tools::spec::`
2026-03-26 19:57:26 -07:00
Michael Bolin
e6e2999209 permissions: remove macOS seatbelt extension profiles (#15918)
## Why

`PermissionProfile` should only describe the per-command permissions we
still want to grant dynamically. Keeping
`MacOsSeatbeltProfileExtensions` in that surface forced extra macOS-only
approval, protocol, schema, and TUI branches for a capability we no
longer want to expose.

## What changed

- Removed the macOS-specific permission-profile types from
`codex-protocol`, the app-server v2 API, and the generated
schema/TypeScript artifacts.
- Deleted the core and sandboxing plumbing that threaded
`MacOsSeatbeltProfileExtensions` through execution requests and seatbelt
construction.
- Simplified macOS seatbelt generation so it always includes the fixed
read-only preferences allowlist instead of carrying a configurable
profile extension.
- Removed the macOS additional-permissions UI/docs/test coverage and
deleted the obsolete macOS permission modules.
- Tightened `request_permissions` intersection handling so explicitly
empty requested read lists are preserved only when that field was
actually granted, avoiding zero-grant responses being stored as active
permissions.
2026-03-26 17:12:45 -07:00
Michael Bolin
44d28f500f codex-tools: extract shared tool schema parsing (#15923)
## Why

`parse_tool_input_schema` and the supporting `JsonSchema` model were
living in `core/src/tools/spec.rs`, but they already serve callers
outside `codex-core`.

Keeping that shared schema parsing logic inside `codex-core` makes the
crate boundary harder to reason about and works against the guidance in
`AGENTS.md` to avoid growing `codex-core` when reusable code can live
elsewhere.

This change takes the first extraction step by moving the schema parsing
primitive into its own crate while keeping the rest of the tool-spec
assembly in `codex-core`.

## What changed

- added a new `codex-tools` crate under `codex-rs/tools`
- moved the shared tool input schema model and sanitizer/parser into
`tools/src/json_schema.rs`
- kept `tools/src/lib.rs` exports-only, with the module-level unit tests
split into `json_schema_tests.rs`
- updated `codex-core` to use `codex-tools::JsonSchema` and re-export
`parse_tool_input_schema`
- updated `codex-app-server` dynamic tool validation to depend on
`codex-tools` directly instead of reaching through `codex-core`
- wired the new crate into the Cargo workspace and Bazel build graph
2026-03-27 00:03:35 +00:00
viyatb-oai
b52abff279 chore: move bwrap config helpers into dedicated module (#15898)
## Summary
- move the bwrap PATH lookup and warning helpers out of config/mod.rs
- move the related tests into a dedicated bwrap_tests.rs file

## Validation
- git diff --check
- skipped heavier local tests per request

Follow-up to #15791.
2026-03-26 15:15:59 -07:00
Michael Bolin
b23789b770 [codex] import token_data from codex-login directly (#15903)
## Why
`token_data` is owned by `codex-login`, but `codex-core` was still
re-exporting it. That let callers pull auth token types through
`codex-core`, which keeps otherwise unrelated crates coupled to
`codex-core` and makes `codex-core` more of a build-graph bottleneck.

## What changed
- remove the `codex-core` re-export of `codex_login::token_data`
- update the remaining `codex-core` internals that used
`crate::token_data` to import `codex_login::token_data` directly
- update downstream callers in `codex-rs/chatgpt`,
`codex-rs/tui_app_server`, `codex-rs/app-server/tests/common`, and
`codex-rs/core/tests` to import `codex_login::token_data` directly
- add explicit `codex-login` workspace dependencies and refresh lock
metadata for crates that now depend on it directly

## Validation
- `cargo test -p codex-chatgpt --locked`
- `just argument-comment-lint`
- `just bazel-lock-update`
- `just bazel-lock-check`

## Notes
- attempted `cargo test -p codex-core --locked` and `cargo test -p
codex-core auth_refresh --locked`, but both ran out of disk while
linking `codex-core` test binaries in the local environment
2026-03-26 13:34:02 -07:00
Michael Bolin
e36ebaa3da fix: box apply_patch test harness futures (#15835)
## Why

`#[large_stack_test]` made the `apply_patch_cli` tests pass by giving
them more stack, but it did not address why those tests needed the extra
stack in the first place.

The real problem is the async state built by the `apply_patch_cli`
harness path. Those tests await three helper boundaries directly:
harness construction, turn submission, and apply-patch output
collection. If those helpers inline their full child futures, the test
future grows to include the whole harness startup and request/response
path.

This change replaces the workaround from #12768 with the same basic
approach used in #13429, but keeps the fix narrower: only the helper
boundaries awaited directly by `apply_patch_cli` stay boxed.

## What Changed

- removed `#[large_stack_test]` from
`core/tests/suite/apply_patch_cli.rs`
- restored ordinary `#[tokio::test(flavor = "multi_thread",
worker_threads = 2)]` annotations in that suite
- deleted the now-unused `codex-test-macros` crate and removed its
workspace wiring
- boxed only the three helper boundaries that the suite awaits directly:
  - `apply_patch_harness_with(...)`
  - `TestCodexHarness::submit(...)`
  - `TestCodexHarness::apply_patch_output(...)`
- added comments at those boxed boundaries explaining why they remain
boxed

## Testing

- `cargo test -p codex-core --test all suite::apply_patch_cli --
--nocapture`

## References

- #12768
- #13429
2026-03-26 17:32:04 +00:00