mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
a287c5dffdc96855e61a75526e86428fee6663e4
343 Commits
-
skills: make backend plugin skills invocable without an executor (#27387)
## Why #27198 made the extension-owned `codex_apps` MCP connection the hosted plugin runtime, but its `mcp/skill` resources still bypassed the skills extension. App-server could list and read those resources through generic MCP APIs, but a thread with no selected environment did not expose them in the model's skills catalog or load their `SKILL.md` through `$skill`. Hosted skills should stay remote while using the same typed catalog, source authority, deduplication, bounded contextual catalog, and selected-skill prompt injection as host and executor skills. They should not be downloaded or exposed as ambient filesystem paths. ## What changed - Add a session-scoped `McpResourceClient` over the replaceable MCP connection manager so resource list/read calls follow startup and refresh replacements. - Add a `BackendSkillProvider` that pages `codex_apps` resources, accepts bounded and validated `mcp/skill` entries, and reads a selected skill's `SKILL.md` through the same MCP connection. - Register the remote provider in app-server and include it in the skills catalog even when a thread has no selected capability roots or executor. - Contribute hosted skill metadata through the bounded `AvailableSkillsInstructions` developer-context path, exclude remote entries from per-turn catalog injection, and classify `<skills>` messages as contextual developer content so rollback can trim and rebuild them correctly. ## Testing - Extend the app-server MCP resource integration test with `environments: []` to exercise two-page discovery, filter a non-`mcp/skill` resource, verify the escaped developer catalog entry and user-role `<skill>` fragment containing the fetched `SKILL.md`, and preserve generic MCP resource reads. - Add core event-mapping coverage that classifies `<skills>` developer messages as contextual history.
jif ·
2026-06-11 11:28:16 +02:00 -
[codex] Compact when comp_hash changes (#27520)
## Summary - snapshot `comp_hash` into `TurnContext` when the turn is created and use that snapshot as the downstream source of truth - persist the turn hash in rollout context and recover it into previous-turn settings during resume and fork replay - compact existing history with the previous model only when both adjacent turns provide hashes and the values differ - record `comp_hash_changed` as the compaction reason - cover ordinary transitions, resume, and missing-hash compatibility with end-to-end tests ## Why History produced under one compaction-compatible model configuration may not be safe to carry directly into another. Compacting at the turn boundary converts that history before context updates and the new user message are added. Persisting the turn snapshot in `TurnContextItem` makes the same protection work after resuming a rollout. A missing hash is not treated as evidence of incompatibility. `None → Some`, `Some → None`, and `None → None` do not trigger compaction; only `Some(previous) → Some(current)` with unequal values does. ## Stack - depends on #27532 - #27532 is based directly on `main` ## Testing - `just test -p codex-core pre_sampling_compact_` — 6 passed - `just test -p codex-core turn_context_item_uses_turn_context_comp_hash_snapshot` — passed - `just fix -p codex-core -p codex-protocol -p codex-analytics -p codex-models-manager`
Ahmed Ibrahim ·
2026-06-11 04:11:26 +00:00 -
[codex] Add new context window tool (#27488)
## Why The token budget feature tells the model how much room remains in the current context window. When the model decides the current window is no longer useful, it needs a way to ask Codex to start over with a fresh context window without spending tokens on a compaction summary. This PR adds that model-requestable escape hatch on top of #27438. ## What changed - Added a direct-model-only `new_context` tool behind `Feature::TokenBudget`. - Stores the tool request on `AutoCompactWindow` and consumes it after sampling so the next follow-up request in the same turn starts in the new window. - Starts the new window as a no-summary compaction checkpoint that contains only fresh initial context, not preserved conversation history. - Keeps the new window aligned with token-budget startup context, including the `Current context window Z` message. - Added integration coverage and a snapshot showing the same-turn `new_context` flow into a fresh full-context follow-up request. ## Validation - `just test -p codex-core token_budget`
pakrym-oai ·
2026-06-11 03:39:07 +00:00 -
[codex] Add token budget context feature (#27438)
## Why The model should be able to see bounded context-window budget metadata when the `token_budget` feature is enabled. The full-window message is only injected with full context, while normal turns get a smaller follow-up only when reported usage first crosses a budget threshold. ## What changed - Added the `TokenBudget` feature flag. - Added `<token_budget>` developer fragments for full context-window metadata and current-window remaining tokens. - Inserted the threshold message during normal turn handling by comparing token usage before and after sampling, avoiding persistent threshold bookkeeping. - Added core integration coverage for full-context-only metadata and 25/50/75 percent threshold messages. ## Verification - `just test -p codex-core token_budget` - `git diff --check`
pakrym-oai ·
2026-06-10 20:07:06 -07:00 -
core: resize all history images behind a feature flag (#27247)
## Summary Adds complete client-side image preparation behind the default-off `resize_all_images` feature flag. When enabled, local image producers defer decoding and resizing. Images are prepared centrally before insertion into conversation history, covering user input, `view_image`, and structured tool-output images. ## Behavior - Processes base64 `data:` images in messages and function/custom tool outputs. - Leaves non-data URLs, including HTTP(S) URLs, unchanged. - Applies image-detail budgets: - `high` and omitted: 2048px maximum dimension and 2.5K 32px patches. - `original`: 6000px maximum dimension and 10K 32px patches. - `auto`: uses the same 2048px / 2.5K-patch budget as high. - `low`: unsupported and replaced with an actionable placeholder. - Preserves original image bytes when no resize or format conversion is needed. - Enforces the shared 1 GiB encoded and decoded data-URL sanity limits. - Replaces only an image that fails preparation, preserving sibling content and tool-output metadata. - Uses bounded placeholders distinguishing generic processing failures, oversized images, and unsupported `low` detail. - Prepares resumed and forked history before installing it as live history without modifying persisted rollouts. ## Flag-Off Behavior When `resize_all_images` is disabled: - Existing local user-input and `view_image` processing remains unchanged. - Existing decoding and error behavior remains unchanged. - Arbitrary tool-output images are not processed. - HTTP(S) image URLs continue to be forwarded unchanged. #### [git stack](https://github.com/magus/git-stack-cli) - ✅ `1` https://github.com/openai/codex/pull/27245 - 👉 `2` https://github.com/openai/codex/pull/27247 - ⏳ `3` https://github.com/openai/codex/pull/27246 - ⏳ `4` https://github.com/openai/codex/pull/27266
Curtis 'Fjord' Hawthorne ·
2026-06-10 19:21:24 -07:00 -
Forward standalone assistant output to realtime (#27319)
## Why When a realtime session is open without an active frontend-model handoff, completed Codex assistant messages are currently dropped. That prevents the frontend model from hearing orchestrator preambles and final responses produced by typed turns or other non-handoff work, which makes the two models present as disconnected personas. Active handoffs already forward each completed assistant message, including preambles. This change leaves those V1 and V2 paths intact and fills only the no-active-handoff gap. ## What changed - Send standalone V1 assistant messages through `conversation.handoff.append` with a stable synthetic handoff ID - Send standalone V2 assistant messages as normal `[BACKEND]` `conversation.item.create` message items, then enqueue `response.create` so the frontend model responds - Preserve the existing active V1 and V2 transport and completion behavior - Continue excluding user messages from realtime mirroring - Skip empty output and cap each complete context injection, including its V2 prefix, at 1,000 tokens - Add end-to-end coverage for both wire formats, V2 response creation, preambles, final responses, and truncation ## Test plan - CI
guinness-oai ·
2026-06-10 21:32:29 +00:00 -
[codex] Store compact window id in rollout (#27264)
## Why Compaction window identity is part of session history, not model-client transport state. Persisting it with the compacted rollout item lets resumed threads continue from the reconstructed window without keeping mutable window state on `ModelClient`. ## What changed - Added `window_id` to `CompactedItem` and stamp it when `replace_compacted_history` installs compacted history. - Moved auto-compact window id ownership into `AutoCompactWindow` / `SessionState`; `ModelClient` now receives the request window id from callers instead of storing it. - Returned `window_id` from rollout reconstruction for resume. Reconstruction uses the newest surviving compacted item's stored `window_id` when present, and falls back to the legacy compacted-item count when it is absent. - Kept fork startup at the fresh default window id and updated direct model-client tests to pass explicit test window ids. ## Validation - `cargo check -p codex-core --tests`
pakrym-oai ·
2026-06-10 08:47:16 -07:00 -
Use latest-wins MCP manager replacement (#27259)
## Summary We originally addressed startup prewarming holding the read side of `RwLock<McpConnectionManager>` by snapshotting tool-list state. Review feedback identified the broader ownership problem: the outer synchronization should only publish or retrieve the current manager, while MCP operations rely on the manager's internal synchronization. A follow-up preserved operation retirement with a separate gate, but further review questioned whether that synchronization was actually required and whether we could support latest-wins replacement instead. This PR now stores the current MCP manager in `ArcSwap`. Each operation uses `load_full()` to obtain an owned `Arc<McpConnectionManager>`, then performs MCP I/O without retaining the publication mechanism. Refresh cancels obsolete startup work, constructs a replacement, and atomically publishes it. New operations see the latest manager, while operations that already loaded the previous manager retain a valid handle. Refresh happens at a turn boundary, so there should be no active user tool calls to drain. Git history supports dropping the outer `RwLock`. It was introduced in `03ffe4d595` on November 17, 2025 for non-blocking MCP startup: the session published an empty manager, startup initialized that same object while holding the write lock, and readers waited for initialization. `7cd2e84026` on February 19, 2026 removed that two-phase initialization in favor of constructing a fresh manager and swapping it in, explicitly noting that `Option` or `OnceCell` could replace the placeholder design. Hot reload later reused the existing lock to publish a replacement, but I found no indication that the lock was introduced to guarantee in-flight tool calls finish before refresh or shutdown. Terminal shutdown remains separate from refresh: it aborts startup prewarming and active tasks before shutting down the current manager, so tool calls may be interrupted and no model WebSocket work continues after shutdown. Focused regression coverage exercises pending tool-list cancellation, deferred refresh, and startup-prewarm shutdown.
Charlie Marsh ·
2026-06-10 08:33:21 -07:00 -
Remove async-trait from extension contributors (#27383)
## Why Extension contributors are registered behind `dyn Trait` objects, so native `async fn`/RPITIT methods would make these traits non-object-safe. Spell out the boxed, `Send` future contract directly so `extension-api` no longer needs `async-trait` while retaining the existing runtime model. ## What changed - add a shared `ExtensionFuture` alias and use it for asynchronous contributor methods - migrate production and test implementations to return `Box::pin(async move { ... })` - remove `async-trait` dependencies where they are no longer used, keeping it dev-only where unrelated test executors still require it ## Behavior No behavior change is intended. Contributor futures remain boxed, `Send`, dynamically dispatched, and lazily executed; cancellation and callback ordering stay unchanged. ## Testing - `just test -p codex-extension-api` (11 passed) - affected extension crates (64 passed) - targeted `codex-core` contributor tests (14 passed) - `just fmt` - `just bazel-lock-update` - `just bazel-lock-check` A broad local `codex-core` run compiled successfully but encountered unrelated sandbox and missing test-binary fixture failures; CI will run the full checks.jif ·
2026-06-10 14:31:09 +02:00 -
Use plugin-service MCP as the hosted plugin runtime (#27198)
## Stack - Base: #27191 - This PR is the third vertical and should be reviewed against `jif/external-plugins-2`, not `main`. ## Why #27191 moves the host-owned Apps MCP registration behind an extension contributor, but deliberately preserves the existing endpoint-selection feature while that contribution contract lands. App-server can therefore resolve the server through extensions, yet the hosted plugin endpoint is still selected through temporary `apps_mcp_path_override` plumbing. That is not the long-term plugin model. A plugin can bundle skills, connectors, MCP servers, and hooks, and those components do not all need the same source or execution environment. In particular, an authenticated HTTP MCP server can expose plugin capabilities directly from a backend without an executor or an orchestrator filesystem. This PR completes that hosted vertical. App-server's MCP extension now owns the aggregate hosted plugin runtime at `/ps/mcp`. Connector actions continue to arrive as MCP tools, while backend-provided skills arrive as MCP resources and use Codex's existing resource list/read paths. No second backend client, skill filesystem, or generic plugin activation framework is introduced. The backend route remains the hosted implementation. This change replaces Codex's temporary endpoint-selection mechanism, not the service behind the endpoint. ## What changed ### Hosted plugin runtime The MCP extension now contributes `codex_apps` as the hosted plugin runtime rather than as a configurable Apps endpoint: - `https://chatgpt.com` resolves to `https://chatgpt.com/backend-api/ps/mcp`; - a bare custom ChatGPT base resolves to `/api/codex/ps/mcp`; - the existing product-SKU header and ChatGPT authentication behavior are preserved; - executor availability is never consulted for this streamable HTTP transport. The same MCP connection carries both component shapes supported by the hosted endpoint: - connector actions are discovered and invoked as MCP tools; - hosted skills are enumerated and read as MCP resources through the existing `list_mcp_resources` and `read_mcp_resource` paths. This keeps component access in the subsystem that already owns the protocol instead of downloading backend skills into an orchestrator filesystem or inventing a parallel hosted-skill client. ### Explicit runtime ordering `McpManager` now resolves the reserved `codex_apps` entry in three ordered phases: 1. install the legacy Apps fallback for compatibility; 2. apply ordered extension `Set` or `Remove` overlays; 3. apply the final ChatGPT-auth gate without synthesizing the server again. This ordering is important: - an ordinary configured or plugin MCP server cannot claim the auth-bearing `codex_apps` name; - an extension-contributed hosted runtime wins over the fallback; - an extension `Remove` remains authoritative; - a host without the MCP extension retains the legacy Apps endpoint and current local-only behavior. The temporary `legacy_apps_mcp_loader_enabled` coordination flag is no longer needed. ### Remove the path override The `apps_mcp_path_override` feature and its runtime plumbing are removed, including: - the feature registry entry and structured feature config; - `Config` and `McpConfig` fields; - config schema output; - config-lock materialization; - URL override handling in `codex-mcp`. Existing boolean and structured forms still deserialize as ignored compatibility input. They are omitted from new serialized config, and config-lock comparison normalizes the removed input so older locks remain replayable. ### App-server coverage App-server MCP fixtures now serve the hosted route at `/api/codex/ps/mcp`. Existing resource-read and tool/elicitation flows therefore exercise the extension-owned endpoint rather than succeeding through the legacy fallback. The stack also adds the missing `codex_chatgpt::connectors` re-export for the manager-backed connector helper introduced in #27191. ## Compatibility - App-server installs the extension and uses `/ps/mcp` for the hosted runtime. - CLI and other hosts that do not install the extension retain the legacy Apps endpoint. - Apps disabled or non-ChatGPT authentication removes `codex_apps` from the effective runtime view. - Existing local plugins, local skills, executor-selected skills, configured MCP servers, and MCP OAuth behavior are otherwise unchanged. - Backend plugin enablement remains account/workspace state owned by the hosted endpoint; this PR does not add thread-local backend plugin selection. ## Architectural fit The stack now proves two independent runtime shapes: 1. #27184 resolves filesystem-backed skills through the executor that owns a selected root. 2. #27191 and this PR resolve a backend-hosted HTTP MCP through an extension with no executor. Together they preserve the intended separation: - selection identifies a plugin/root when explicit selection is needed; - each component's owning extension resolves its concrete access mechanism; - execution stays with the runtime required by that component; - existing skills, MCP, connector, and hook subsystems remain the downstream consumers. ## Planned follow-ups 1. **Executor stdio MCP:** selecting an executor plugin registers a manifest-declared stdio MCP server and executes it in the environment that owns the plugin. 2. **Optional backend selection:** only if CCA needs thread-local selection distinct from backend account/workspace enablement, add a concrete backend-owned capability location and surface those selected skills through the skills catalog. 3. **Connector metadata and hooks:** activate those plugin components through their existing owning subsystems, with executor hooks remaining environment-bound. 4. **Propagation and persistence:** define explicit resume, fork, subagent, refresh, and environment-removal semantics once selected roots have multiple real consumers. 5. **Local convergence:** migrate legacy local skill, MCP, connector, and hook paths behind their owning extensions one vertical at a time, then remove duplicate core managers and compatibility plumbing after parity. ## Verification Coverage in this change exercises: - extension-owned `/backend-api/ps/mcp` registration without an executor; - preservation of the legacy endpoint in hosts without the extension; - extension `Set` and `Remove` precedence over the legacy fallback; - ChatGPT-auth gating for the reserved server; - hosted MCP resource reads with and without an active thread; - connector tool invocation and MCP elicitation through the hosted route; - ignored boolean and structured forms of the removed path override; - config-lock replay compatibility for the removed feature. `cargo check -p codex-features -p codex-mcp-extension -p codex-app-server` passes. Tests and Clippy were not run locally under the current development instruction; CI provides the full validation pass.
jif ·
2026-06-10 12:54:21 +02:00 -
[codex] Make MCP connection startup fallible (#27261)
## Why Required MCP server startup was enforced in `Session::new` after `McpConnectionManager` had already created the clients. That split let other manager construction paths bypass the same requirement and exposed manager internals solely so the session could validate them. Keeping required-server readiness in the constructor gives every caller one consistent startup contract. ## What changed - make `McpConnectionManager::new` return `anyhow::Result<Self>` and fail when an enabled, required server cannot initialize - pass the startup cancellation token into the constructor so required-server waits remain cancellable - propagate constructor failures through resource reads, connector discovery, and MCP status collection - preserve the active manager and cancellation token when a refreshed replacement fails - keep required-startup failure collection private and cover the constructor error contract directly ## Validation - updated the focused connection-manager test to assert the complete required-server startup error - local tests not run; relying on CI
Ahmed Ibrahim ·
2026-06-10 00:17:58 -07:00 -
Add spans to run_turn (#27107)
## Why Codex app-server latency traces do not granularly cover turn orchestration, sampling-request preparation, and tool-loading work. These spans help separate local coordination/setup costs from model streaming and tool execution. ## What changed - Add `run_turn.*` spans around sampling-request input preparation and post-sampling state collection - Add function-level trace spans around turn setup, hook execution, compaction, prompt construction, and MCP tool exposure - Add `built_tools.*` spans around plugin loading and discoverable-tool loading ## Verification Trigger Codex rollout and observe new spans are included
mchen-oai ·
2026-06-10 04:41:06 +00:00 -
Stop mirroring Codex user input into realtime (#27116)
## Why The realtime frontend model and the backing Codex thread should present one coherent assistant. Raw typed messages, steers, and worker reports belong to the orchestrator; the frontend model should receive the orchestrator's user-facing result rather than a second copy of those inputs. Today normal `turn/start` input is automatically inserted into the realtime conversation, while `turn/steer` is not. Besides creating inconsistent context, this can make the frontend model react independently before Codex has produced the response it should speak. ## What changed - Remove automatic accepted-user-input mirroring into realtime - Remove the mirror-only echo-suppression flag and dead V2 prefix helper - Preserve explicit app-to-realtime text injection and FEM-to-Codex delegation - Replace the positive mirror tests and obsolete snapshots with a negative routing regression test ## Test plan - `cargo test -p codex-core conversation_user_text_turn_is_not_sent_to_realtime` - `cargo test -p codex-core conversation_startup_context_is_truncated_and_sent_once_per_start` - `cargo test -p codex-core inbound_handoff_request_starts_turn`
guinness-oai ·
2026-06-09 15:20:01 -07:00 -
Route hosted Apps MCP through extensions (#27191)
## Stack - Base: #27184 - This PR is the second vertical and should be reviewed against `jif/external-plugins-1`, not `main`. ## Why CCA is moving toward a split runtime where the orchestrator may have no filesystem or executor, but it still needs to activate remotely hosted plugin components. HTTP MCP servers are the simplest complete example: they need configuration and host authentication, but they do not need an executor process. The Apps MCP endpoint is currently synthesized by a special-purpose loader inside the MCP runtime. That works locally, but it leaves hosted MCP activation outside the extension model being established in #27184. It also makes the Apps path a poor foundation for plugins whose skills, MCP servers, connectors, and hooks may come from different sources or execute in different places. This PR moves that one behavior behind an extension-owned contribution while preserving the existing local fallback. It deliberately does not introduce a generic plugin activation framework. ## What changed ### MCP extension contribution `codex-extension-api` gains an ordered `McpServerContributor` contract. A contributor returns typed `Set` or `Remove` overlays for MCP server configuration; later contributors win for the names they own. The contract stays at the existing MCP configuration boundary. Extensions do not create a second connection manager or transport abstraction. ### Hosted Apps MCP extension A new `codex-mcp-extension` contributes the reserved `codex_apps` server from the existing Apps feature, ChatGPT base URL, path override, and product SKU configuration. When `apps_mcp_path_override` is enabled for `https://chatgpt.com`, the resulting streamable HTTP endpoint is `https://chatgpt.com/backend-api/ps/mcp`. The existing ChatGPT-auth gate remains authoritative, so this server can run in an orchestrator-only process without being exposed for API-key sessions. ### One resolved runtime view `McpManager` now distinguishes three views: - **configured:** config- and plugin-backed servers before extension overlays; - **runtime:** configured servers plus host-installed extension contributions; - **effective:** runtime servers after auth gating and compatibility built-ins. App-server installs the hosted MCP extension and uses the runtime view for thread startup, refresh, status, threadless resource reads, connector discovery, and MCP OAuth lookup. This keeps `mcpServer/oauth/login` consistent with the servers exposed by the other MCP APIs. The hosted Apps server itself continues to use existing ChatGPT host authentication rather than MCP OAuth. ## Compatibility Hosts that do not install the MCP extension retain the existing Apps MCP synthesis path. This preserves current local-only, CLI, and standalone-host behavior while app-server exercises the extension path. Disabling Apps removes the reserved `codex_apps` entry, and losing ChatGPT auth removes it from the effective runtime view. Executor availability is not consulted for this HTTP transport. ## Follow-ups The next vertical will resolve a manifest-declared stdio MCP server from an executor-selected plugin root and execute it in the environment that owns that root. Later verticals can add backend-owned skills, connector metadata, hooks, durable selection semantics, and incremental local convergence without changing the component-specific runtime boundaries introduced here. ## Verification Focused coverage was added for: - contributing the hosted Apps MCP at `/backend-api/ps/mcp` without an executor; - requiring ChatGPT auth in the effective runtime view; - removing a reserved configured Apps server when the Apps feature is disabled. `cargo check -p codex-app-server -p codex-mcp-extension -p codex-extension-api -p codex-mcp` passed. Tests and Clippy were not run locally under the current development instruction; CI provides the full validation pass.
jif ·
2026-06-09 22:44:16 +02:00 -
[codex-analytics] add extensible feature thread sources (#27063)
## Why - `ThreadSource` currently defines a closed set of core-owned values - Product features also create threads for background or scheduled work - Adding every product-specific value to the core enum would require repeated `codex-rs` protocol changes - Feature-backed values let product callers provide precise attribution while preserving the existing core classifications ## What Changed - Adds `ThreadSource::Feature(String)` for app-owned thread source values - Represents all app-server v2 thread sources as scalar strings, so a feature source is supplied as `"automation"` - Persists and emits the feature's plain string label, so `"automation"` produces `thread_source="automation"` in analytics - Keeps `user`, `subagent`, and `memory_consolidation` as explicit core-owned values and regenerates the app-server schemas and TypeScript bindings ## Verification - `just write-app-server-schema` - `cargo check --workspace` - `just test -p codex-protocol feature_thread_source_serializes_as_its_app_owned_label` - `just test -p codex-app-server-protocol thread_sources_round_trip_as_scalar_labels` - `cargo test -p codex-analytics thread_initialized_event_serializes_expected_shape` - `just fmt`
marksteinbrick-oai ·
2026-06-09 12:27:10 -07:00 -
Load selected executor skills through extensions (#27184)
## Why CCA is moving toward a split runtime where the orchestrator may not have a filesystem, while executors can expose preinstalled plugins and skills. A thread therefore needs to select capabilities without asking app-server or core to interpret executor-owned paths through the orchestrator's filesystem. The longer-term model is broader than executor skills: - A plugin is a bundle of skills, MCP servers, connectors/apps, and hooks. - A plugin root can be local, executor-owned, or hosted by a backend. - Components inside one plugin can use different access and execution mechanisms. A skill may be read from a filesystem or through backend tools; an HTTP MCP server can run without an executor; a stdio MCP server or hook needs an execution environment. - Core should carry generic extension initialization data. The extension that owns a component should discover it, expose it to the model, and invoke it through the appropriate runtime. This PR establishes that architecture through one complete vertical: selecting a root on an executor, discovering the skills beneath it, exposing those skills to the model, and reading an explicitly invoked `SKILL.md` through the same executor. ## Contract `thread/start` gains an experimental `selectedCapabilityRoots` field: ```json { "selectedCapabilityRoots": [ { "id": "deploy-plugin@1", "location": { "type": "environment", "environmentId": "workspace", "path": "/opt/codex/plugins/deploy" } } ] } ``` The root is intentionally not classified as a "plugin" or "skill" in the API. It can point at a standalone skill, a directory containing several skills, or a plugin containing skills and other components. This PR only teaches the skills extension how to consume it; later extensions can resolve MCP, connector, and hook components from the same selection. The platform-supplied `id` is stable selection identity. The location says which runtime owns the root and gives that runtime an opaque path. App-server does not inspect or canonicalize the path. ## What changed ### Generic thread extension initialization App-server converts selected roots into `ExtensionDataInit`. Core carries that generic initialization value until the final thread ID is known, then creates thread-scoped `ExtensionData` before lifecycle contributors run. This keeps `Session` and core independent of the capability-selection contract. The initialization value is consumed during construction; it is not retained as another long-lived `Session` field. ### Executor-backed skills The skills extension now owns an `ExecutorSkillProvider` that: - resolves the selected environment through `EnvironmentManager` - discovers, canonicalizes, and reads skills through that environment's `ExecutorFileSystem` - contributes the bounded selected-skill catalog as stable developer context - reads an explicitly invoked skill body through the authority that listed it - warns when an environment or root is unavailable - never falls back to the orchestrator filesystem for an executor-owned root Skill catalog and instruction fragments have hard byte bounds, which also bound them below the 10K-token per-item context limit. If a selected executor skill has the same name as a legacy local skill, the executor selection owns that invocation and the local body is not injected a second time. Existing local and bundled skill loading remains in place. Omitting `selectedCapabilityRoots` therefore preserves current local-only behavior. ## Current semantics - Only environment-owned locations are represented in this first contract. - Roots are resolved by the destination extension, not by app-server or core. - An unavailable executor or invalid root produces a warning and no capabilities from that root; it does not trigger a local-filesystem fallback. - Selection applies to a newly started active thread. - MCP servers, connectors, and hooks beneath a selected plugin root are not activated yet. - Selection is not yet persisted or inherited across resume, fork, or subagent creation. Existing local capabilities continue to behave as they do today in those flows. ## Planned vertical follow-ups 1. **Hosted HTTP MCP:** add an extension-backed HTTP MCP source that works without an executor, then replace the special-purpose MCP plugins loader with that implementation. 2. **Executor MCP:** register and execute stdio MCP servers through the environment that owns the selected plugin root. 3. **Backend skills:** add a hosted skill source whose catalog and bodies are accessed through extension tools rather than a filesystem. 4. **Connectors and hooks:** activate those components through their owning extensions, using the same selected-root boundary and component-specific runtime. 5. **Durable selection:** define the desired-selection lifecycle, persist it, and make resume, fork, and subagent inheritance explicit rather than accidental. 6. **Local convergence:** incrementally route existing local plugin, skill, and MCP loading through the same extension model while preserving current local behavior. Each follow-up remains reviewable as an end-to-end capability. The platform selects roots, generic thread extension data carries the selection, and the owning extension resolves and operates its component. ## Verification Coverage added for: - app-server end-to-end discovery and explicit invocation of a skill inside an executor-selected plugin root - exclusive invocation when a selected executor skill collides with a local skill name - executor filesystem authority for discovery, canonicalization, and reads - thread extension initialization before lifecycle contributors run - stable executor catalog context, explicit invocation, context rebuilding, hidden skills, and preserved host/remote catalog behavior Targeted protocol, core-skills, skills-extension, core lifecycle, and app-server executor-skill tests were run during development.jif ·
2026-06-09 19:51:54 +02:00 -
multi-agent: add path-based v2 activity tracking (#27007)
## Why Multi-agent v2 identifies agents by canonical paths, but its tool handlers still emitted the larger legacy collaboration begin/end events built around nickname and role metadata. App-server, rollout-trace, analytics, and TUI consumers therefore lacked one compact path-based completion signal that behaved consistently across live events and replay. The TUI also needs a bounded `/agent` status surface for v2 agents. It should use recent local activity for previews, refresh liveness without loading full histories, and keep the legacy picker available when no path-backed v2 agent is known. ## What changed - Replace the v2 `spawn_agent`, `send_message`, `followup_task`, and `interrupt_agent` legacy lifecycle emissions with a success-only `SubAgentActivity` event. The event records the tool call ID, occurrence time, affected thread, canonical agent path, and `started`, `interacted`, or `interrupted` kind. - Expose the activity as a completion-only app-server v2 `subAgentActivity` thread item in live notifications and reconstructed history, regenerate the protocol schemas, and count it in sub-agent tool analytics. - Track canonical paths from live activity and loaded-thread metadata in the TUI, and render the activity in live and replayed transcripts. - Make `/agent` list running path-backed agents with summaries from bounded local event buffers. Each summary is capped at 240 graphemes, the scan is capped at six recent items, only the last three wrapped lines are shown, and command output is omitted. Liveness falls back to metadata-only `thread/read` when local turn state is unavailable. - Persist the activity as a terminal rollout-trace runtime payload and reduce it to the corresponding spawn, send, follow-up, or close interaction edge. `interrupt_agent` is classified as a close-edge operation. - Preserve the legacy picker when no path-backed v2 agent is known. ## Compatibility App-server v2 clients that consumed `collabAgentToolCall` begin/end pairs for these tools must handle the new completion-only `subAgentActivity` item. Legacy v1 collaboration behavior is unchanged. ## Screenshot <img width="684" height="288" alt="Screenshot 2026-06-08 at 15 40 47" src="https://github.com/user-attachments/assets/194b3cd0-619d-45fb-b587-cf3e2b1b8a1d" /> ## Testing - `just test -p codex-app-server-protocol` - `just test -p codex-rollout-trace` - Added focused coverage for activity analytics, terminal trace serialization, spawn-edge reduction, `interrupt_agent` classification, TUI status rendering without aggregated command output, and clearing stale running state after a completed turn.
jif ·
2026-06-09 12:14:48 +02:00 -
[codex] Remove remote compaction failure log (#27106)
## Why `log_remote_compact_failure` was the only consumer of the compact-request logging payload and most of the token-usage breakdown fields. Once that failure log is removed, keeping the surrounding carrier types leaves dead plumbing in the compaction path and context manager. ## What changed - Remove `log_remote_compact_failure`, `CompactRequestLogData`, and the v2 wrapper that only fed that log. - Let both remote compaction implementations return the original compaction error directly. - Replace `TotalTokenUsageBreakdown` with a narrow helper that returns only the remaining value needed by compaction analytics. - Keep `estimate_response_item_model_visible_bytes` private to the context manager implementation. ## Validation - `cargo check -p codex-core`
pakrym-oai ·
2026-06-08 19:23:35 -07:00 -
Boyang Niu ·
2026-06-09 00:38:35 +00:00 -
Pair thread environment settings (#26687)
## Why Thread cwd and environment selections are a single logical setting in core: updating one without the other can silently desynchronize the next-turn execution context. This change makes that relationship explicit in the internal thread settings flow while preserving the existing app-server public API shape. ## What changed - Moved the cwd/environment pair through internal `ThreadSettingsOverrides.environment_settings` instead of a top-level internal `cwd` field. - Kept `thread/settings/update` public params unchanged, with app-server translating top-level `cwd` into the paired internal settings shape. - Moved `Op::UserInput` environment overrides into thread settings so user turns and settings updates use the same core path. - Updated core, app-server, MCP, memories, sample, and test callsites to construct the paired settings shape. ## Verification - `git diff --check` - Local test run starting after PR creation.
pakrym-oai ·
2026-06-08 13:55:15 -07:00 -
feat: count V2 concurrency by active execution (#26969)
## Why Multi-Agent V2 concurrency should count active non-root turns, not resident or durable agent threads. The limit is intentionally best effort: admission checks are synchronous, but concurrent successful checks may overshoot slightly. ## What changed - Keep one root-derived execution limit on the shared `AgentControl`. - Count active V2 subagent turns with an RAII guard owned by `RunningTask`. - Check capacity before spawning or starting an idle agent, including direct app-server `turn/start` submissions. - Preserve queued delivery for agents that are already running. - Exempt automatic idle continuations so `/goal` work is not dropped when capacity is temporarily full. - Keep root and V1 turns outside this limiter. ## Test coverage - `execution_guards_count_active_v2_subagent_turns` - `execution_guards_ignore_root_and_v1_turns` - `v2_nested_spawn_checks_shared_active_execution_capacity`
jif ·
2026-06-08 14:21:28 +02:00 -
[2 of 2] Finish moving goal runtime to extension (#26548)
## Stack 1. [#26547](https://github.com/openai/codex/pull/26547) - [1 of 2] Align goal extension with core behavior 2. [#26548](https://github.com/openai/codex/pull/26548) - [2 of 2] Move goal runtime to extension ## Why This PR completes the switch of the goal behavior to the extension-backed runtime and removes the old core goal implementation. ## What Changed - Installs the goal extension for app-server `ThreadManager` sessions. - Routes app-server thread goal `get`, `set`, and `clear` through `GoalService`. - Uses thread-idle lifecycle emission after goal resume and snapshot ordering so the extension can decide whether to continue the goal. - Forwards extension goal updates through a FIFO async app-server notification path so backpressure does not drop them or reorder updates. - Keeps review turns from enabling goal runtime behavior. - Plans extension tools before dynamic tools so built-in goal tool names keep their old precedence when goals are enabled. - Removes the old core goal runtime, core goal tool handlers, and core goal tool specs. - Updates tests that were coupled to the core-owned goal runtime while leaving the legacy `<goal_context>` compatibility path in core for old threads. - Removes the stale cargo-shear ignore now that `codex-goal-extension` is used by the workspace. - Keeps realtime event matching exhaustive after removing the old goal-specific realtime text path. ## Validation - Ran manual `/goal` runs in TUI. Validated time accounting matched wall-clock time and goal lifecycle state transitions.
Eric Traut ·
2026-06-05 14:17:30 -07:00 -
[codex] Add turn profiling analytics (#26484)
## Summary Add flat profiling fields to `codex_turn_event` so analytics can explain where turn wall-clock time is spent without changing tool execution behavior. The profile reports: - time before the first sampling request - sampling time across all attempts and follow-ups - overhead between sampling requests - time blocked in the post-sampling tool drain - time after the final sampling request - sampling request and retry counts ## Implementation - Extend the existing turn timing state with constant-memory phase accounting and one RAII phase guard. - Observe sampling and the existing post-sampling drain only at turn orchestration boundaries. - Keep tool runtime, tool futures, response item handling, and turn lifecycle values unchanged. - Add the profiling fields directly to the existing analytics turn event without changing app-server protocol or rollout persistence. - Use the existing turn `status` to distinguish completed, failed, and interrupted profiles. Exact sampling/tool overlap is intentionally omitted because measuring tool completion accurately would require hooks in the tool execution path. ## Validation - Add app-server end-to-end coverage for a single-sampling turn with no blocking tool work. - Add app-server end-to-end coverage for `request_user_input` blocking followed by a second sampling request. - CI is running on the PR; tests were not executed locally per repository guidance.
Ahmed Ibrahim ·
2026-06-05 11:27:10 -07:00 -
[codex] Respect Windows sandbox backend in exec policy (#26307)
## Why Windows managed filesystem permissions can now be backed by a real Windows sandbox. `exec-policy` was still treating the managed read-only policy shape as if there were never a sandbox backend, so benign unmatched commands such as PowerShell directory listings could be rejected with `blocked by policy` even when `windows.sandbox` was enabled. The inverse case still needs to stay conservative: when the Windows sandbox backend is disabled, managed filesystem restrictions are only configuration intent, not an enforced filesystem boundary. That applies to writable-root restricted profiles too, not just read-only profiles. ## What Changed - Thread the effective `WindowsSandboxLevel` into exec-policy approval decisions for shell, unified exec, and intercepted shell exec paths. - Treat managed restricted filesystem profiles as lacking sandbox protection only on Windows when `WindowsSandboxLevel::Disabled`. - Exclude full-disk-write profiles from that no-backend path because they do not rely on filesystem sandbox enforcement. - Remove the cwd-sensitive read-only heuristic and the now-stale cwd plumbing from exec-policy approval contexts. - Add Windows coverage for both enabled-sandbox and disabled-backend behavior, including a writable-root managed profile. ## Validation - Added/updated `exec_policy` coverage for managed filesystem restrictions, full-disk-write exclusion, enabled Windows sandbox behavior, and disabled-backend read-only/writable-root behavior. - `just test -p codex-core exec_policy` — 100 passed, 10 leaky - Empirical local `codex exec` probe with `--sandbox read-only -c 'windows.sandbox="unelevated"'`: PowerShell directory listing completed successfully. - Disabled-backend control with Windows sandbox cleared: the same command was rejected with `blocked by policy`.
iceweasel-oai ·
2026-06-05 11:20:52 -07:00 -
Make turn diff tracker multi-env aware (#26433)
## Why Turn diffs were tracked as one flat set of absolute paths. In multi-environment turns, local and remote environments can report the same path while representing different filesystems, so a single path key can collapse distinct changes or attribute them to the wrong environment. The environment name is **NOT** included in the generated unified diff. This can come later.
pakrym-oai ·
2026-06-05 17:31:22 +00:00 -
Require absolute cwd in thread settings (#26532)
## Why Thread settings cwd overrides are expected to be resolved before they enter core. Keeping this boundary as a plain `PathBuf` made it easy for core/session code to keep fallback normalization and relative-path resolution logic in places that should only receive an already-resolved cwd. This is intentionally the absolute-cwd-only slice: it does not change environment selection stickiness or cwd-to-default-environment fallback behavior. ## What changed - Changes `ThreadSettingsOverrides.cwd`, `CodexThreadSettingsOverrides.cwd`, and `SessionSettingsUpdate.cwd` to use `AbsolutePathBuf`. - Removes core-side cwd normalization/resolution from session settings updates. - Updates affected core/app-server test helpers and callsites to pass existing absolute cwd values or use `abs()` helpers. ## Validation Opening as draft so CI can start while local validation continues.
pakrym-oai ·
2026-06-05 09:29:15 -07:00 -
[codex] Forward turn moderation metadata through app-server (#25710)
## Why First-party backends can supply turn-scoped moderation metadata that app-server clients need for client-side presentation. Exposing this as an experimental typed notification lets opted-in clients consume it without interpreting raw Responses API events. ## What changed - forward `response.metadata.openai_chatgpt_moderation_metadata` from Responses API SSE and WebSocket streams as turn-scoped moderation metadata - emit the experimental app-server v2 `turn/moderationMetadata` notification with `{ threadId, turnId, metadata }` - add app-server integration coverage for the typed moderation metadata notification ## Testing - `just test -p codex-core build_ws_client_metadata_includes_window_lineage_and_turn_metadata` - `just test -p codex-core` (fails locally: 46 failures and 1 timeout, primarily missing `test_stdio_server` and shell snapshot timeouts) - `just test -p codex-app-server-protocol` - `just test -p codex-app-server turn_moderation_metadata_emits_typed_notification_v2` - `just test -p codex-app-server` (fails locally: 792 passed, 10 failed, and 5 timed out; failures are in existing environment-sensitive tests, primarily because nested macOS `sandbox-exec` is not permitted) - `just write-app-server-schema --experimental --schema-root /tmp/codex-app-server-schema-experimental`carlc-oai ·
2026-06-05 02:41:06 -07:00 -
Encrypt multi-agent v2 message payloads (#26210)
## Why Multi-agent v2 currently routes agent instructions through normal tool arguments and inter-agent context. That means the parent model can emit plaintext task text, Codex can persist it in history/rollouts, and the recipient can receive it as ordinary assistant-message JSON. This changes the v2 path so agent instructions stay encrypted between model calls: Responses encrypts the `message` argument returned by the model, Codex forwards only that ciphertext, and Responses decrypts it internally for the recipient model. ## What changed - Mark the v2 `message` parameter as encrypted for `spawn_agent`, `send_message`, and `followup_task`. - Treat multi-agent v2 tool `message` values as ciphertext unconditionally. - Store v2 inter-agent task text in `InterAgentCommunication.encrypted_content` with empty plaintext `content`. - Convert encrypted inter-agent communications into the Responses `agent_message` input item before sending the child request. - Preserve `agent_message` items across history, rollout, compaction, telemetry, and app-server schema paths. - Leave multi-agent v1 unchanged. ## Message shape The model still calls the v2 tools with a `message` argument, but that value is now ciphertext: ```json { "name": "spawn_agent", "arguments": { "task_name": "worker", "message": "<ciphertext>" } } ``` Codex stores the task as encrypted inter-agent communication: ```json { "author": "/root", "recipient": "/root/worker", "content": "", "encrypted_content": "<ciphertext>", "trigger_turn": true } ``` When Codex builds the recipient request, it forwards the ciphertext using the new Responses input item: ```json { "type": "agent_message", "author": "/root", "recipient": "/root/worker", "content": [ { "type": "encrypted_content", "encrypted_content": "<ciphertext>" } ] } ``` Responses decrypts that item internally for the recipient model. ## Context impact - Parent context no longer carries plaintext v2 agent task instructions from these tool arguments. - Codex rollout/history stores ciphertext for v2 agent instructions. - Recipient requests receive an `agent_message` item instead of assistant commentary JSON for encrypted task delivery. - Plaintext completion/status notifications are still plaintext because they are Codex-generated status messages, not encrypted model tool arguments. ## Validation - `just test -p codex-tools` - `just test -p codex-protocol` - `just test -p codex-rollout` - `just test -p codex-rollout-trace` - `just test -p codex-otel` - `just write-app-server-schema`jif ·
2026-06-05 10:25:57 +02:00 -
core: derive exec policy filesystem policy from profile (#26499)
## Why `PermissionProfile` already owns the runtime filesystem sandbox policy through `file_system_sandbox_policy()`. Keeping a separate `FileSystemSandboxPolicy` on exec-policy fallback contexts made it possible for callers and tests to construct split states that the production permission model should not rely on. ## What changed - Removed `file_system_sandbox_policy` from `UnmatchedCommandContext`, `ExecApprovalRequest`, and the intercepted Unix exec-policy context. - Derived filesystem sandbox policy inside unmatched-command decision logic from `PermissionProfile::file_system_sandbox_policy()`. - Simplified shell/unified-exec callers and tests that were only plumbing the duplicate policy through. ## Testing Local tests not run per request; relying on remote CI.
Michael Bolin ·
2026-06-04 21:48:45 -07:00 -
[codex] Support model-defined reasoning efforts (#26444)
## Summary - accept non-empty model-defined reasoning effort values while preserving built-in effort behavior - propagate the non-Copy effort type through core, app-server, TUI, telemetry, and persistence call sites - preserve string wire encoding and expose an open-string schema for clients - update model selection and shortcut behavior for model-advertised effort values ## Root cause `ReasoningEffort` gained a string-backed custom variant, so it could no longer implement `Copy` or rely on derived closed-enum serialization. Existing consumers still moved effort values from shared references and assumed a fixed built-in value set. ## Validation - `just fmt` - Local tests and compilation were not run per request; relying on CI.
Ahmed Ibrahim ·
2026-06-04 13:36:24 -07:00 -
Remove response.processed websocket request (#26447)
## Why The Responses websocket client no longer needs to send a follow-up `response.processed` request after a turn response has already been recorded. Keeping that extra acknowledgement path adds feature-gated control flow and a second websocket request shape that no longer carries useful behavior. ## What Changed - Removed the `response.processed` websocket request type and sender. - Removed the `responses_websocket_response_processed` feature flag and schema entry. - Removed turn and remote-compaction plumbing that only tracked response IDs to send the acknowledgement. - Removed tests that existed solely to cover the deleted feature path. ## Validation - `just fix -p codex-core -p codex-api -p codex-features`
pakrym-oai ·
2026-06-04 13:15:50 -07:00 -
Route AGENTS.md loading through environment filesystems (#26205)
## Why Workspace-specific `AGENTS.md` loading needs to use the selected environment filesystem so remote workspaces and child agents read instructions from their actual environment instead of the host filesystem. The app-server should report the same instruction sources the initialized thread actually loaded, rather than independently rescanning configuration and filesystem state. ## What changed - Introduce `LoadedAgentsMd` to retain ordered user, project, and internal instructions with their provenance. - Load and canonicalize workspace `AGENTS.md` paths through the primary `EnvironmentManager` environment, then render the loaded instructions when constructing turn context. - Expose cached loaded instruction sources from initialized threads and use them for app-server start, resume, and fork responses. - Preserve global `CODEX_HOME` loading and separator behavior while excluding empty project files that did not supply model-visible instructions. - Add integration coverage for CLI injection, selected-environment provenance and rendering, empty environment selection, and cached sources on loaded-thread resume. ## Validation - `just test -p codex-core agents_md` - `just test -p codex-core selected_environment_sources_match_model_visible_instructions` - `just test -p codex-exec agents_md` - `just test -p codex-app-server instruction_sources` - `just test -p codex-app-server --status-level fail`
Adam Perry @ OpenAI ·
2026-06-04 12:43:07 -07:00 -
core: allow excluding tool namespaces from code mode (#26320)
## Why Research and training setups need to control which tool namespaces appear inside code mode's nested `tools` surface without disabling those tools entirely. This makes it possible to train against a deliberately reduced nested-tool setup while preserving the normal direct and deferred tool paths. ## What - Extend `features.code_mode` to accept structured configuration while preserving the existing boolean syntax. - Add an exact `excluded_tool_namespaces` list under `[features.code_mode]`: ```toml [features.code_mode] enabled = true excluded_tool_namespaces = ["mcp__codex_apps", "multi_agent_v1"] ``` - Filter matching canonical `ToolName` namespaces when constructing code mode's nested router and code-mode-specific direct tool descriptions. - Keep excluded tools registered, directly exposed in mixed code mode, and discoverable through top-level `tool_search` when otherwise eligible. - Derive deferred nested-tool guidance after namespace filtering so the `exec` description does not advertise excluded-only deferred tools. - Preserve the boolean/table representation when materializing config locks and update the generated config schema. ## Testing - `just test -p codex-features` - `just test -p codex-config` - `just test -p codex-core load_config_resolves_code_mode_config` - `just test -p codex-core lock_contains_prompts_and_materializes_features` - `just test -p codex-core excluded_deferred_namespaces_do_not_enable_nested_tool_guidance` - `just test -p codex-core code_mode_excludes_configured_nested_tool_namespaces` - `cargo check -p codex-thread-manager-sample`
sayan-oai ·
2026-06-04 18:40:18 +00:00 -
[codex-analytics] emit forked thread id on initialization (#26248)
## Why - Thread initialization analytics do not identify the source thread for forked threads. - The session viewer needs this lineage to construct thread trees. - Depends on openai/openai#987854. Do not release this change before that backend schema change is deployed. ## What Changed - Adds optional `forked_from_thread_id` to `codex_thread_initialized`. - Populates it from the existing thread fork lineage for app-server and in-process subagent initialization paths. - Keeps it null for non-forked threads. ## Verification - `just fmt` - `just test -p codex-analytics` - `just test -p codex-app-server thread_fork_tracks_thread_initialized_analytics`
kbazzi ·
2026-06-04 11:24:12 -07:00 -
Bridge host-loaded skills into the skills extension (#26172)
## Why The skills extension needs to become the path that exposes local host skills without losing the behavior already owned by core skill loading. Host skill discovery is not just `$CODEX_HOME/skills`: it also includes config layers, bundled-skill settings, plugin roots, runtime extra roots, and the filesystem for the selected primary environment. Rather than making the extension reload host skills and risk drifting from that authoritative load, this PR bridges the already-loaded per-turn skills outcome into the extension. That lets the extension advertise host skills and inject explicit `$skill` prompts while preserving the same roots, disabled/hidden state, rendered paths, and environment-backed file reads that the legacy path uses. ## What Changed - Adds `HostLoadedSkills` in `core-skills` to wrap the turn's `SkillLoadOutcome` and read `SKILL.md` through the filesystem that loaded that skill. - Stores `HostLoadedSkills` in turn extension data for normal turns and review turns, so the skills extension can consume the loaded host catalog without reloading it. - Adds `HostSkillProvider` under `ext/skills/src/provider/host.rs`, mapping host-loaded skill metadata into the skills-extension catalog/read contract. - Registers the host provider by default from `codex_skills_extension::install()`. - Preserves host skill metadata such as dependencies, disabled state, hidden-from-prompt policy, and slash-normalized display paths. - Passes host-loaded skills through `SkillListQuery` and `SkillReadRequest` so explicit skill invocation reads only resources from the loaded host catalog. - Adds integration coverage for a real legacy `$CODEX_HOME/skills/.../SKILL.md` skill being listed and injected through the installed extension. ## Testing - Added `installed_extension_loads_host_skills_from_legacy_roots` in `ext/skills/tests/skills_extension.rs`. - `just test -p codex-skills-extension`
jif ·
2026-06-04 15:28:06 +02:00 -
Gate automatic idle turns in Plan mode (#26147)
## Why Goal idle continuation is extension-triggered model-visible work, so it should follow one core-owned rule for when automatic work may start. In particular, it should not jump ahead of queued user/client work, start while another task is active, or inject a continuation turn while the thread is in Plan mode. Keeping this policy in `try_start_turn_if_idle` avoids passing `collaboration_mode` or review-specific state through `ThreadLifecycleContributor::on_thread_idle`. Active `/review` is covered by the same active-task gate because Review turns are not steerable. ## What Changed - Teach `Session::try_start_turn_if_idle` to reject automatic idle turns in Plan mode, both before reserving an idle turn and after building the turn context. - Document `CodexThread::try_start_turn_if_idle` as the extension-facing gate for automatic idle work, including Plan-mode and active Review-task behavior. - Add focused coverage for Plan-mode rejection and active Review-task rejection without queuing synthetic input. ## Testing - `just test -p codex-core try_start_turn_if_idle`
jif ·
2026-06-04 14:44:45 +02:00 -
feat: catalog multi-agent v2 config (#26254)
## Why Model metadata can now select multi-agent v2 even when a user has not enabled `features.multi_agent_v2` in their config. Some existing configs still set the legacy `agents.max_threads` knob for v1 multi-agent behavior, so treating every v2 runtime as incompatible with `agents.max_threads` would break users whose only v2 signal came from the model catalog. The incompatible configuration is specifically enabling `features.multi_agent_v2` while also setting `agents.max_threads`. Catalog-forced v2 should use the v2 concurrency setting and ignore the legacy v1 cap instead of rejecting the config. ## What changed - Split config validation from runtime concurrency calculation: `effective_agent_max_threads` now just returns the effective cap for the resolved multi-agent runtime. - Added explicit validation for `features.multi_agent_v2` + `agents.max_threads` at session startup. - Preserved catalog-selected v2 behavior when `features.multi_agent_v2` is disabled, so existing configs with `agents.max_threads` keep starting. - Updated model-runtime selector coverage so a catalog v2 model still exposes v2 tools even when `agents.max_threads` is set and the config flag is disabled. ## Validation - `cargo check -p codex-core --lib` - `just test -p codex-core --lib -E "test(multi_agent_v2_feature_rejects_agents_max_threads) | test(catalog_v2_allows_agents_max_threads_when_feature_disabled)"`
jif ·
2026-06-04 00:24:40 +02:00 -
core: stop threading SandboxPolicy through exec (#25700)
## Why #25450 attempts a broad `SandboxPolicy` removal across several unrelated surfaces, which makes it hard to review and still leaves new helper code moving legacy policies around. This PR is a narrower alternative: migrate only the exec-side Windows sandbox plumbing so the review can focus on one production path and one compatibility boundary. The goal is to stop threading `SandboxPolicy` through exec code without expanding the migration into app-server, protocol, telemetry, config, or session behavior. ## What changed - Removed `ExecRequest::compatibility_sandbox_policy()`. - Changed the Windows restricted-token and elevated filesystem override helpers to accept `PermissionProfile` plus the split filesystem/network policies instead of a `SandboxPolicy`. - Kept the remaining legacy projection local to the writable-root comparison that still needs to compare split policy behavior against the legacy Windows backend model. - Rejected restricted split filesystem policies that still grant full-disk writes before using the Windows restricted-token backend, preserving the previous clear-failure behavior for profiles that project to `ExternalSandbox`. - Updated the Windows sandbox override tests to exercise the new call shape and cover the full-write split-profile regression. ## Verification - `just test -p codex-core windows_restricted_token` - `just test -p codex-core windows_elevated`
Michael Bolin ·
2026-06-03 10:41:41 -07:00 -
feat: guard git enrichment (#26175)
Skip turn git metadata enrichment when a turn has remote or multiple executors, so we do not report the orchestrator checkout as executor workspace metadata. Test: `just test -p codex-core` (blocked by existing `Session::conversation_id` compile error in `close_agent.rs`).
jif ·
2026-06-03 18:36:10 +02:00 -
chore: mechanical rename (#26156)
Rename `Session::conversation_id` to `Session::thread_id` with an auto refactor in RustRover
jif ·
2026-06-03 15:38:30 +02:00 -
skills: resolve per-turn catalogs from turn input context (#26106)
## Why The skills extension needs the resolved turn environments to build a real per-turn `SkillListQuery`. The previous `TurnLifecycleContributor` hook only had a turn id, so it could only seed a placeholder query and never carry the executor authorities that executor-scoped skill routing will need. Moving catalog resolution onto `TurnInputContributor` puts the skills extension on the same turn-preparation path that already has the environment ids and working directories for the submitted turn, while keeping the actual prompt injection work for follow-up changes. ## What changed - switch `ext/skills` from `TurnLifecycleContributor` to `TurnInputContributor` - build `executor_authorities` from `TurnInputContext.environments` and pass them through `SkillListQuery` - keep storing the resolved catalog in `SkillsTurnState`, but drop the placeholder query helper that no longer matches the real data flow - update the extension TODOs to reflect that per-turn catalog resolution now happens in the turn-input contributor, and that prompt/context injection still needs to move later ## Testing - Not run locally.
jif ·
2026-06-03 13:32:55 +02:00 -
feat: add extension turn-input contributors (#25959)
## Disclaimer Do not use for now ## Why Extensions can already contribute prompt fragments and request same-turn item injection, but there was no host-owned hook for contributing structured `ResponseItem`s while Codex is assembling a new turn's initial model input. This change adds that seam so extensions can attach turn-local input that depends on the submitted user input and resolved turn environments without routing through prompt text or late injection. ## What changed - add `TurnInputContributor` to `codex_extension_api` and export the new `TurnInputContext` / `TurnInputEnvironment` types it receives - teach `ExtensionRegistry` to register and expose turn-input contributors alongside the existing extension hooks - call registered turn-input contributors from `core/src/session/turn.rs` while building the initial injected input for a turn, then append their returned `ResponseItem`s after the skill and plugin injections
jif ·
2026-06-03 01:33:31 +02:00 -
Switch runtime to cloud config bundle (#24622)
## Summary - Adapts the moved `codex-cloud-config` crate from the legacy cloud requirements endpoint to the new config bundle endpoint. - Switches runtime consumers from `CloudRequirementsLoader` to `CloudConfigBundleLoader` so one shared bundle supplies cloud-delivered config and requirements. - Removes the legacy cloud requirements domain loader path. ## Details This intentionally keeps `codex-cloud-config` monolithic for review lineage: the previous PR establishes the crate move, and this PR shows the behavior change against that moved implementation. A follow-up PR splits the module back into focused files. The new bundle path preserves the important cloud requirements loader semantics where intended: account-scoped signed cache, 30 minute TTL, 5 minute refresh cadence, retry/backoff, auth recovery, and fail-closed startup loading. The cached payload changes from a single requirements TOML string to the backend-delivered bundle, and validation rejects malformed config or requirements fragments before cache write/use.
joeflorencio-openai ·
2026-06-02 13:18:59 -07:00 -
Populate workspace kind on Codex turn events (#25135)
## Summary - carry `workspace_kind` from Responses API client metadata into the turn resolved analytics fact - serialize the optional value on `codex_turn_event` - cover both the turn metadata source and turn event serialization The `workspace_kind` tells us whether a thread had a project attached vs projectless. this is an indicator for who is adopting Codex for knowledge work outside of coding ## Testing - `env UV_CACHE_DIR=/private/tmp/uv-cache /private/tmp/cargo-tools/bin/just fmt` - `env PATH=/private/tmp/cargo-tools/bin:$PATH CARGO_HOME=/private/tmp/cargo-home UV_CACHE_DIR=/private/tmp/uv-cache /private/tmp/cargo-tools/bin/just test -p codex-analytics` - `env PATH=/private/tmp/cargo-tools/bin:$PATH CARGO_HOME=/private/tmp/cargo-home UV_CACHE_DIR=/private/tmp/uv-cache /private/tmp/cargo-tools/bin/just test -p codex-core turn_metadata` Paired with openai/openai#970661, which keeps forwarding the same metadata key through Responses API headers.
knittel-openai ·
2026-06-02 12:46:14 -07:00 -
Propagate permission approval environment id (#25862)
## Stack 1. #25850 - Key request-permission grants by environment: stores and applies sticky permission grants per environment id. 2. #25858 - Add `environmentId` to `request_permissions`: lets the model target a selected environment and resolves relative permission paths against it. 3. This PR (#25862) - Propagate permission approval environment id: carries the selected environment id through approval events, app-server requests, TUI prompts, and delegate forwarding. 4. #25867 - Add remote request permissions integration coverage: verifies the selected remote environment across request, approval, grant reuse, and exec. This PR is stacked on #25858, and #25867 is stacked on this PR. ## Why PR2 lets the model bind a `request_permissions` call to a selected environment, but the approval event and client-facing request still needed to carry that binding. For CCA, the user-facing prompt and delegated approval path should know which environment the grant applies to instead of relying on cwd alone. ## What Changed - Added optional `environmentId` to `RequestPermissionsEvent`. - Emit the selected environment id from core permission approval events. - Preserve the environment id through delegate forwarding, including cwd-based delegated requests. - Added `environmentId` to app-server permission approval params, generated schema/TypeScript artifacts, and README examples. - Preserve and display the environment id in TUI permission approval prompts. - Updated focused core, app-server protocol, and TUI conversion coverage. ## Testing Not run locally per instruction. Performed read-only `git diff --check`.
jif ·
2026-06-02 21:09:34 +02:00 -
Add environmentId to request_permissions (#25858)
## Stack 1. #25850 - Key request-permission grants by environment: stores and applies sticky permission grants per environment id. 2. This PR (#25858) - Add `environmentId` to `request_permissions`: lets the model target a selected environment and resolves relative permission paths against it. 3. #25862 - Propagate permission approval environment id: carries the selected environment id through approval events, app-server requests, TUI prompts, and delegate forwarding. 4. #25867 - Add remote request permissions integration coverage: verifies the selected remote environment across request, approval, grant reuse, and exec. This PR is stacked on #25850; #25862 and #25867 are stacked on this PR. ## Why PR1 made request-permission grants internally environment-keyed, but the model-facing `request_permissions` tool could still only target the primary environment. For CCA and multi-environment turns, the tool needs an explicit way to bind a permission request to a selected attached environment before resolving relative paths. ## What Changed - Added optional `environmentId` to `RequestPermissionsArgs`, with `environment_id` accepted as an alias. - Exposed `environmentId` in the `request_permissions` tool schema and description. - Resolve the selected environment before parsing filesystem permission paths, so relative paths bind to the selected environment cwd. - Route validated tool calls through `request_permissions_for_environment` directly instead of duplicating environment lookup in `Session::request_permissions`. - Reject unknown environment ids with a model-facing error. - Updated focused request-permissions and Guardian call sites for the new optional field. ## Testing Not run locally per instruction.
jif ·
2026-06-02 20:51:25 +02:00 -
[codex-analytics] Track CodexErr details in turn analytics (#25707)
## Summary - add analytics-only `CodexErr` telemetry to `codex_turn_event` while leaving existing `turn_error` unchanged - record terminal `CodexErr` facts from core immediately before the existing turn error event is sent - emit source-truth `codex_error_*` fields for downstream analytics, including the raw `CodexErr::InvalidRequest(String)` message as `codex_error_subreason` ## Validation - `just test -p codex-analytics` - attempted `just test -p codex-core`, but the local run timed out across unrelated integration suites in this environment and is not being used as validation
rhan-oai ·
2026-06-02 11:40:35 -07:00 -
Key request-permission grants by environment (#25850)
## Stack 1. This PR (#25850) - Key request-permission grants by environment: stores and applies sticky permission grants per environment id. 2. #25858 - Add `environmentId` to `request_permissions`: lets the model target a selected environment and resolves relative permission paths against it. 3. #25862 - Propagate permission approval environment id: carries the selected environment id through approval events, app-server requests, TUI prompts, and delegate forwarding. 4. #25867 - Add remote request permissions integration coverage: verifies the selected remote environment across request, approval, grant reuse, and exec. #25858, #25862, and #25867 are stacked on this PR and should be reviewed after it. ## Why Multi-environment CCA turns can attach both local and remote executors, but request-permission grants were still effectively cwd-only. Pending permission requests tracked a cwd, while stored turn/session grants had no environment identity, so sticky grants could be reused through the wrong executor context. This makes the first permission-grant step environment-aware without changing the external `request_permissions` payload shape: omitted environment targeting remains bound to the primary turn environment. ## What Changed - Store turn- and session-scoped request-permission grants by `environment_id`. - Keep the selected `TurnEnvironmentSelection` with pending `request_permissions` calls so approval responses normalize and record grants against the same environment. - Resolve relative `request_permissions` file paths against the primary turn environment cwd instead of deprecated `turn.cwd`. - Apply sticky grants in `shell`, `exec_command`, and `apply_patch` by selected environment id while still using the actual tool cwd for cwd-relative permission materialization. - Update Guardian and request-permissions coverage for the environment-keyed grant behavior. ## Testing Not run locally. Added or updated focused coverage for: - `request_permission_grants_are_environment_keyed` - `request_permissions_tool_resolves_relative_paths_against_primary_environment` - related Guardian/request-permissions sticky grant tests
jif ·
2026-06-02 20:16:57 +02:00 -
[app-server][core] Add connector-level Guardian reviewer overrides (#25167)
Context: https://openai.slack.com/archives/C0B4JAF0Q2C/p1779912328647229 ``` approvals_reviewer = "auto_review" [apps.connector_5f3c8c41a1e54ad7a76272c89e2554fa] enabled = true approvals_reviewer = "user" default_tools_approval_mode = "prompt" ``` <img width="230" height="84" alt="Screenshot 2026-05-31 at 11 56 34 AM" src="https://github.com/user-attachments/assets/e319f8f7-0983-42a7-98cd-3302732fa406" /> <img width="841" height="233" alt="Screenshot 2026-05-31 at 11 52 42 AM" src="https://github.com/user-attachments/assets/7ac76645-4e90-4d00-8242-f031146a22a5" /> ------- ``` approvals_reviewer = "user" [apps.connector_5f3c8c41a1e54ad7a76272c89e2554fa] enabled = true approvals_reviewer = "auto_review" default_tools_approval_mode = "prompt" ``` <img width="195" height="83" alt="Screenshot 2026-05-31 at 12 02 27 PM" src="https://github.com/user-attachments/assets/3d374dc8-8aa2-466f-a13f-e4ed8567aa2e" /> <img width="771" height="207" alt="Screenshot 2026-05-31 at 12 05 42 PM" src="https://github.com/user-attachments/assets/105c2575-68d6-4ca6-8e69-dc8c82da36a2" /> ## Summary - add `apps.<connector_id>.approvals_reviewer` to override Guardian or user review routing per connected app - apply overrides across direct app MCP calls, delegated MCP prompts, and app-server MCP elicitation review while preserving global behavior for non-app MCP servers - expose and document the config through app-server v2 and generated schemas, while honoring global managed reviewer requirements --------- Co-authored-by: jif-oai <jif@openai.com>
Alex Zamoshchin ·
2026-06-02 17:04:11 +02:00 -
Reduce stack pressure in session startup and config rebuilds (#25844)
## Why `/clear` starts a fresh thread with `InitialHistory::Cleared`, which re-enters the thread/session startup path. That path now builds large async futures through `ThreadManagerState::spawn_thread_with_source`, `Codex::spawn`, and `Session::new`. Separately, TUI config rebuilds for cwd and permission-profile changes build a similarly heavy `ConfigBuilder::build()` future inside the app task. In debug and Bazel runs, those call chains can put enough state on the caller stack to abort before startup or config refresh completes. This change keeps the behavior the same while moving the heaviest future frames off the caller stack. ## What changed - Box `Codex::spawn(...)` in `codex-rs/core/src/thread_manager.rs` before awaiting it from `spawn_thread_with_source`. - Box `Session::new(...)` in `codex-rs/core/src/session/mod.rs` before awaiting it from `Codex::spawn_internal`. - Route `ConfigBuilder::build()` through a small `tokio::spawn` helper in `codex-rs/tui/src/app/config_persistence.rs` so cwd and permission-profile config rebuilds run on a runtime worker stack while preserving error context. ## Verification CI is running on the PR. No new targeted tests were added. This is a mechanical stack-pressure reduction that keeps the existing behavior and error propagation intact.
jif-oai ·
2026-06-02 15:42:47 +02:00