Commit Graph
7280 Commits
Author SHA1 Message Date
viyatb-oaiandGitHub 85fd52f7e4 Enforce configured network proxy in codex sandbox (#27035)
## Why

`codex sandbox` can start a network proxy from a configured permission
profile. Previously, sandbox-level containment was tied to managed
network requirements rather than whether a proxy was actually active.
This meant config-driven proxy policies were not consistently enforced
as the sandbox's only network path.

## What changed

- Enable proxy-only network containment whenever `codex sandbox` starts
a network proxy.
- Apply the same active-proxy check to the macOS and Linux sandbox
paths.
- Add a Linux regression test that verifies a sandboxed command cannot
establish a direct connection while the configured proxy is active.

## Test plan

- `just test -p codex-cli debug_sandbox::tests`
- `sandbox_with_network_proxy_blocks_direct_loopback_access` runs on
Linux to cover the config-driven proxy path end to end.
2026-06-08 14:03:37 -07:00
Michael BolinandGitHub e0ee491df3 cli: add -P sandbox permissions profile alias (#27054)
## Why

`codex sandbox --permissions-profile` is useful when running commands
under a named permissions profile, but the long option is cumbersome for
a debugging-oriented command. `-p` is already used for the config
profile selector, so `-P` gives the permissions profile selector a
compact, non-conflicting alias.

## What Changed

- Added `short = 'P'` to the `permissions_profile` option for the macOS,
Linux, and Windows sandbox command structs in
[`codex-rs/cli/src/lib.rs`](https://github.com/openai/codex/blob/6d9f9c5cdcaa0a156aa2dabbde259ae5e9e8bc0b/codex-rs/cli/src/lib.rs#L29-L112).
- Added parser coverage for `codex sandbox -P :workspace -- echo` in
[`codex-rs/cli/src/main.rs`](https://github.com/openai/codex/blob/6d9f9c5cdcaa0a156aa2dabbde259ae5e9e8bc0b/codex-rs/cli/src/main.rs#L2883-L2896).

## Verification

- `just test -p codex-cli` passed, including the new
`sandbox_parses_permissions_profile_short_alias` parser test.
2026-06-08 20:59:23 +00:00
pakrym-oaiandGitHub f3c1283411 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.
2026-06-08 13:55:15 -07:00
jifandGitHub f9a680b907 [codex] Calm multi-agent v2 usage prompts (#27037)
## Summary
- tighten the default multi-agent v2 root and subagent usage hints to
bias toward local work
- add a pre-call gate to the v2 spawn_agent description for independent,
bounded, parallelizable subtasks

## Validation
- just fmt
- started just test -p codex-core, but it was interrupted before
completion per follow-up request to commit and push immediately
2026-06-08 22:32:10 +02:00
Adam Perry @ OpenAIandGitHub f3a8074975 [codex] Clarify PR babysitter state mutations (#27038)
# Why

Codex is doing a bit too much on my PRs that it's babysitting. In
particular I'd like it to not interact with comment threads that involve
other humans -- I should be the one doing human interaction. This is
tricky because it's still very useful to be able to drop review comments
myself and have Codex iterate on them.

## What

This updates `.codex/skills/babysit-pr/SKILL.md` with an explicit GitHub
state mutation policy.
2026-06-08 13:09:06 -07:00
9e0d7f02c9 fix: preserve auto review across config and delegation (#26230)
## Why

Auto Review should remain the effective approval reviewer when settings
cross runtime boundaries. A config or app-server round trip must not
change the reviewer identity, and delegated work must not silently fall
back to user review.

This requires both a stable canonical serialized value and propagation
of the effective setting. `auto_review` is the canonical value across
protocol and app-server output, while `guardian_subagent` remains
accepted as backward-compatible input.

## What changed

- serialize `ApprovalsReviewer::AutoReview` consistently as
`auto_review` across core protocol and app-server v2
- continue accepting `guardian_subagent` when reading existing config or
client requests
- carry the active turn's approval reviewer into spawned agents
- update config/debug expectations and add delegated-task regression
coverage

## Scope

This does not change Guardian policy or remove compatibility with
existing `guardian_subagent` inputs. It preserves the selected reviewer
across serialization, config reloads, app-server settings, and delegated
task setup.

Related Guardian changes are split independently:

- #26231 adds denials and soft denials
- #26334 retries transient reviewer failures
- #26333 reuses narrowly scoped low-risk approvals
- #26232 adds TUI denial recovery

## Validation

- `just test -p codex-app-server-protocol` (224 passed)
- regression coverage for delegated task reviewer propagation
- serialization coverage for canonical `auto_review` output and legacy
`guardian_subagent` input

---------

Co-authored-by: saud-oai <saud@openai.com>
2026-06-08 18:59:50 +00:00
Michael BolinandGitHub 2375cb6449 ci: template custom runner names by repo (#27024)
## Why

These workflows currently hard-code the `codex` runner group and custom
runner labels. That makes the same workflow definitions less portable
across repository copies or renamed repos, even though the runner fleet
follows the repository name scheme. Template the runner identities from
the repository name so `openai/codex` still resolves to the existing
`codex-*` runners while other repos can use their own `<repo>-*` runner
names.

## What Changed

- Replaced custom runner `group` values such as `codex-runners` with
`${{ github.event.repository.name }}-runners`.
- Replaced custom runner labels such as `codex-linux-x64` and
`codex-windows-arm64` with `${{ github.event.repository.name }}-...`.
- Covered direct `runs-on` objects, matrix `runs_on` entries, reusable
workflow runner inputs, and release runner labels.

## Verification

- Parsed all `.github/workflows/*.yml` files as YAML with Ruby.
- Searched `.github/workflows` to confirm no hardcoded runner-field
`codex-runners` or `codex-*` labels remain.
2026-06-08 11:47:23 -07:00
mpc-oaiandGitHub 0aa9931aea [plugins] Expose marketplace source in marketplace list JSON (#27009)
## Summary
- Follow-up to #26417 and #26631
- Add `marketplaceSource` to `codex plugin marketplace list --json`
entries for configured marketplaces
- Reuse the existing `marketplaceSource` shape from `codex plugin list
--json`
- Keep human-readable marketplace list output unchanged
- Add CLI coverage for configured local and git marketplace sources

Example:

```json
{
  "marketplaces": [
    {
      "name": "debug",
      "root": "/path/to/.codex/.tmp/marketplaces/debug",
      "marketplaceSource": {
        "sourceType": "git",
        "source": "https://example.com/acme/agent-skills.git"
      }
    }
  ]
}
```

## Validation
- `just fmt`
- `just fix -p codex-cli`
- `just test -p codex-cli marketplace_list`
- `just test -p codex-cli`
2026-06-08 13:37:55 -05:00
stefanstokic-oaiandGitHub 6d8e12ac42 [codex] Speed up external agent session imports (#26637)
## Why

Importing large external-agent session histories currently starts a full
live Codex thread for every imported session. This initializes unrelated
runtime systems and repeats expensive transcript, metadata, hashing, and
ledger work.

On a 50-session, 238 MiB fixture, the existing path took roughly 70
seconds to complete the import and 77 seconds end to end.

## What changed

- Persist imported sessions directly through `ThreadStore` instead of
starting full live threads.
- Process imports through a bounded five-session pipeline.
- Parse, extract, and hash each source file in one pass.
- Move blocking source preparation onto the blocking thread pool.
- Reuse prepared content hashes and update the import ledger once per
batch.
- Avoid metadata readback for newly written rollouts.
- Preserve imported conversation history and visible thread metadata.
- Keep the implementation out of `codex-core` and avoid changes to the
public `ThreadStore` trait.

## Performance

For the same 50-session, 238 MiB fixture:

| Path | Import completion | End to end |
| --- | ---: | ---: |
| Existing import | 69.61s | 76.62s |
| This change | 5.95s | 6.58s |

All 50 sessions imported successfully with no warnings or contention
signals.

## Validation

- `just test -p codex-external-agent-sessions`
- `just test -p codex-app-server external_agent_config_import`
- Verified imports do not initialize unrelated required MCP servers.
- Verified previously imported source versions are skipped and changed
sources can be imported again.
- Verified imported rollouts remain readable through thread listing and
history APIs.
2026-06-08 14:16:32 -04:00
rhan-oaiandGitHub f1c18df9ae [codex-analytics] report compaction analytics details (#26680)
## Why

Compaction analytics adds retained image count and compaction summary
output tokens for v1.5 specifically.

## What changed

- Add nullable `retained_image_count` and `compaction_summary_tokens`
fields to `codex_compaction_event`.
- Populate them only for `responses_compaction_v2`: retained images come
from the retained v2 compacted history, and summary tokens come from
`response.completed.token_usage.output_tokens`.
- Leave local and legacy remote compaction events as `null` for these
detail fields.

## Verification

- `just fmt`
- `just fix -p codex-core`
- `just test -p codex-core
build_v2_compacted_history_counts_retained_input_images`
- `git diff --check`
2026-06-08 10:52:31 -07:00
ningyi-oaiandGitHub a815311466 Add HTTP window ID to Responses client metadata (#26923)
## Summary

- Keep the existing `x-codex-window-id` HTTP header unchanged.
- Also send the same window ID in Responses `client_metadata`, allowing
supported backend paths to surface it as
`x-client-meta-x-codex-window-id`.
- Cover normal HTTP Responses and remote compaction v2 requests without
changing window generation or compaction behavior.

## Why

In the `2026-06-06T23` production hour, all 28,729 HTTP compaction
requests had `window_id` in `x-codex-turn-metadata`, but only 73
retained the direct `x-codex-window-id` header. The request-body
`client_metadata` path is already used for installation ID and is
preserved through supported Responses API paths.

This is additive metadata only. It does not change the direct header,
request count, model input, compaction routing, window generation, or
user response behavior.

Legacy `/v1/responses/compact` is intentionally unchanged. Its current
server-side `CompressBody` schema does not accept `client_metadata` and
rejects unknown fields, so supporting that path requires a backend
schema change before the Codex client can safely send this field.

## Validation

- Current head: `219baef3c`, rebased onto `origin/main` at `26d932983`.
- The post-rebase diff remains limited to the original five files (`22`
insertions, `6` deletions); the legacy experiment remains fully
reverted.
- `just test -p codex-core
responses_stream_includes_subagent_header_on_review`: passed; validates
normal HTTP Responses metadata.
- `just test -p codex-core
remote_compact_v2_reuses_compaction_trigger_for_followups`: passed;
validates remote compaction v2.
- `just test -p codex-core
remote_manual_compact_chatgpt_auth_reuses_service_tier_and_prompt_cache_key`:
passed; validates that legacy compact keeps its accepted payload shape.
- `just test -p codex-core
remote_manual_compact_api_auth_omits_service_tier_and_reuses_prompt_cache_key`:
passed; validates the legacy API-key payload as well.
- `just fmt`: passed; an unrelated root `justfile` rewrite produced by
the formatter was discarded.
- `git diff --check origin/main...HEAD`: passed.

The focused server pytest could not start in the local monorepo
environment because test setup is missing the `dotenv` module. Server
source and tests explicitly show that `CompressBody` omits
`client_metadata` and `/v1/responses/compact` returns HTTP 400 for
unknown body fields.
2026-06-08 10:49:59 -07:00
Anton PanasenkoandGitHub b128da272e fix(app-server): avoid blocking connection cleanup (#26852)
## Why

Remote-control app-server sessions can reconnect every 5-7 seconds when
the shared transport-event queue fills. The queue's consumer handled
`ConnectionClosed` by awaiting all in-flight RPCs for the disconnected
connection. A stuck RPC therefore blocked processing of replacement
connection and initialize events until remote-control forwarding hit its
five-second timeout and reconnected again.

Related issue: N/A (internal remote-control incident investigation).

## What Changed

- Split fast RPC admission closure from draining:
`ConnectionRpcGate::close()` rejects queued and future RPCs, while
`shutdown()` continues waiting for RPCs that already started.
- Close a disconnected connection's RPC gate before spawning the
existing RPC drain and resource cleanup in a tracked background task, so
the transport-event consumer remains available without waiting for
active RPCs.
- Reap completed cleanup tasks during normal operation, drain them
during graceful shutdown, and abort them during forced shutdown.
- Add regression coverage for closing with an active RPC, rejecting
post-close requests without polling them, and preserving the existing
shutdown wait behavior.

## Verification

`just test -p codex-app-server --lib connection_rpc_gate` passes all 6
tests, including the new close-versus-drain regression coverage.
2026-06-08 10:20:54 -07:00
Jeremy RoseandGitHub 6d0e313e23 [codex] Restore release symbol artifacts with line tables (#26202)
## Summary

- Restore separate release symbol archives for macOS, Linux, and Windows
binaries.
- Build release binaries with `line-tables-only` debuginfo instead of
full debuginfo.
- Strip Unix distribution binaries after extracting symbols, preserve
Windows PDBs, and keep symbol archives available to the release job.
- Strip the packaged Linux `bwrap` binary before hashing it so the
embedded digest matches the distributed bytes.

## Root cause

The first symbol-artifact implementation enabled
`CARGO_PROFILE_RELEASE_DEBUG=full`. In the June 2 release runs, macOS
ARM primary builds reached the 90-minute timeout while still inside
`Cargo build`. After the symbol changes were reverted, the same primary
build completed in about 22 minutes. The archive step itself completed
in tens of seconds when reached.

Rust's `line-tables-only` debuginfo level preserves function names and
source locations for symbolication without emitting the heavier variable
and type information from full debuginfo.

## Validation

- Ran `just fmt` from `codex-rs`.
- Ran `just test-github-scripts` from the repository root: 23 tests
passed.
- Ran `bash -n` and `shellcheck` on
`.github/scripts/archive-release-symbols-and-strip-binaries.sh`.
- Parsed both modified workflows as YAML and ran `git diff --check`.
- Built a macOS release smoke binary with `line-tables-only`, archived
its dSYM through the restored script, stripped the production binary,
and verified that `atos` resolves `symbol_smoke_function` to
`main.rs:2`.
- Ran Linux archive-script control-flow coverage with stubbed `objcopy`
and `strip` commands.
- Ran Windows PDB archive staging coverage and verified
underscore-emitted Rust PDB names are staged under shipped hyphenated
binary names.

## Follow-up

The release workflow only runs for tags or manual dispatches, so CI
cannot dry-run the full release matrix on this PR. The next release run
will verify runner time and memory behavior under `line-tables-only`.
2026-06-08 17:16:36 +00:00
rka-oaiandGitHub 26d9329833 [codex] Exclude external tool output from memories (#26821)
## Summary

- add contains_external_context() to tool output so other tools can be
opted out of influencing memory when disable_on_external_context=true
- Classify standalone web-search output as external context (to match
behavior as hosted web search)
- Verify with integration test
2026-06-08 16:53:04 +00:00
jifandGitHub 0526cb56ac Avoid reopening v2 descendants on resume (#26997)
## Why

Multi-agent v2 residency is intended to keep only the threads that need
to be live. The existing rollout resume path still walked persisted open
descendants and reopened the entire descendant tree when resuming a v2
root, which turns resume into an eager reload of work that should stay
unloaded until it is explicitly needed.

The interrupted-agent path has a related residency issue. Interrupted
agents remain open by design, so an idle interrupted resident should be
eligible for eviction just like an idle completed or errored resident.
Otherwise a resident set full of interrupted agents can consume every v2
slot and block later spawns or reloads with `AgentLimitReached`.

## What Changed

- Return early from `resume_agent_from_rollout` after resuming a v2
thread so persisted v2 descendants are not reopened eagerly.
- Treat idle `Interrupted` v2 residents as unloadable in the LRU
residency path.
- Add focused coverage for v2 root resume leaving descendants unloaded
and for eviction of an idle interrupted v2 resident when a new slot is
needed.

## Verification

Added targeted `codex-core` tests covering:

- v2 root resume with persisted descendants, verifying only the root is
loaded after resume.
- residency eviction of an idle interrupted v2 agent when the resident
set is full.
2026-06-08 16:44:50 +02:00
jifandGitHub 8d415050fc Rename multi-agent v2 close_agent to interrupt_agent (#26994)
## Why

`close_agent` is the wrong model-facing name for the v2 operation after
the residency changes. V2 agents remain reusable by task name, and
residency/unloading owns capacity management; the exposed tool should
describe the action it actually performs: interrupt the target agent's
current turn without making the agent unavailable for future messages or
follow-up tasks.

## What changed

- Rename the multi-agent v2 tool from `close_agent` to
`interrupt_agent`.
- Keep the v1 `close_agent` surface unchanged.
- Update the v2 handler to send `Op::Interrupt`, keep interrupted agents
registered, and reject root/self targets with interrupt-specific errors.
- Route interrupt delivery through the existing dead-thread cleanup path
so stale resident entries do not keep consuming capacity.
- Update tool planning and handler tests for the new v2 surface and
semantics.

## Verification

Added focused coverage in:

- `core/src/tools/spec_plan_tests.rs`
- `core/src/tools/handlers/multi_agents_tests.rs`
2026-06-08 14:46:35 +02:00
jifandGitHub 743f5aad38 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`
2026-06-08 14:21:28 +02:00
jifandGitHub 8f1aad58dc Ignore proc-macro-error2 advisory (#26974)
## Summary
- ignore RUSTSEC-2026-0173 in cargo-deny and cargo-audit config
- document that proc-macro-error2 is pulled in transitively via
i18n-embed-fl/age/codex-secrets
- leave the ignore temporary until codex-secrets moves off age or age
drops i18n-embed-fl

## Validation
- just fmt
- cargo deny check --hide-inclusion-graph
2026-06-08 11:39:08 +02:00
jifandGitHub 4e803a017c feat: add v2 agent residency lru (#26632)
## Why

Multi-agent v2 treats agents as durable logical agents, not just live
entries in `ThreadManager`. After the reload-on-delivery change, a v2
agent can be addressed even if its thread is not currently loaded.

This PR adds the next layer: loaded v2 subagents can be paged out of
`ThreadManager` when the session has too many resident agents. That
keeps residency separate from logical identity and prepares the stack
for making v2 concurrency count active execution instead of existing
agents.

## What Changed

- Add an `AgentControl`-scoped LRU for resident v2 subagents.
- Reserve residency before spawning or reloading a v2 subagent.
- If resident capacity is full, unload the least-recently-used idle v2
subagent from `ThreadManager`.
- Keep `ThreadManager` as a primitive loaded-thread store; it does not
own the LRU policy.
- Keep unloaded agents registered and durable so they can be reloaded by
the delivery path.
- Preserve the existing v2 cap semantics by using the derived non-root
v2 cap for residency.

Eviction is intentionally conservative. A thread is unloadable only when
it is a v2 subagent, has completed or errored, has no active turn, and
has no pending mailbox work. Before removal, the rollout is materialized
and flushed.

## Assumptions And Non-Goals

- PR #26623 provides the reload-on-delivery path for unloaded v2 agents.
- `ThreadManager` membership means loaded/resident, not logical agent
existence.
- `AgentRegistry` remains the logical identity/metadata source for v2
agents that may be unloaded.
- `list_agents` remains a recent/resident view for now.
- This does not change active execution concurrency; that is the next
PR.
- This does not change `close_agent` semantics.
- This does not change or remove `resume_agent`.
- This does not add a new residency config knob.

## Stack

1. V2 durable lookup and reload on delivery (#26623) - reload unloaded
v2 agents before delivering follow-up/input.
2. V2 residency LRU (this PR) - unload idle resident v2 agents from
`ThreadManager` when resident capacity is full.
3. V2 active-execution concurrency - count running non-root v2 turns
instead of logical agents.
4. V2 close/interrupt semantics - make v2 close interrupt the current
turn without deleting durable identity.
5. V2 resume cleanup - remove the manual resume surface for v2 while
keeping internal reload support.

## Validation

- Added focused coverage for the residency LRU eviction path.
- Local clippy/check/tests were not run; CI will cover them.
2026-06-08 10:24:48 +02:00
rka-oaiandGitHub ed6e5cf919 [codex] Enable standalone web search in code mode (#26719)
## What

- Consume plaintext `output` from standalone search while retaining
optional `encrypted_output` parsing.
- Expose `web.run` to code mode and return search output to nested
JavaScript calls.
- Cover direct and code-mode standalone search paths with integration
tests.

## Why

`/v1/alpha/search` now returns plaintext output, which code mode needs
to consume standalone search results.

## Test plan

- `just test -p codex-api`
- `just test -p codex-web-search-extension`
- `just test -p codex-core code_mode_can_call_standalone_web_search`
- `just test -p codex-app-server
standalone_web_search_round_trips_output`
2026-06-07 23:18:23 -07:00
Felipe CouryandGitHub 5a440c03f2 fix(tui): scope MCP startup status by thread (#26639)
## Why

MCP startup failures from spawned subagents were rendered as global
notifications, so a child thread's failure could pollute the visible
parent transcript. Routing the notification to the child exposed two
related replay problems: session refresh could discard the buffered
event, and a newly created child `ChatWidget` did not know the expected
MCP server set, which could leave its startup spinner running after
every server had settled.

MCP startup diagnostics should remain visible in the thread that owns
the startup without affecting other transcripts. The protocol also needs
to support a future app-scoped MCP lifecycle where startup is not owned
by any thread.

## Reported Behavior

The [originating Slack
report](https://openai.slack.com/archives/C08JZTV654K/p1780604538859939)
called out that using subagents could turn MCP startup failures into a
wall of yellow CLI warnings because repeated failures were not
deduplicated. The intended behavior is for those diagnostics to remain
visible once in the thread that owns the startup, without polluting the
parent transcript.

## What Changed

- add nullable `threadId` ownership to `mcpServer/startupStatus/updated`
- populate it from the app-server conversation ID for the current
thread-scoped lifecycle and regenerate the protocol schema and
TypeScript artifacts
- treat a missing or null `threadId` as app-scoped without injecting it
into the active chat transcript
- route and buffer thread-owned MCP startup notifications by thread in
the TUI
- preserve buffered MCP startup events across child session refresh
- seed expected MCP servers before replaying a thread snapshot so
startup reaches its terminal state
- suppress an identical repeated failure warning for the same server
within one startup round

The owning thread still renders the detailed failure and final `MCP
startup incomplete (...)` summary.

## How to Test

1. Configure an optional MCP server named `smoke` that exits during
initialization.
2. Launch the TUI with multi-agent support enabled.
3. Confirm the main thread's own startup failure renders one detailed
`smoke` warning and one incomplete-startup summary.
4. Spawn exactly one subagent.
5. Confirm the parent transcript does not receive the subagent's MCP
startup failure.
6. Switch to the subagent thread and confirm it contains exactly one
detailed `smoke` failure and one incomplete-startup summary.
7. Confirm the subagent's MCP startup spinner disappears and the thread
remains usable.
8. Switch between the parent and subagent and confirm the warnings
neither move nor duplicate.

Targeted tests:

- `just test -p codex-app-server-protocol`
- `just test -p codex-app-server
thread_start_emits_mcp_server_status_updated_notifications`
- `just test -p codex-tui mcp_startup`

The parent/child behavior and spinner completion were also exercised
manually in tmux. `just argument-comment-lint` was attempted but blocked
by an unrelated local Bazel LLVM empty-glob failure; touched Rust
callsites were inspected manually.
2026-06-07 20:12:05 -07:00
Michael BolinandGitHub e648ec771f deps: update starlark to 0.14.2 (#24820) 2026-06-07 17:35:33 -07:00
Felipe CouryandGitHub e093d81982 fix(tui): accept prompts with resume and fork (#26818)
## Why

Interactive `codex resume` and `codex fork` expose both a session ID
positional and an initial prompt positional. With `--last`, Clap still
assigns the first positional to the session ID, so a command such as
`codex fork --last "/compact focus on auth"` either fails parsing or
attempts to look up the prompt as a session ID instead of sending it to
the latest session.

This makes it impossible to select the latest session and immediately
provide a follow-up prompt, even though `codex exec resume --last`
already supports that workflow.

<img width="1746" height="1024" alt="CleanShot 2026-06-06 at 17 00
47@2x"
src="https://github.com/user-attachments/assets/86885c07-a23c-48ee-b0ee-47f2484f6eb7"
/>

## What Changed

- Reinterpret the first positional as the initial prompt when
interactive `resume --last` or `fork --last` is used and no explicit
second prompt was parsed.
- Preserve the existing `resume SESSION_ID PROMPT` and `fork SESSION_ID
PROMPT` behavior.
- Add parser-level regression coverage for latest-session and
explicit-session prompt forms.

## How to Test

1. Start an interactive session, exit it, then run `codex resume --last
"continue from the latest session"`.
2. Confirm Codex resumes the latest session and submits the supplied
prompt instead of treating it as a session ID.
3. Run `codex fork --last "take a different approach"`.
4. Confirm Codex forks the latest session and submits the supplied
prompt.
5. Also verify `codex resume SESSION_ID "continue here"` and `codex fork
SESSION_ID "branch here"` still target the explicit session and submit
the prompt.

Targeted tests:
- `just test -p codex-cli` (267 passed)
2026-06-07 17:34:35 -04:00
Michael BolinandGitHub e6c470957d fix: preserve approval sandbox decisions in unified exec (#24981)
## Why

This PR fixes approval sandbox semantics in the unified-exec path. The
zsh-fork runtime exposed the bug because the shell can do meaningful
work before any intercepted child `execv(2)` exists: redirections,
builtins, globbing, and pipeline setup all happen in the launch process.
If the model requested `sandbox_permissions=require_escalated`, or an
exec-policy `allow` rule explicitly bypassed the sandbox, that approved
sandbox decision needs to be preserved for the launch path and for
intercepted execs that use the same approval machinery.

The behavior is not only about zsh fork. The production changes are in
shared approval/escalation code, so they also affect non-zsh-fork
intercepted exec paths that go through the same sandbox decision logic.
The narrow intent is to preserve the approval decision while still
keeping denied-read profiles and bounded additional-permission requests
sandboxed.

## Production Changes

- `codex-rs/core/src/tools/runtimes/unified_exec.rs`: derives a
`launch_sandbox_permissions` value from the requested sandbox
permissions and the runtime filesystem policy, then uses that value for
managed-network/env setup and launch sandbox selection. This keeps full
approval or policy-bypass decisions visible to the first unified-exec
attempt, while still preventing a full sandbox override from discarding
denied-read restrictions. Direct unified exec keeps the same decision
surface; the important difference is that zsh-fork launch setup no
longer accidentally loses the approved parent sandbox decision.

- `codex-rs/core/src/tools/runtimes/shell/unix_escalation.rs`: makes
intercepted-exec escalation selection explicit for the three sandbox
permission modes. `UseDefault` only escalates when an exec-policy
decision allows sandbox bypass, `RequireEscalated` escalates when
unsandboxed execution is allowed, and `WithAdditionalPermissions`
escalates through the bounded additional-permissions path instead of
being treated as a full unsandboxed override. Unsandboxed intercepted
execs now also rebuild the environment as `RequireEscalated`, which
strips managed-network proxy variables consistently with other
unsandboxed execution.

## Test Coverage

Most of the PR is tests. The new coverage verifies:

- unified exec preserves parent approval and exec-policy sandbox
decisions for zsh-fork launch selection;
- bounded `with_additional_permissions` remains sandboxed and
permission-profile based;
- denied-read profiles are not weakened by parent approval;
- explicit prompt rules still prompt for intercepted execs after the
parent command is approved;
- unsandboxed intercepted execs strip managed-network env vars.

No documentation update is needed; this is an internal approval/sandbox
correctness fix.





---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/24981).
* #24982
* __->__ #24981
2026-06-07 11:33:16 -07:00
Michael BolinandGitHub 2ee3358c00 ci: use bazel environment for BuildBuddy secret (#26895)
## Why

`BUILDBUDDY_API_KEY` now lives in the `bazel` GitHub Actions environment
as an environment secret. Jobs that need BuildBuddy credentials must opt
into that environment so `${{ secrets.BUILDBUDDY_API_KEY }}` resolves
from the protected environment secret instead of relying on an unscoped
repository/organization secret.

This follows the same environment-secret migration pattern as #26466.

## What Changed

- Attach each workflow job that reads `BUILDBUDDY_API_KEY` to the
`bazel` environment.
- Set `deployment: false` on those job-level environment blocks.

`deployment: false` lets the job enter the `bazel` environment to access
its environment secrets without creating GitHub deployment records for
these CI jobs. That keeps the environment as a secret/access-control
boundary without making ordinary Bazel CI runs look like deploys.

## Validation

- Parsed the modified workflow YAML files with Ruby's YAML parser.
- Checked the modified workflow files for trailing whitespace.
2026-06-07 09:24:54 -07:00
Channing CongerandGitHub b89ce9a2bc build(v8): update rusty_v8 to 149.2.0 (#26464) 2026-06-06 14:27:23 -07:00
Eric NingandGitHub cdc8ec065e fix(core-plugins): send Codex product SKU to plugin-service (#26804) 2026-06-06 14:03:00 -07:00
Anton PanasenkoandGitHub 87b808bb57 fix(remote-control): preserve enrollment on generic websocket 404s (#26741)
## Why

A remote-control WebSocket handshake can receive a generic HTTP 404 when
an intermediary routes the request without preserving the WebSocket
upgrade. Treating every 404 as proof that the remote app server is gone
clears valid enrollment and causes repeated re-enrollment, new
environment and server IDs, Habitat churn, and noisy `/server/enroll`
traffic.

## What Changed

- Clear enrollment only when a 404 JSON response explicitly contains
`{"detail":"Remote app server not found"}`.
- Preserve enrollment for empty, plain-text, malformed, or otherwise
unrecognized 404 responses, return the transport error, and retry with
the existing reconnect backoff.
- Log the status, correlation headers (`request-id` or
`x-oai-request-id`, plus `cf-ray`), and bounded/redacted response body
for unrecognized 404s.
- Cover both explicit missing-server re-enrollment and generic 404
enrollment preservation/reconnect behavior.

## Verification

`just test -p codex-app-server-transport` passes all 114 tests on the
rebased branch, including the targeted explicit and generic WebSocket
404 scenarios.

Related issue: N/A
2026-06-05 22:54:57 -07:00
Adam Perry @ OpenAIandGitHub 3ea9e98333 Remove just bench-smoke from just test. (#26716)
## Why

`just test` should run the test suite without also compiling and
executing benchmark smoke tests. Keeping benchmark validation explicit
avoids adding unrelated work to every project-specific test invocation.

## What changed

- Remove the `just bench-smoke` step from the Unix and Windows `test`
recipes.
- Document `just bench` and `just bench-smoke` as the explicit benchmark
commands in `AGENTS.md`.

## Validation

- `just test -p codex-arg0`
- `just --dry-run test`
- `just --dry-run bench-smoke`
2026-06-05 18:53:12 -07:00
xl-openaiandGitHub cbac22dabe [codex] Deduplicate skill load warnings (#26698)
Skill reloads can get noisy when the watcher keeps triggering
`skills/list` and the same invalid `SKILL.md` error comes back each
time.

This keeps the first warning visible, then suppresses repeats while the
same `(path, message)` is still active. If the error clears and later
comes back, or if the message changes, it will show again.

Validation:
- `just fmt`
- `just test -p codex-tui skill_load_warning_state`
2026-06-05 18:37:47 -07:00
2f108f9fd9 permissions: enforce managed permission profile allowlists (#24852)
## Why

Permission profile allowlists are an enterprise security boundary, but
they also need to compose across the managed requirements layers added
in #24620.

A map representation lets each requirements layer add, allow, or revoke
individual profiles without replacing an entire array.

## Managed Contract

Administrators configure the mergeable allow map with
`allowed_permission_profiles`. A recommended enterprise configuration
explicitly lists every built-in and custom profile users should be able
to select:

```toml
default_permissions = "review_only"

[allowed_permission_profiles]
":read-only" = true
":workspace" = true
review_only = true
# ":danger-full-access" is intentionally omitted, so it is denied.

[permissions.review_only]
extends = ":read-only"
```

- Profiles whose effective merged value is `true` are allowed.
- Missing profiles and profiles set to `false` are denied.
- This is a closed allowlist: built-in profiles and profiles introduced
in future versions are denied unless explicitly allowed.
- Explicitly list each built-in profile the enterprise wants to make
available. Omit built-ins such as `:danger-full-access` when they should
remain unavailable.
- Set `default_permissions` explicitly to the allowed profile users
should receive when they have no local selection.
- Higher-precedence layers override only the profile keys they define.
- `false` is only needed when a higher-precedence layer must revoke a
`true` inherited from a lower layer.
- Explicit keys must refer to known built-in or managed profiles.

A custom or narrowed allowlist requires an allowed
`default_permissions`. For compatibility, if both `:workspace` and
`:read-only` are explicitly allowed, an omitted default resolves to
`:workspace`; customer configurations should still set the intended
default explicitly.

When `allowed_permission_profiles` is absent, existing implicit
permission and legacy `sandbox_mode` behavior is unchanged.

## What Changed

- Add `allowed_permission_profiles` as a `BTreeMap<String, bool>` that
merges per profile across requirements layers.
- Enforce managed defaults, strict denial of omitted profiles, and the
explicitly allowed standard-pair fallback.
- Expose `allowedPermissionProfiles` through `configRequirements/read`
and regenerate its schemas.
- Add regression coverage for map composition and revocation, managed
defaults, strict denial of omitted built-ins, and API output.

## Verification

- Focused `codex-config` coverage for layered map composition and
revocation
- Focused `codex-core` coverage for managed defaults, invalid defaults,
strict denial of omitted built-ins, and the standard built-in pair
- Focused `codex-app-server` coverage for requirements API output
- Scoped Clippy for `codex-config`, `codex-core`,
`codex-app-server-protocol`, and `codex-app-server`

## Documentation

The managed `requirements.toml` documentation should introduce
`allowed_permission_profiles` as a closed permission-profile allowlist
before this setting is published on developers.openai.com.

---------

Co-authored-by: Codex <noreply@openai.com>
2026-06-05 18:06:29 -07:00
rka-oaiandGitHub 954e2878bb [codex] Send Responses Lite transport header (#26542)
## Summary

- send `X-OpenAI-Internal-Codex-Responses-Lite: true` on HTTP Responses
requests and WebSocket upgrade requests when model metadata enables
Responses Lite
- use client metadata when sending it over the websocket

This PR is stacked on #26490.

## Why

The Responses Lite marker is request-scoped for HTTP but
connection-scoped for Responses-over-WebSocket because it is carried on
the upgrade request. Reusing a cached socket opened for the opposite
mode would therefore send the wrong transport contract.

## Validation

- `just test -p codex-core responses_lite`
- `just test -p codex-core
responses_websocket_reconnects_when_responses_lite_mode_changes`
- `just fix -p codex-core`
- `just fmt`
2026-06-06 01:01:20 +00:00
cooper-oaiandGitHub df7818c7d1 [codex-rs] support v2 personal access tokens (#25731)
## Summary

- add v2 personal access token support for `codex login
--with-access-token` and `CODEX_ACCESS_TOKEN`
- classify opaque `at-` tokens separately from legacy Agent Identity
JWTs
- hydrate required ChatGPT account metadata through AuthAPI
`/v1/user-auth-credential/whoami`
- use PATs directly as bearer tokens while preserving existing ChatGPT
account surfaces
- expose PAT-backed auth as the explicit `personalAccessToken`
app-server auth mode

## Implementation

PAT auth is intentionally small and stateless. Loading a PAT performs
one AuthAPI metadata request, stores the hydrated metadata in the
in-memory auth object, and redacts the secret from debug output. Legacy
Agent Identity JWT handling remains unchanged. The shared access-token
classifier lives in a private neutral module because it dispatches
between both credential types.

PAT hydration fails closed when AuthAPI omits any required metadata,
including email. Hydrated metadata is intentionally not persisted:
startup performs a live `whoami` preflight so revoked tokens or changed
account metadata are not accepted from a stale cache.

## Workspace restriction scope

This change intentionally does **not** apply
`forced_chatgpt_workspace_id` to PAT authentication. The setting is a
client-side config guardrail, not an authorization boundary, and PAT
does not currently require workspace-ID parity. The PAT login and
`CODEX_ACCESS_TOKEN` paths therefore validate through AuthAPI without
threading workspace-restriction state through access-token loading.
Existing workspace checks for non-PAT auth remain on their established
paths.

## App-server compatibility

The public app-server `AuthMode` is shared across v1 and v2, and
PAT-backed auth reports `personalAccessToken` through both APIs.
Following human review, this intentionally removes the temporary v1
compatibility mapping that reported PATs as `chatgpt`; the deprecated v1
API is kept in parity with v2 rather than maintaining a separate closed
enum. Clients with exhaustive auth-mode handling in either API version
must add the new case and should generally treat it as ChatGPT-backed
unless they need PAT-specific behavior.

The v1 auth-status response still omits the raw PAT when `includeToken`
is requested because that response cannot carry the account metadata
needed to reuse the credential safely. Persisted PAT auth also omits the
new enum value so older Codex builds can deserialize `auth.json` and
infer PAT auth from the credential field after a rollback.

## Validation

Latest review-fix validation:

- `CARGO_INCREMENTAL=0 just test -p codex-login` (126 passed)
- `CARGO_INCREMENTAL=0 just test -p codex-cli` (263 passed)
- `CARGO_INCREMENTAL=0 just test -p codex-cli
stored_auth_validation_handles_personal_access_token`
- `CARGO_INCREMENTAL=0 just test -p codex-app-server-protocol` (226
passed)
- `CARGO_INCREMENTAL=0 just test -p codex-models-manager
refresh_available_models_uses_remote_only_catalog_for_chatgpt_auth`
- `CARGO_INCREMENTAL=0 just test -p codex-tui
existing_non_oauth_chatgpt_login_counts_as_signed_in`
- `CARGO_INCREMENTAL=0 just fix -p codex-login -p
codex-app-server-protocol -p codex-models-manager -p codex-tui -p
codex-cli`
- `just fmt`
- `git diff --check`

The broader `codex-tui` suite previously compiled and ran 2,834 tests.
Three unrelated environment-sensitive guardian/IDE-socket tests failed
after retries; the PAT-relevant TUI coverage passed.
2026-06-05 17:36:18 -07:00
vie-oaiandGitHub 61a913d9c8 [codex] Gate terminal visualization instructions in TUI (#26013)
## Summary
- add `Feature::TerminalVisualizationInstructions` as
`UnderDevelopment`, disabled by default
- keep terminal visualization instructions inside the TUI package
- append them to existing developer instructions for TUI start, resume,
and fork flows only when enabled
- intentionally do not apply them to `codex exec`

## Rollout
Control behavior is unchanged. TUI dogfooders can enable
`terminal_visualization_instructions`; no default user receives the new
terminal-specific instructions.

The shared visualization-selection rule is supplied separately through
the `codex_proxy_model_3` Statsig layer for every target Codex model
slug in the gated cohort. This TUI feature determines how to render an
appropriate visualization on the terminal surface; the model-layer
treatment determines when to use one.

## Validation
- `cargo test -p codex-tui
terminal_visualization_instructions_are_gated_for_all_tui_thread_flows
--lib`
- `cargo test -p codex-features --lib`
- `cargo fmt --all -- --check`
- `git diff --check`
- GPT-5.4 and GPT-5.5 real prompt-pipeline smoke tests: both visualized
the positive mapping case, abstained on the negative route case, and
passed exact prompt-stack verification on CLI and App
- refreshed onto current `main` with a clean merge and reran the focused
validation

The full 53-probe all-model treatment comparison and requested
production coding evals remain rollout gates before broadening beyond
the initial employee cohort.

This PR remains open for normal human review.
2026-06-05 17:23:45 -07:00
rka-oaiandGitHub ffe90cb5c3 [codex] Use standalone tools for Responses Lite (#26490)
## Summary

Responses Lite does not execute hosted Responses tools, so models using
it must route web search and image generation through Codex-owned
executors & standalone Response's API endpoints.

This PR is stacked on #26487.

## Validation

- `cargo test -p codex-core responses_lite_ --lib`
- `cargo test -p codex-core
standalone_executors_remain_hidden_without_flags_or_responses_lite
--lib`
- `cargo test -p codex-core
hosted_tools_follow_provider_auth_model_and_config_gates --lib`
- `cargo test -p codex-web-search-extension -p
codex-image-generation-extension`
- `cargo test -p codex-app-server --test all standalone_`
- `cargo fmt --all -- --check`
2026-06-06 00:23:40 +00:00
xl-openaiandGitHub 4f655bc3b7 [codex] Remove legacy remote plugin startup sync (#25936)
## Summary

- Remove the legacy startup remote plugin sync path that called
`/plugins/list` and reconciled curated plugin cache/config.
- Remove the `sync_plugins_from_remote` API, its result/error types,
startup marker task, and tests that expected the legacy request.
- Keep the current remote installed bundle sync and remote catalog flows
(`/ps/plugins/installed` and `/ps/plugins/list`) intact.

## Validation

- `just fmt`
- `git diff --check`
- `env HOME=/private/tmp/codex-xin-build-home
USERPROFILE=/private/tmp/codex-xin-build-home just test -p
codex-core-plugins`
- Searched for legacy `/plugins/list` sync references; remaining matches
are `/ps/plugins/list` catalog tests/code.

## Notes

- `just test -p codex-app-server plugin_list` is currently blocked
before running filtered tests by an unrelated compile error in
`app-server/tests/suite/v2/image_generation.rs`:
`app_test_support::McpProcess` is not exported.
2026-06-05 16:33:01 -07:00
Eric TrautandGitHub c62d79259d Block active goals after terminal turn errors (#26690)
## Why

Terminal turn errors can leave a goal active. Automatic goal
continuation may then repeatedly hit a permanent failure, including
compaction requests rejected with HTTP 400, and consume excessive
tokens.

This PR changes the goal extension to treat all turn-ending errors
(including non-retryable errors and retryable errors that have exceeded
their retry count) as "blocking" for the goal. The downside to this
change is that there are some errors that may eventually succeed (e.g. a
429 due to a service outage), and previously the goal runtime would have
kept the agent going in these situations.

## What changed

- Block the current active goal when a turn ends with an error other
than a usage-limit error.
- Preserve the existing `usage_limited` transition for usage-limit
errors.
- Share progress accounting, guarded state updates, metrics, and event
emission in the goal runtime.
2026-06-05 15:54:46 -07:00
pakrym-oaiandGitHub 470c20bf98 protocol: remove submission-side serde from Op (#26674)
## Why

Submission-side `Op` payloads are now an internal handoff inside the
Rust codebase, so keeping a stable serde contract there adds complexity
without a real wire consumer.

## What changed

- remove serde/schema annotations from `Submission`, `Op`, and
submission-only payload types like thread settings overrides, additional
context, realtime conversation params, `TurnEnvironmentSelection`, and
`RequestUserInputResponse`
- delete the `Op` serialization tests and the now-unused double-option
prompt serde helper
- keep event/API-facing serialization where it is still required, and
serialize the `request_user_input` tool output from its wire payload
instead of the core response struct
- update `protocol_v1.md` to call out that events remain the serialized
transport surface while submission payloads are implementation details

## Testing

- `just test -p codex-protocol`
- `cargo check -p codex-core -p codex-app-server -p codex-thread-store`
- `just test -p codex-core request_user_input`
2026-06-05 15:41:13 -07:00
Eric TrautandGitHub 479a14cf59 [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.
2026-06-05 14:17:30 -07:00
xl-openaiandGitHub 679cc08445 [codex] Bound WSL local curated discovery (#26669)
## Context
The installed-app suggestion expansion added in #24996 reads plugin
details for trusted file-backed marketplace candidates because the list
response does not include app ids. On Windows-backed WSL mounts, the
local `openai-curated` checkout lives under `$CODEX_HOME/.tmp/plugins`,
and those per-plugin detail reads can be very slow.

Remote curated already has cached app ids, so it does not need the same
local filesystem traversal.

## Summary
- Keep only the WSL Windows-backed local `openai-curated` checkout on
the legacy fallback/configured discovery path.
- Preserve installed-app expansion for non-WSL file-backed marketplaces
and remote curated.
- Add focused tests for the WSL local curated path predicate.

## Test
- `just test -p codex-core-plugins discoverable`
- `just test -p codex-core plugins::discoverable::tests`
2026-06-05 14:09:40 -07:00
mpc-oaiandGitHub bb7d19bc24 Add JSON output for plugin subcommands (#26631)
## Summary
- Follow-up to #25330 and #26417
- Add `--json` output for `codex plugin add` and `codex plugin remove`
- Add `--json` output for `codex plugin marketplace
add/list/upgrade/remove`
- Keep existing human-readable output unchanged
- Keep existing error handling/stderr behavior unchanged; `--json`
changes successful stdout output only
- Align marketplace add/remove JSON field names with the existing
app-server protocol shape
- Add CLI coverage for plugin and marketplace JSON outputs

## Validation
- `just fmt`
- `just fix -p codex-cli`
- `just test -p codex-cli`
2026-06-05 14:40:31 -05:00
Charlie MarshandGitHub 055c7a7c53 Speed up TUI startup by reusing plugin discovery (#26469)
## Summary

TUI startup loads related plugin data from `hooks/list`, session MCP
initialization, and plugin skill warmup. These paths repeated filesystem
discovery and emitted the same plugin warnings, while `hooks/list` and
account/model bootstrap ran serially.

This change:

- Reuses one immutable plugin load outcome across startup consumers.
- Keys the cache only on plugin-relevant configuration.
- Single-flights concurrent plugin loads and prevents invalidated loads
from repopulating the cache.
- Runs hook discovery and account/model bootstrap concurrently.
- Preserves configuration-migration ordering, hook review behavior, and
accurate startup telemetry.

In 10 alternating release-build launches in the Ruff repository with the
existing `~/.codex` configuration, median time to the first editable
composer decreased from 833ms to 504ms. The branch was faster in 9 of 10
pairs, with a paired median improvement of 312ms.
2026-06-05 15:32:43 -04:00
Charlie MarshandGitHub 345cf6e8d0 Use state DB first for resume --last (#26462)
## Summary

`codex resume --last` currently lists sessions by updated time using
scan-and-repair. Updated-time filesystem listing must stat every rollout
before applying the cwd, provider, and source filters, so startup scales
with the entire local session history...

This change queries the state DB first for the latest matching session.
For local workspaces, we only accept the indexed result when its rollout
path still exists; otherwise we retry with scan-and-repair. The same
lookup path is shared by `fork --last`.

I benchmarked the same `thread/list` request used by `resume --last` in
my local `ruff` checkout against a Codex home with 2,599 active rollouts
totaling 3.7 GiB, including 90 Ruff threads.

Across five fresh release app-server processes with warm filesystem
caches, the state-DB-only lookup had median latency of 0.37-0.44 ms,
while scan-and-repair had median latency of 139-162 ms. First-request
latency was 0.7-1.7 ms versus 142-185 ms.

So this **removes roughly 140-160 ms from the `resume --last` lookup**
on this machine, and makes that lookup over 300x faster.

The tradeoff is that this does leave two correctness gaps:

- If a newer matching rollout is missing from SQLite but an older
matching row exists, the fast path resumes the older thread and never
falls back to the filesystem scan.
- If an existing row has stale filter or ordering metadata, the fast
path can select a different thread from scan-and-repair. The rollout
tests already demonstrate this for stale cwd metadata: state-DB-only
returns the stale match, while scan-and-repair removes and repairs it.

So you could end up seeing the "wrong" result in cases like...

1. A crash or SQLite error occurs between Codex writing the conversation
file and updating SQLite, leaving the newer file unindexed.

2. An older Codex version, restore, or manual copy adds a conversation
file after SQLite’s one-time backfill completed.

These seem pretty rare though (and sessions can always be recovered via
other mechanisms -- `--last` is just a convenience feature), and I think
the tradeoffs are good here?
2026-06-05 14:58:09 -04:00
pakrym-oaiandGitHub 76c0a5379c Make runtime workspace roots absolute in app-server API (#26552)
Stacked on #26532.

## Why

#26532 moves cwd normalization to the app-server/core boundary.
`runtimeWorkspaceRoots` still accepted raw paths in v2 requests and in
`ConfigOverrides`, which left core responsible for interpreting those
roots later. This makes runtime workspace roots follow the same
absolute-path boundary as cwd.

## What

- Change v2 `runtimeWorkspaceRoots` request fields for `thread/start`,
`thread/resume`, `thread/fork`, and `turn/start` to `AbsolutePathBuf`.
- Deduplicate already-absolute runtime roots in app-server handlers and
pass them through `ConfigOverrides.workspace_roots` as
`AbsolutePathBuf`.
- Update TUI and exec client request builders to pass absolute runtime
roots directly.
- Update app-server docs, schema fixtures, and focused tests for
absolute runtime roots.

## Testing

- `just test -p codex-app-server-protocol`
- `just test -p codex-app-server runtime_workspace_roots`
- `just test -p codex-core
session_permission_profile_rebinds_runtime_workspace_roots`
- `just test -p codex-tui app_server_session`
- `just test -p codex-exec`
2026-06-05 11:36:53 -07:00
Ahmed IbrahimandGitHub 8d72fb6de9 [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.
2026-06-05 11:27:10 -07:00
iceweasel-oaiandGitHub 82b15b65e2 [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`.
2026-06-05 11:20:52 -07:00
Felipe CouryandGitHub 679a944dbc fix(tui): restore cancelled prompt cursor at end (#26457)
## Why

Pressing `Esc` on a turn that produced no visible output restores the
submitted prompt so the user can keep editing it. That restore path
preserved the prompt content, images, and mention bindings, but left the
composer cursor at the start of the restored text. The next edit
therefore inserted at the beginning instead of continuing from the end
of the prompt.

## What Changed

- Move the cursor to the end after
`BottomPane::set_composer_text_with_mention_bindings` rehydrates a
restored draft.
- Add test-only cursor accessors so restore tests can assert the
composer state directly.
- Extend the queued restore regression to assert the restored composer
cursor is positioned at `text.len()`.

## How to Test

Manual reviewer flow:

1. Start Codex in the TUI.
2. Submit a prompt that will take long enough to interrupt.
3. Press `Esc` before any visible assistant output appears.
4. Confirm the prompt is restored into the composer and the cursor is at
the end, so typing appends to the prompt.
5. Repeat with a prompt that includes an attached image or resolved
mention and confirm the restored content remains intact.

Targeted tests:

- `just test -p codex-tui
chatwidget::tests::composer_submission::queued_restore_with_remote_images_keeps_local_placeholder_mapping`

Lint note:

- `just argument-comment-lint` is blocked locally by the existing Bazel
`compiler-rt` empty glob failure before analyzing touched code. The
touched Rust diff was manually inspected and adds no new opaque
positional literal callsites.
2026-06-05 15:10:13 -03:00
713192381b fix(tui): Windows composer background (#26181)
## Why

On Windows, the TUI could not shade the composer against the terminal
background because `terminal_palette::default_colors()` always fell back
to `None`. That preserved safety, but it also meant terminals that do
support OSC 10/11 default color replies had no path to report their real
background color.

This keeps the existing fallback behavior for unsupported terminals
while allowing capable Windows terminals to report their default
foreground/background colors during startup.

| Before | After |
|---|---|
| <img width="1235" height="658" alt="win-before"
src="https://github.com/user-attachments/assets/ff756589-fcb3-43de-8f2a-ebc0369b30dd"
/> | <img width="1235" height="658" alt="win-after"
src="https://github.com/user-attachments/assets/9563ff20-4be5-4608-9414-a2afb647e745"
/> |

## What Changed

- Moved the OSC 10/11 default color parser in
`tui/src/terminal_probe.rs` out of the Unix-only implementation so it
can be reused by Windows.
- Added a Windows-only bounded OSC 10/11 probe using raw console handles
and the existing `windows-sys` dependency.
- Added Windows palette caching in `tui/src/terminal_palette.rs` so
startup probe results, including `None`, are reused instead of probing
again later.
- Wired the Windows color probe into TUI startup after the existing
non-Unix crossterm cursor and keyboard checks.
- Added parser coverage for malformed, partial, and noisy OSC color
replies.

If the probe fails, times out, receives only one color, or receives
malformed data, the cache stores `None` and the composer keeps the
current behavior.

## How to Test

1. On Windows, start Codex in a terminal that supports OSC 10/11 default
color replies.
2. Open the TUI composer.
3. Confirm the composer/status area is painted using the terminal's
reported default background, instead of leaving the background unshaded.
4. Start Codex in a terminal that does not answer OSC 10/11, or
otherwise blocks terminal color replies.
5. Confirm startup still succeeds and the composer uses the existing
fallback behavior.

Targeted tests:

- `CARGO_TARGET_DIR=/private/tmp/codex-windows-osc-default-colors-target
just test -p codex-tui terminal_probe`

Additional local verification:

- `CARGO_TARGET_DIR=/private/tmp/codex-windows-osc-default-colors-target
just test -p codex-tui` was run; 2774 tests passed, and two unrelated
Guardian feature-flag tests failed reproducibly when isolated.
- `just argument-comment-lint` was attempted but blocked by the local
Bazel/LLVM `include/sanitizer/*.h` empty glob issue. Touched Rust
literal callsites were inspected manually.
- `cargo check -p codex-tui --target x86_64-pc-windows-msvc` was
attempted after installing the target, but local macOS cross-checking is
blocked by missing Windows C SDK headers in native dependencies
(`ring`/`aws-lc-sys`).

---------

Co-authored-by: Kevin Bond <kbond@openai.com>
2026-06-05 11:05:46 -07:00
Eric TrautandGitHub a8c9530911 [1 of 2] Align goal extension with core behavior (#26547)
## 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

The goal runtime is moving out of `codex-core` and into
`codex-goal-extension`. This first PR brings the extension back in line
with the current core behavior before the follow-up PR switches
app-server sessions over to the extension, so that review can focus on
ownership and wiring rather than hidden behavior drift.

## What Changed

- Updates the extension `create_goal` and `update_goal` tool
schemas/descriptions to match the current core wording for explicit
token budgets, blocked-goal audits, resumed blocked goals, and
system-owned budget/usage-limit transitions.
- Marks `codex-goal-extension` as the live `/goal` extension crate
rather than an unwired sketch.
- Looks up the live thread before reading goal state for idle
continuation, so continuation setup exits early when no live thread can
accept the automatic turn.
2026-06-05 10:37:38 -07:00
Shijie RaoandGitHub 78eba34b41 Clean up Rust release workflow (#26335)
## Why
PR #26252 moved macOS release signing into the tag-triggered
`rust-release` workflow through the protected `codesigning` environment
and Azure Key Vault. That leaves the old manual unsigned-build /
signed-promotion handoff as dead compatibility scaffolding: it makes the
release DAG harder to reason about and keeps paths around that the
current release process no longer intends to operate.

## What changed
- Remove the manual `workflow_dispatch` inputs and validation for
`build_unsigned`, `promote_signed`, and the deprecated `sign_macos`
flag.
- Drop the `stage-signed-macos` job and the promotion-specific artifact
download, re-upload, pruning, and cleanup logic.
- Make tag-pushed releases always follow the signed release path: build,
sign, package, finalize, publish, and then run downstream release jobs
from `release` success.
- Remove stale `SIGN_MACOS` / `sign_macos` conditions and outputs,
including downstream gates for npm, DotSlash, WinGet, dev website
deploy, and `latest-alpha-cli` branch updates.

## Verification
- `ruby -e 'require "yaml"; YAML.load_file(ARGV.fetch(0)); puts "yaml
ok"' .github/workflows/rust-release.yml`
- `git diff --check`
- `rg -n
"workflow_dispatch|inputs\\.|release_mode|build_unsigned|SIGN_MACOS|outputs\\.sign_macos|sign_macos\\b"
.github/workflows/rust-release.yml` returned no matches
2026-06-05 10:36:14 -07:00