Commit Graph
7280 Commits
Author SHA1 Message Date
Charlie MarshandGitHub 4ae7930f58 Load plugin hooks without other plugin capabilities (#26272)
## Summary

`hooks/list` only consumes plugin hook declarations, but previously
loaded every enabled plugin's skills, MCP configuration, apps, and
capability summary before discarding them.

In a local benchmark, this reduced `hooks/list` latency by over 100ms
(e.g., from 594 to 467ms on startup, and 168 to 16ms when making a
`hooks/list` call later in the same TUI session). This is on the
critical path to rendering the TUI, so every 10s of ms should be eyed
skeptically (IMO).

This change adds a hook-specific plugin loading path that preserves
plugin enablement, remote/local conflict resolution, deterministic
ordering, manifest resolution, and hook-loading warnings while skipping
unrelated capabilities. (I think there's room for a more general design
here that allows you to project the capabilities you need at load-time,
but that seems unnecessary right now.)
2026-06-04 11:21:40 -04:00
Zanie BlueandGitHub d81fcdf8ef Reduce SQLite contention from OpenTelemetry SDK debug logs (#26396)
## Summary

- skip `opentelemetry_sdk` DEBUG and TRACE events before formatting or
queueing them for the SQLite log sink
- preserve INFO, WARN, and ERROR events from the SDK, along with TRACE
events from application targets
- add a persistence-level regression test for the target and level
policy

## Why

OpenTelemetry's batch log processor emits internal
`BatchLogProcessor.ExportingDueToTimer` meta-events every second per
Codex process. In measured high-fanout `logs_2.sqlite` databases,
low-level `opentelemetry_sdk` events accounted for over 30% of retained
rows (30-60% on the machines of people I asked to check).

Persisting this SDK bookkeeping across many processes adds substantial
write volume and contention without representing application activity.

## Validation

- `just test -p codex-state` (132/132 tests passed, plus bench smoke)
- `just fix -p codex-state`
- `just fmt`
2026-06-04 10:12:08 -05:00
Charlie MarshandGitHub 7da4af622f Optimize unbounded byte scans with memchr (#26265)
## Summary

This PR adds `memchr` for some low-hanging performance improvements
(namely, in MCP stdio, Ollama streaming, and full message-history
newline counts).

Codex produced the following release benchmarks:

| Operation | Before | After | Speedup |
| --- | ---: | ---: | ---: |
| MCP 1 MiB chunked line | 2.172 s | 3.984 ms | 545x |
| Ollama 1 MiB chunked line | 1.673 s | 2.790 ms | 600x |
| Count newlines in 10 MiB history | 132.83 ms | 20.05 ms | 6.6x |

With a "real" MCP setup (`ExecutorStdioServerLauncher` started a Python
MCP server, completed `initialize`, requested `tools/list`, and
deserialized a 1 MiB tool description over newline-delimited stdio),
it's about 16x faster end-to-end:

| Branch | 50 calls | Per call |
| --- | ---: | ---: |
| `main` | 862.53 ms | 17.25 ms |
| this branch | 53.89 ms | 1.08 ms |

`memchr` is already in our dependency tree and extremely widely used for
this kind of optimized scanning.
2026-06-04 09:53:08 -04:00
jifandGitHub d46a98d31a 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`
2026-06-04 15:28:06 +02:00
jifandGitHub d297616d3e 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`
2026-06-04 14:44:45 +02:00
jifandGitHub 16d02ec77c chore: calm down (#26367)
Prompt update to address feedback
2026-06-04 12:46:02 +02:00
ad2012d645 ci: sign macOS release artifacts with Azure Key Vault (#26252)
## Why

The public Codex release workflow needs to sign and notarize macOS
binaries and DMGs without placing the Developer ID private key in
GitHub. This moves the private-key operation behind the protected
`codesigning` environment and uses GitHub OIDC with Azure Key Vault
PKCS#11, while preserving the existing external `build_unsigned` /
`promote_signed` fallback.

## What changed

- Add a reusable AKV PKCS11 setup action that authenticates to Azure
with OIDC, downloads pinned signing tools, verifies their SHA-256
digests, and loads the public signing certificate from Key Vault.
- Replace the legacy macOS signing action with scripts that support
AKV-backed `rcodesign`, notarize signed binaries and DMGs, and staple
DMG notarization tickets.
- Restructure `rust-release.yml` so macOS builds produce unsigned
artifacts first, protected jobs perform signing and notarization, macOS
runners package and verify the results, and release publishing waits for
verified artifacts.
- Preserve the manual external-signing handoff flow and make manual-mode
conditions explicit.
- Move the Codex entitlements file alongside the signing scripts and
update CODEOWNERS for the new signing surfaces.

## Verification

- [Live protected signing workflow
run](https://github.com/openai/codex/actions/runs/26903610631) completed
successfully for both macOS architectures, including binary
signing/notarization, DMG signing/notarization, and final artifact
verification.
- Downloaded both signed DMGs and independently verified their checksums
and strict signatures.
- Confirmed `xcrun stapler validate` succeeds and Gatekeeper accepts
both DMGs as `Notarized Developer ID`.
- Mounted both DMGs and confirmed the contained `codex` and
`codex-responses-api-proxy` binaries have valid Developer ID signatures
for the expected architectures.

---------

Co-authored-by: shijie-openai <shijie.rao@openai.com>
2026-06-03 20:34:51 -07:00
rhan-oaiandGitHub c143a86de8 [codex-analytics] report compaction request token counts (#25946)
## Why

Compaction analytics need token counts that better represent the request
being compacted. The existing session snapshot can diverge from the
actual remote compaction request after output rewriting, and remote v2
can use server-side Responses usage when available.

## What changed

- Add an optional `active_context_tokens_before` override to
`CompactionAnalyticsAttempt::track(...)` for remote compaction when it
has a better before-token value than the begin-time session snapshot.
The local `/compact` path passes no override.
- For remote v1 `responses_compact`, subtract the estimated token delta
from pre-compaction output rewriting from the session snapshot, capped
by locally-added tokens since the last successful API response.
- For remote v2 `responses_compaction_v2`, use the same bounded
output-rewrite fallback as remote v1, then overwrite
`active_context_tokens_before` with server `token_usage.input_tokens`
from the `response.completed` event when present.
- Keep the existing v2 compaction-output validation while carrying the
completed response token usage through `collect_compaction_output`.

## Verification

- `just fmt`
- `just test -p codex-core
collect_compaction_output_accepts_additional_output_items`
- `git diff --check`
2026-06-04 03:00:44 +00:00
Michael BolinandGitHub 6bcccb0ee6 cli: add package path from install context (#26189)
## Why

Codex package installs include helper binaries in `codex-path`, such as
the bundled `rg`. Package-layout launches should add that directory
before user commands run, but standalone launches were missing it while
npm launches only worked because `codex.js` had its own legacy `PATH`
rewrite. That made npm and standalone package behavior diverge.

Shell snapshot restoration can also reset `PATH` after runtime setup.
Any package-owned `PATH` prepend has to be recorded as an explicit
runtime override so shells, unified exec, and user-shell commands keep
access to `codex-path` after a snapshot is sourced.

## Repro

Before this change, a curl-installed package could contain `rg` under
`codex-path` but still fail to put it on `PATH`:

```shell
mkdir /tmp/test-codex-curl
curl -fsSL https://chatgpt.com/codex/install.sh \
  | CODEX_HOME=/tmp/test-codex-curl CODEX_NON_INTERACTIVE=1 sh
/tmp/test-codex-curl/packages/standalone/current/bin/codex exec \
  --skip-git-repo-check 'print `which -a rg`'
find /tmp/test-codex-curl -name rg
```

The `which -a rg` output omitted the packaged helper even though `find`
showed it under
`/tmp/test-codex-curl/packages/standalone/releases/.../codex-path/rg`.

The npm install path behaved differently only because
`codex-cli/bin/codex.js` had legacy `PATH` rewriting:

```shell
mkdir /tmp/test-codex-npm
cd /tmp/test-codex-npm
npm install @openai/codex
./node_modules/.bin/codex exec --skip-git-repo-check 'print `which -a rg`'
```

That printed the npm package's `vendor/<target>/codex-path/rg` first.
This PR moves that behavior into Rust-side package launch setup so
curl/standalone and npm/bun launches agree without JS rewriting `PATH`.

## What Changed

- `codex-rs/arg0` now uses
`InstallContext::current().package_layout.path_dir` to prepend the
package helper directory before any threads are created.
- Package helper `PATH` setup is independent from the temporary arg0
alias setup, so `codex-path` is still added even if CODEX_HOME tempdir,
lock, or symlink setup fails.
- `codex-rs/install-context` detects the canonical package layout we
ship: `bin/`, `codex-resources/`, and `codex-path/` next to
`codex-package.json`.
- Shell, local unified exec, and user-shell runtimes now record package
`codex-path` prepends in `explicit_env_overrides`, matching the existing
zsh-fork behavior so shell snapshots cannot restore over the package
helper path.
- Remote unified exec requests do not receive the local app-server
package path overlay.
- `codex-cli/bin/codex.js` no longer computes or overrides `PATH`; it
only locates the native binary in the canonical package layout and
passes npm/bun management metadata.
- Added regression tests for `PATH` ordering, package layout detection,
and shell snapshot preservation of package path prepends.

## Verification

- `node --check codex-cli/bin/codex.js`
- `just test -p codex-install-context -p codex-arg0`
- `just test -p codex-core
user_shell_snapshot_preserves_package_path_prepend`
- `just test -p codex-core tools::runtimes::tests`
- `just bazel-lock-update`
- `just bazel-lock-check`
- `just fix -p codex-install-context -p codex-arg0 -p codex-core`
2026-06-03 19:08:19 -07:00
Felipe CouryandGitHub 80b65e9945 feat(tui): add /app desktop handoff (#25638) 2026-06-03 20:30:15 -03:00
Felipe CouryandGitHub 8285cd278b fix(tui): add reasoning effort fallback shortcuts (#25623) 2026-06-03 20:28:31 -03:00
Chris DongandGitHub 4d4837c495 log plugin MCP server names (#26002)
## Summary
- emit the plugin capability summary's exact MCP server names in
`codex_plugin_used`

## Test
- `just test -p codex-analytics`
- `just test -p codex-core
explicit_plugin_mentions_track_plugin_used_analytics`
- `just fix -p codex-analytics`
2026-06-03 16:06:52 -07:00
AbhinavandGitHub 0ed2735d19 Use Windows setup marker as completion signal (#26074)
# Why

When an organization requires the elevated Windows sandbox, Codex
launches an elevated helper to provision users, configure firewall and
ACL rules, and lock persistent sandbox directories.

We observed that closing the helper after setup started could leave the
machine partially initialized while the TUI still announced **Sandbox
ready**. Model-only turns continued to work, but the first shell command
retried setup and failed with Windows cancellation error `1223`.

This was not an enforcement bypass; command execution continued to fail
closed. The issue was a false readiness signal: `setup_marker.json` was
written during user provisioning, before the remaining setup stages had
completed.

# What

Treat `setup_marker.json` as the commit record for Windows sandbox
setup:

1. Before full or provisioning setup begins, remove the existing marker
and create the final marker path with a protected ACL.
2. Keep the marker empty and therefore invalid while setup is in
progress. Sandbox users cannot read, modify, or replace it.
3. Run every synchronous setup stage.
4. After setup succeeds, write the valid marker contents without
changing its ACL.
5. After the helper exits successfully, verify the existing readiness
check before enabling the sandbox.

If setup is canceled or fails, the marker remains invalid and Codex
reports setup as incomplete instead of announcing readiness.

Refresh-only and read-ACL-only helper runs continue to leave the marker
untouched. The setup version remains `5` to avoid forcing all existing
Windows users through elevated setup again.

# Verification

- Added coverage confirming sandbox users cannot read or modify the
setup marker after elevated setup.
- Added coverage confirming a successful helper exit without complete
setup artifacts is rejected.
- Ran `just test -p codex-windows-sandbox`.
2026-06-03 15:33:34 -07:00
Adam Perry @ OpenAIandGitHub 14272b21e9 codex-pr-body: avoid confidential references (#26260)
## Why

PR descriptions can be visible outside the context used to generate
them. In #23710, a generated description referenced an internal
document, showing that the skill needs an explicit guardrail against
exposing confidential context.

## What changed

- Updated the `codex-pr-body` guidance to prohibit confidential
references, including codenames and OpenAI-internal URLs.
2026-06-03 15:29:57 -07:00
pakrym-oaiandGitHub 4231472c03 Rewrite oversized tool outputs during remote compaction (#26251)
## Why

When trying to fit history under compaction limit rewrite output items
instead of removing them entirely. Otherwise we're breaking
incrementality in relation to the previous response.
2026-06-03 15:25:50 -07:00
jifandGitHub 11bceb8f8b 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)"`
2026-06-04 00:24:40 +02:00
Ahmed IbrahimandGitHub 2ca3810005 [codex] Split Python runtime release workflow (#26226)
## Why

Python SDK releases pin an exact `openai-codex-cli-bin` version, so all
eight platform runtime wheels must be available on PyPI before the SDK
package is built and published. PyPI does not support reusable workflows
as Trusted Publishers, which means OIDC-backed publishing must run from
each top-level release workflow.

## What changed

- add reusable `python-runtime-build.yml` to prepare and upload all
eight runtime wheels without publishing
- add top-level `python-runtime-release.yml` for manual runtime
publication before updating an SDK pin
- have `python-sdk-release.yml` publish and verify the prepared runtime
wheels from its own top-level trusted job before building the SDK
- verify PyPI exposes exactly the expected eight runtime wheels before
either release workflow continues

## PyPI configuration

- keep the trusted publisher for
`.github/workflows/python-sdk-release.yml` with environment `pypi`
- add a trusted publisher for
`.github/workflows/python-runtime-release.yml` with environment `pypi`
- no trusted publisher is needed for
`.github/workflows/python-runtime-build.yml`

## Validation

- parsed all three workflow YAML files
- validated all embedded shell blocks with `bash -n`
- no local tests run; relying on online CI
2026-06-03 14:29:52 -07:00
Won ParkandGitHub 0eb7e6d79b Restore Windows coverage for code-mode image generation exposure (#25960)
## Summary

Restore Windows coverage for standalone image generation in code mode.

The previous test executed a V8-backed code-mode cell on Windows CI,
where that runtime path is intentionally excluded because it is
unreliable. The test was then ignored entirely on Windows, removing
useful coverage.

This splits the test into two checks:

- All platforms verify that `image_gen__imagegen` is exposed to the
model when image generation is configured for code mode only.
- Non-Windows platforms continue to execute the full V8-backed flow and
verify that the nested image-generation call succeeds.

## Verification

- `just fmt`
- `git diff --check`
- `just test -p codex-app-server standalone_image_generation`

Result: 3 tests passed, plus the required bench smoke check.
2026-06-03 14:02:55 -07:00
Eric TrautandGitHub d8121f93c8 Fix forked thread name inheritance (#26075)
Fixes #25950.

## Why
Forking a renamed thread could fall back to the source thread's
first-prompt title because the fork path did not preserve the source's
explicit name. That meant fork-of-renamed-fork flows could show stale
sidebar labels even though the user had renamed the parent.

## What changed
`thread/fork` now reads the source thread's distinct `name`, normalizes
it, persists it onto materialized forks, and applies it to the returned
API thread. Because the source `name` already excludes first-prompt
pseudo-titles, forks inherit only an explicit user rename instead of
stale generated metadata.
2026-06-03 12:56:54 -07:00
dhruvgupta-oaiandGitHub a2ebe07b39 [profile-switcher][rust] -- [1/2] Add app-server account session protocol (#25469)
## Summary

Adds the app-server v2 `accountSession/*` protocol used by the Desktop
profile switcher and the backend account metadata client needed to
populate workspace choices.

This is the protocol layer only. The app-server lifecycle and
consolidated saved-session storage are split into a follow-up PR.

## Rust Stack

1. This PR
2. [openai/codex#25383](https://github.com/openai/codex/pull/25383) adds
app-server session lifecycle behavior and consolidated saved-session
storage.

## Validation

- Generated app-server schema fixtures are included from the existing
generation flow in the lifecycle PR where the routes are registered.
- Did not run tests per requested scope.
2026-06-04 01:25:11 +05:30
Won ParkandGitHub 57ab4c89e0 Expose local image paths to models (#25944)
## Why

Local image attachments include image bytes, but the adjacent
model-visible label omits the source path. Exposing the path lets
model-selected workflows refer back to the intended local image
explicitly.

## What changed

- Include an escaped `path` attribute in model-visible local image
opening tags.
- Reuse the path-aware marker generator in rollout coverage.
- Update protocol, replay, and rollout coverage for the new request
shape.

## Validation

- `just fmt`
- `just test -p codex-protocol`
- `just test -p codex-core skips_local_image_label_text`
- `just test -p codex-core
copy_paste_local_image_persists_rollout_request_shape`
- `git diff --check`
2026-06-03 19:49:58 +00:00
Eric NingandGitHub aeac226d16 Preserve remote plugin default prompts (#25887)
## Summary

- Read `default_prompts` from remote plugin release metadata.
- Prefer the plural prompt list over legacy `default_prompt`.
- Fall back to `default_prompt` as a single-item list for backward
compatibility.

## Testing

- `just test -p codex-core-plugins`
- `just test -p codex-app-server`
2026-06-03 12:39:13 -07:00
Ahmed IbrahimandGitHub 10b408080a [codex] Pin Python SDK to runtime 0.137.0a4 (#26216)
## Summary
- pin the Python SDK runtime to `openai-codex-cli-bin==0.137.0a4`
- refresh generated protocol artifacts from `rust-v0.137.0-alpha.4`
- refresh `sdk/python/uv.lock` with all eight published runtime wheels

## Runtime publication
- published `openai-codex-cli-bin==0.137.0a4` through the
`python-sdk-release` workflow
- includes macOS, manylinux, musllinux, and Windows wheels
- publication run:
https://github.com/openai/codex/actions/runs/26905608531

## Validation
- ran `just fmt`
- generated artifacts from the `rust-v0.137.0-alpha.4` release wheel
- ran `uv lock --check --default-index https://pypi.org/simple`
- did not run tests locally, per request; CI provides the test signal
2026-06-03 12:14:14 -07:00
Adam Perry @ OpenAIandGitHub 2d5c264ebc [codex] Copy user Bazel settings into Codex worktrees (#25925)
## Why

Codex-created linked worktrees do not include ignored files from the
main worktree. Bazel users who keep local overrides in `user.bazelrc`
therefore lose those settings in every new worktree.

The setup must also work on Windows and must not overwrite a file that
already exists in the worktree.

## What changed

The checked-in Codex environment now invokes
`.codex/environments/setup.py`. The script resolves the main worktree
and current worktree, then uses
`copy_from_main_worktree_to_worktree(repo_relative_path)` to copy
ignored files into new worktrees without overwriting existing
destinations.

`main()` currently copies `user.bazelrc`. Additional repository-relative
paths can be added as further calls to the same helper.

## Validation

- Ran the setup script in a linked worktree and confirmed it handles a
missing main-worktree `user.bazelrc`.
- Verified the helper copies a main-worktree file, preserves an existing
worktree file, and creates parent directories for a nested path.
2026-06-03 18:29:36 +00:00
Michael BolinandGitHub 52b359b249 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`
2026-06-03 10:41:41 -07:00
Eric TrautandGitHub a2a9e767f7 Fix multiline paste in /goal edit (#26047)
Fixes #26025.

## Why
`/goal edit` opens `CustomPromptView`, which did not use the paste-burst
handling that protects the main composer when terminals deliver paste as
rapid key events. On Windows terminals, the first pasted newline could
be treated as Enter-to-submit, truncating the goal edit and leaving the
rest of the paste behind.

## What
This reuses `PasteBurst` in `CustomPromptView` as a lightweight
Enter-suppression detector for paste-like key streams. Characters still
insert directly, explicit paste still goes through the view paste path,
and ordinary text entry still submits on Enter.
2026-06-03 09:36:50 -07:00
jifandGitHub 8030c36970 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`).
2026-06-03 18:36:10 +02:00
jifandGitHub 99c9be1d30 nit: small prompt update for MAv2 (#26179)
Simple prompt change for MAv2 because of OOD compared to CBv9
2026-06-03 18:34:32 +02:00
iceweasel-oaiandGitHub b2344d8fbc [codex] Restore setup helper UAC manifest (#25949)
## Why

#23764 removed Windows resource stamping from `codex-windows-sandbox`,
but it also removed the setup helper's UAC manifest. That manifest was
doing more than cosmetic version metadata: Microsoft documents
`requestedExecutionLevel level="asInvoker"` as the setting that makes an
executable run at the same permission level as the process that started
it:
https://learn.microsoft.com/en-us/windows/win32/sbscs/application-manifests#trustinfo

In the reported session, `codex-windows-sandbox-setup.exe` was launched
for a non-elevated setup refresh and `CreateProcess` failed with `os
error 740` (`The requested operation requires elevation`). Restoring an
explicit `asInvoker` manifest records the helper's intended default
launch contract: normal launches inherit the caller's token, and
elevation only happens through the code paths that request it
explicitly.

The setup helper has two launch modes:

- setup refresh uses a normal `Command::new(...)` spawn and should never
trigger UAC
- full setup explicitly uses `ShellExecuteExW` with the `runas` verb
when elevation is required

Restoring `asInvoker` keeps refresh non-elevated by default while
preserving the explicit elevated path for full setup.

## What changed

- Restored a minimal `codex-windows-sandbox-setup.manifest` containing
only `requestedExecutionLevel level="asInvoker"`.
- Added a small build script that passes setup-helper-scoped manifest
linker args for MSVC and the Windows GNU/LLVM target used by Bazel.
- Wired the manifest into Bazel build-script data.

This does not restore `winres`, `FileDescription`, `ProductName`, or
package-wide resource stamping, so other Codex binaries that link
`codex-windows-sandbox` do not inherit metadata from this package.

## Verification

- `cargo fmt -p codex-windows-sandbox`
- `cargo build -p codex-windows-sandbox --bin
codex-windows-sandbox-setup`
- `cargo build -p codex-windows-sandbox --bin codex-command-runner`
- `cargo build -p codex-windows-sandbox --lib`
- Build-script output simulation for `CARGO_CFG_TARGET_ENV=msvc` emits
`/MANIFEST:EMBED` and `/MANIFESTINPUT:<manifest>`.
- Build-script output simulation for `CARGO_CFG_TARGET_ENV=gnu` +
`CARGO_CFG_TARGET_ABI=llvm` emits `-Wl,-Xlink=/manifest:embed` and
`-Wl,-Xlink=/manifestinput:<manifest>`.
- Inspected the built binaries and confirmed:
- `codex-windows-sandbox-setup.exe` contains `requestedExecutionLevel` /
`asInvoker`
  - `codex-command-runner.exe` does not contain those manifest strings
- Windows `VersionInfo` remains blank for `FileDescription` /
`ProductName`
- `just test -p codex-windows-sandbox` ran through Nextest, with 114
passing, 2 skipped, and 1 existing Windows sandbox failure:
`unified_exec::tests::legacy_non_tty_cmd_emits_output` fails with
`CreateRestrictedToken failed: 87`.
2026-06-03 09:21:24 -07:00
jifandGitHub 4417e4c193 fix: main (#26176) 2026-06-03 16:47:34 +02:00
jifandGitHub 96d2d2f68c Implement v1 skills extension prompt injection (#26167)
## Why

The skills extension needs a real turn-time path before host, executor,
or remote skills can be routed through it. The previous code was mostly
a placeholder catalog/provider sketch, so there was no bounded
available-skills fragment, no source-owned `SKILL.md` read, and no place
for warnings or per-turn selection state to live.

This PR makes `ext/skills` the authority-preserving flow for listing
candidate skills and injecting only explicitly selected main prompts,
without adding more of that logic to `codex-core`.

## What changed

- Expands catalog entries with `main_prompt`, display path, short
description, dependency metadata, enabled/prompt visibility flags, and
authority/package-aware read requests.
- Replaces the placeholder `providers/*` modules with
`SkillProviderSource` and `SkillProviders`, routing list/read/search
calls by source kind and surfacing provider failures as warnings.
- Adds bounded available-skills rendering and `SKILL.md` main-prompt
truncation before the fragments enter model context.
- Resolves explicit skill selections from structured `UserInput::Skill`,
skill-file mentions, `skill://...` paths, and plain `$skill` text
mentions, then reads selected prompts through their owning provider.
- Stores mutable per-thread skills config and per-turn
catalog/selection/warning state.
- Adds `install_with_providers` so tests and future host wiring can
supply concrete providers.

## Testing

- Not run locally.
- Added `codex-rs/ext/skills/tests/skills_extension.rs` coverage for
available-catalog injection, selected prompt injection through the
owning provider, and prompt-hidden skills that remain invokable.
2026-06-03 16:24:16 +02:00
jifandGitHub c9ae0f48a1 chore: mechanical rename (#26156)
Rename `Session::conversation_id` to `Session::thread_id` with an auto
refactor in RustRover
2026-06-03 15:38:30 +02:00
jifandGitHub 7db18c8241 fix: serialize goal progress accounting (#26155)
## Why

Goal progress accounting can be reached from multiple completion paths
for the same thread. Each path takes a progress snapshot, writes the
usage delta, and then marks that snapshot as accounted. When two
tool-completion hooks run at the same time, they can both observe the
same unaccounted delta and charge it twice.

## What changed

- Added a per-thread progress-accounting permit to
`GoalAccountingState`.
- Held that permit across the snapshot/write/mark-accounted critical
section for active-turn, idle, and tool-finish accounting.
- Added regression coverage for parallel tool-finish hooks so a shared
token delta is charged once and only one progress event is emitted.

## Testing

- Not run locally.
- Added `parallel_tool_finish_accounts_active_goal_progress_once`.
2026-06-03 15:10:16 +02:00
jifandGitHub 3389fa554e 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.
2026-06-03 13:32:55 +02:00
jifandGitHub 51493157cd Reject MAv2 close_agent self-targets (#26144)
## Why

`close_agent` is a parent-owned coordination tool: a worker should
return its result, then let its parent decide when to close it. Before
this change, if an MAv2 worker targeted itself, the resolved target
could flow through the normal close path and ask the agent control layer
to close the current conversation.

## What changed

- Reject `close_agent` when the resolved target is the current session's
`conversation_id`, returning a model-visible error that tells the worker
to return its result instead.
- Keep the guard after target resolution so it covers both thread-id
targets and task-path targets.
- Add coverage for self-targeting by thread id and by task name in
`multi_agents_tests.rs`.

Relevant code:

-
[`handle_close_agent`](https://github.com/openai/codex/blob/7c24e6641b693a3eed933dd376ce8f424ab6ea5f/codex-rs/core/src/tools/handlers/multi_agents_v2/close_agent.rs#L39-L57)
- [`multi_agent_v2_close_agent_rejects_self_target_by_id` /
`multi_agent_v2_close_agent_rejects_self_target_by_task_name`](https://github.com/openai/codex/blob/7c24e6641b693a3eed933dd376ce8f424ab6ea5f/codex-rs/core/src/tools/handlers/multi_agents_tests.rs#L3936-L4070)

## Testing

Not run locally.
2026-06-03 13:30:04 +02:00
jifandGitHub ac67905fc4 chore: extract context fragments into dedicated crate (#26122)
## Why

`codex-core` currently owns the generic contextual-fragment trait and
several reusable fragment implementations. That makes it harder for
other crates to share the same host-owned model-input abstraction
without depending on all of `codex-core`.

This change extracts the reusable fragment machinery into a small
`codex-context-fragments` crate so future extension and skills work can
depend on the fragment abstraction directly.

## What Changed

- Added the `codex-context-fragments` crate with:
  - `ContextualUserFragment`
  - `FragmentRegistration` / `FragmentRegistrationProxy`
  - additional-context fragment types
- Moved `SkillInstructions` into `codex-core-skills`, since
skill-specific rendering belongs with skills rather than generic core
context machinery.
- Kept `codex-core` re-exporting the fragment types it still uses
internally, so existing call sites keep the same shape.
- Updated Cargo and Bazel workspace metadata for the new crate.

## Verification

- `cargo metadata --locked --format-version 1 --no-deps`
- `just bazel-lock-update`
- `just bazel-lock-check`
2026-06-03 12:25:21 +02:00
jifandGitHub 668703c23f feat: default hide_spawn_agent_metadata to true (#26114)
For MAv2 CBv9
2026-06-03 12:22:23 +02:00
Shijie RaoandGitHub d36a3ead3c revert: publish release symbol artifacts (#25988)
revert https://github.com/openai/codex/pull/25916 and
https://github.com/openai/codex/pull/25649.
2026-06-02 17:34:04 -07:00
Anton PanasenkoandGitHub 98a62a62ce feat(app-server): add remote control client management RPCs (#25785)
## Why

Remote-control clients need to list and revoke controller-device grants
without enabling or enrolling the local relay. These are signed-in
account-management operations, so coupling them to websocket, pairing,
enrollment, or persisted relay state would prevent clients from managing
stale grants from the picker.

Related enhancement request: N/A. This adds the Codex app-server surface
for the planned upstream environment-scoped revoke endpoint.

## What Changed

- Added experimental app-server v2 RPCs:
  - `remoteControl/client/list`
  - `remoteControl/client/revoke`
- Added picker-oriented protocol types and standard generated schema
fixtures. The list response intentionally omits backend account id,
enrollment status, and location fields.
- Added `app-server-transport/src/transport/remote_control/clients.rs`
for environment-scoped GET and DELETE requests. It builds escaped URL
path segments, forwards optional pagination query fields, sends ChatGPT
auth plus `chatgpt-account-id`, converts RFC3339 `last_seen_at` values
to Unix seconds, accepts `204 No Content` revoke responses, and retries
once after a `401`.
- Extracted shared ChatGPT auth loading and recovery into
`app-server-transport/src/transport/remote_control/auth.rs` so
websocket, pairing, and client management use the same account-auth
boundary.
- Retained the configured remote-control base URL on
`RemoteControlHandle` and resolve management URLs lazily, preserving
deferred validation while relay startup is disabled.
- Registered list as `global_shared_read("remote-control-clients")` and
revoke as `global("remote-control-clients")`.

## Verification

- Added transport coverage proving list and revoke work while relay
state is disabled, IDs are escaped, picker-only fields are returned,
timestamps are converted, revoke accepts `204`, auth headers are
forwarded, `401` retries exactly once, `403` is not retried, and
malformed list payloads retain decode context.
- Added an app-server integration test proving both JSON-RPC methods
work before relay enablement and successful revoke returns `{}`.
- Regenerated and validated experimental and standard app-server schema
fixtures.
2026-06-02 17:01:02 -07:00
joeflorencio-openaiandGitHub 1fd2a6d328 Allow EDU accounts to fetch cloud config bundles (#25963)
## Summary

Allow EDU ChatGPT workspaces to fetch cloud config bundles. The existing
cloud config eligibility gate only allowed business-like and enterprise
plans, which meant EDU admins could configure managed policies in the UI
but the Codex client would skip fetching them.

This keeps individual/pro and team-like usage-based plans excluded, and
adds service-level coverage for both `edu` and `education` plan aliases.

## Validation

- `just fmt`
- `just test -p codex-cloud-config`
- Built the Codex app locally, created a new EDU ChatGPT workspace, and
verified config bundles can be fetched and are properly applied.
2026-06-02 16:41:48 -07:00
jifandGitHub 271d5cecf2 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
2026-06-03 01:33:31 +02:00
Michael BolinandGitHub a28b32a835 config: express implicit sandbox defaults as permission profiles (#25926)
## Why

`PermissionProfile` is becoming the default way to represent Codex
permissions, but the implicit default behavior should stay the same for
now:

- trusted projects use `:workspace`
- untrusted projects also use `:workspace`
- roots without a trust decision use `:read-only`
- unsandboxed Windows falls back to `:read-only`

This keeps the existing sandbox semantics while making silent config
defaults observable as built-in permission profiles instead of treating
the legacy `SandboxPolicy` projection as the primary shape.

## What Changed

- Refactored legacy sandbox derivation to resolve the configured sandbox
mode once, then apply the implicit project fallback only when no sandbox
mode was configured.
- Preserved the existing trust-decision fallback: trusted and untrusted
projects default to workspace-write where supported.
- Added empty-config coverage asserting that an untrusted project
resolves to the built-in active permission profile (`:workspace` outside
unsandboxed Windows).

## Verification

- `just fmt`
- `just test -p codex-core 'config::'`
- `just test -p codex-config`

---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/25926).
* __->__ #25926
2026-06-02 16:26:36 -07:00
Adam Perry @ OpenAIandGitHub 6471f8b31a [codex] Fix Windows BuildBuddy Bazel wrapper execution (#25915)
## Why

#25156 moved Bazel CI launches into a shared Python wrapper. On Windows,
launching Bazel with `os.execvp` can split the spaced
`--test_env=PATH=...` argument and fail to propagate the eventual Bazel
exit status, allowing jobs to pass without running tests. This reapplies
the wrapper after #25909 with a Windows-safe launch path.

## What changed

Use a waited `subprocess.run` launch on Windows while preserving
`os.execvp` on Unix. Add a process-level regression test for spaced
arguments and child exit status, and run it on Windows Bazel shard 1.

## Experiment

To confirm Bazel was actually invoking tests, patch `87b61d0be6`
temporarily added an intentionally failing `codex-core` unit test. Bazel
failed on that sentinel on all three major platforms:

- [Linux Bazel
test](https://github.com/openai/codex/actions/runs/26841132773/job/79151062486)
- [macOS Bazel
test](https://github.com/openai/codex/actions/runs/26841132773/job/79151062362)
- [Windows Bazel test shard
1/4](https://github.com/openai/codex/actions/runs/26841132773/job/79151062155)

The sentinel was removed after collecting this evidence. Windows Bazel
[clippy](https://github.com/openai/codex/actions/runs/26841132773/job/79151062914)
and [release
verification](https://github.com/openai/codex/actions/runs/26841132773/job/79151062739)
also passed.

## Validation

After removing the sentinel, `just test -p codex-core` no longer
reported it. The local run retained two unrelated environment-specific
failures.
2026-06-02 16:22:32 -07:00
jifandGitHub 2d385e166c feat: add skills extension scaffold (#25953)
## Disclaimer
This is only here for iteration purpose! Do not make any code rely on
this

## Why

Skills still live behind `codex-core` discovery and injection paths, but
the extension system needs an authority-aware home before that logic can
move. This adds that boundary without changing current skills behavior,
and keeps host, executor, and remote skills distinct so future
list/read/search flows do not collapse back to ambient local paths.

## What changed

- Add the `codex-skills-extension` workspace/Bazel crate under
`ext/skills`.
- Define the initial catalog, authority, provider, and turn-state types
for authority-bound skill packages and resources.
- Register placeholder thread/config/prompt/turn lifecycle contributors
plus host, executor, and remote provider aggregation points.
- Capture the remaining extraction work as TODOs, including the missing
extension API hooks needed for per-turn catalog construction and typed
skill injection.
- Keep plugins outside the runtime skills model: plugin-installed skills
are treated as materialized host-owned skill sources once available.

## Verification

- Not run locally.
2026-06-03 01:10:26 +02:00
Ahmed IbrahimandGitHub 34dc08c214 [codex] Publish Python runtime wheels with Python SDK releases (#25906)
## Summary
- stop publishing Python runtime wheels as a side effect of Rust
releases
- publish runtime wheels from the Python SDK release workflow, either
explicitly before updating the SDK pin or immediately before a
`python-v*` SDK release
- resolve the runtime release from the requested version or the SDK
package's exact `openai-codex-cli-bin` pin
- build two musllinux-tagged wheels from the Rust-release Linux package
archives alongside the six existing runtime wheels
- validate SDK beta tags before any PyPI write

## Release configuration
- update the `openai-codex-cli-bin` PyPI trusted publisher to trust
`.github/workflows/python-sdk-release.yml` and the
`publish-python-runtime` job

## Pin update flow
- run the `python-sdk-release` workflow manually with the new runtime
version before opening or updating the SDK pin PR
- after the pin lands, a `python-v*` SDK tag republishes with
`skip-existing: true` before publishing the SDK package

## Validation
- ran `just fmt`
- validated the edited workflow YAML
- validated the embedded `publish-python-runtime` Bash with `bash -n`
- validated manual `0.136.0 -> rust-v0.136.0` mapping
- validated tag-driven `python-v0.1.0b3 -> 0.132.0 -> rust-v0.132.0`
mapping
- validated rejection of an invalid SDK tag before publication
- confirmed `rust-v0.136.0` contains the two required Linux package
archives
- CI will provide the full test signal
2026-06-02 15:41:53 -07:00
Won ParkandGitHub bec21c7114 Expose standalone image generation in code mode (#25923)
## Why

Standalone image generation remained top-level-only in code-mode
sessions.

## What changed

- Change imagegen exposure from `DirectModelOnly` to `Direct`.
- Keep direct-mode access while enabling nested code-mode access.
- Add a focused regression test for the exposure contract.

## Validation

- `just test -p codex-image-generation-extension`
2026-06-02 22:27:52 +00:00
Shijie RaoandGitHub f752b25fc4 Revert "Use environment secrets for Azure signing" (#25948)
Reverts openai/codex#24859
2026-06-02 15:12:07 -07:00
Michael BolinandGitHub c6d76750e8 config: remove dead profile sandbox fallback (#25943)
## Why

`profile_sandbox_mode` was left over from the old selected legacy
profile path. Production now always derives permissions without that
value, and legacy profile contents are ignored, so keeping a parameter
that is always `None` makes `derive_permission_profile` look like it
still supports a fallback that no longer exists.

## What Changed

- Removed the `profile_sandbox_mode` argument from
`ConfigToml::derive_permission_profile`.
- Updated the production caller and legacy sandbox-policy test helper to
match.
- Dropped the stale unselected legacy-profile sandbox test that only
protected the removed fallback shape.

## Verification

- `just test -p codex-config`
- `just test -p codex-core 'config::'`


---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/25943).
* #25926
* __->__ #25943
2026-06-02 22:05:04 +00:00
jifandGitHub d55e5a9bde Add remote request permissions integration coverage (#25867)
## 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. #25862 - Propagate permission approval environment id: carries the
selected environment id through approval events, app-server requests,
TUI prompts, and delegate forwarding.
4. This PR (#25867) - Add remote request permissions integration
coverage: verifies the selected remote environment across request,
approval, grant reuse, and exec.

This PR is stacked on #25862 and should be reviewed after #25850,
#25858, and #25862.

## Why

The environment-scoped permission stack needs one end-to-end check that
exercises the CCA-shaped path, not only unit-level parsing. This
verifies that a model-sent `environmentId` on `request_permissions`
reaches the approval event, stores the grant under the selected
environment, and is reused by a later tool call in that same
environment.

## What Changed

- Adds a remote executor integration test for `request_permissions` with
`environmentId: remote` and a relative write root.
- Asserts the permission event reports the remote environment and cwd,
and that the normalized grant resolves under the remote cwd.
- Approves the grant, then runs a remote `exec_command` without explicit
per-call permissions and verifies it completes without another exec
approval and writes only in the remote filesystem.

## Verification

- Not run locally per instruction.
- `git diff --check`
2026-06-02 23:55:08 +02:00
Ahmed IbrahimandGitHub 68e2c8ed69 [codex] Keep hosted tools visible in code-only mode (#25890)
## Why

`code_mode_only` moved ordinary runtime tools behind `exec`, but it also
hid hosted Responses tools. Hosted `web_search` and `image_generation`
do not have a nested `exec` runtime path, so code-only sessions lost
those capabilities entirely even when their existing provider, auth,
model, and configuration gates passed.

## What changed

- Keep hosted Responses tools top-level in `code_mode_only` sessions
after their existing gates pass.
- Preserve the existing nested-tool behavior for ordinary runtimes and
the direct-only behavior for multi-agent v2 tools.
- Add planner coverage for `code_mode_only` with default multi-agent v2
settings, hosted live web search, and hosted image generation.

## Verification

- Added focused regression coverage in
`codex-rs/core/src/tools/spec_plan_tests.rs`.
- Left execution to CI per repository workflow.
2026-06-02 14:50:16 -07:00