mirror of
https://github.com/pchuan98/codex.git
synced 2026-07-01 00:31:56 +08:00
7c11c14efc693c19f59dadfccc7abcdc35bbaf89
641 Commits
-
[codex] Support multiple forced ChatGPT workspaces (#18161)
## Summary This change lets `forced_chatgpt_workspace_id` accept multiple workspace IDs instead of a single value. It keeps the existing config key name, adds backward-compatible parsing for a single string in `config.toml`, and normalizes the setting into an allowed workspace list across login enforcement, app-server config surfaces, and local ChatGPT auth helpers. ## Why Workspace-restricted deployments may need to allow more than one ChatGPT workspace without dropping the guardrail entirely. ## Server-side impact Codex's local server and app-server protocol needed changes because they previously assumed a single workspace ID. The local login flow now matches the auth backend interface by sending the allowed workspace list as a single comma-separated `allowed_workspace_id` query parameter. ## Validation This was tested with: - A single workspace config - With multi-workspace configs - With multiple workspaces in the config - The user only being a part of a subset of them All were successful. Automated coverage: - `cargo test -p codex-login` - `cargo test -p codex-app-server-protocol` - `cargo test -p codex-tui local_chatgpt_auth` - `cargo test --locked -p codex-app-server login_account_chatgpt_includes_forced_workspace_allowlist_query_param`
rreichel3-oai ·
2026-05-14 17:11:36 -04:00 -
Prefer the model list fetched from the backend for SIWC users (#22547)
## Summary - For SIWC users, update the model list merging logic to prefer the model list fetched from the backend over the bundled model list (this is needed for special cases where users have a more limited set of models they're allowed to use) - Add or update tests covering the revised cache behavior ## Testing - Added/updated unit tests in `codex-rs/models-manager/src/manager_tests.rs` - Not run (not requested)
Rajeev Nayak ·
2026-05-14 13:45:49 -04:00 -
tests: avoid ambient temp sandbox roots (#22576)
## Why Some sandboxed integration tests enabled both ambient temp roots (`TMPDIR` and literal `/tmp`) even though they were not testing temp-root behavior. On Linux bwrap, making `/tmp` writable causes protected metadata mount targets such as `/tmp/.git`, `/tmp/.agents`, and `/tmp/.codex` to be synthesized. If a run is interrupted, those top-level markers can be left behind and contaminate later tests. ## What changed For the incidental integration tests that do not need ambient temp-root access, set `exclude_tmpdir_env_var` and `exclude_slash_tmp` to `true`. Dedicated protected-metadata coverage remains in the lower-level sandbox tests that use isolated temp roots. ## Verification Focused remote devbox repros passed with a watcher polling `/tmp/.git`, `/tmp/.agents`, and `/tmp/.codex`; no leaked markers were observed.
starr-openai ·
2026-05-14 10:04:24 -07:00 -
permissions: canonicalize workspace_roots and danger-full-access names (#22624)
## Why This is a small precursor to the larger permissions-migration work. Both the comparison stack in [#22401](https://github.com/openai/codex/pull/22401) / [#22402](https://github.com/openai/codex/pull/22402) and the alternate stack in [#22610](https://github.com/openai/codex/pull/22610) / [#22611](https://github.com/openai/codex/pull/22611) / [#22612](https://github.com/openai/codex/pull/22612) are easier to review if the terminology is already settled underneath them. Because `:project_roots` and `:danger-no-sandbox` have not shipped as stable user-facing surface area, carrying them forward as aliases would just add more migration logic to the later stacks. This PR removes that ambiguity now so the follow-on work can rely on one spelling for each built-in concept. ## What Changed - renamed the config-facing special filesystem key from `:project_roots` to `:workspace_roots` - dropped unpublished `:project_roots` parsing support in `core/src/config/permissions.rs`, so new config only recognizes `:workspace_roots` - renamed the built-in full-access permission profile id from `:danger-no-sandbox` to `:danger-full-access` - dropped unpublished `:danger-no-sandbox` support entirely, including the old active-profile canonicalization path, and added explicit rejection coverage for the legacy id - introduced shared built-in permission-profile id constants in `codex-rs/protocol/src/models.rs` - updated `core`, `app-server`, and `tui` call sites that special-case built-in profiles to use the shared constants and canonical ids - updated tests and the Linux sandbox README to use `:workspace_roots` / `:danger-full-access` ## Verification I focused verification on the three places this rename can regress: config parsing, active-profile identity surfaced back out of `core`, and user/server call sites that special-case built-in profiles. Targeted checks: - `config::tests::default_permissions_can_select_builtin_profile_without_permissions_table` - `config::tests::default_permissions_read_only_applies_additional_writable_roots_as_modifications` - `config::tests::default_permissions_can_select_builtin_full_access_profile` - `config::tests::legacy_danger_no_sandbox_is_rejected` - `workspace_root` filtered `codex-core` tests - `request_processors::thread_processor::thread_processor_tests::thread_processor_behavior_tests::requested_permissions_trust_project_uses_permission_profile_intent` - `suite::v2::turn_start::turn_start_rejects_invalid_permission_selection_before_starting_turn` - `status::tests::status_snapshot_shows_auto_review_permissions` - `status::tests::status_permissions_full_disk_managed_with_network_is_danger_full_access` - `app_server_session::tests::embedded_turn_permissions_use_active_profile_selection`
Michael Bolin ·
2026-05-14 08:45:54 -07:00 -
feat: add layered --profile-v2 config files (#17141)
## Why `--profile-v2 <name>` gives launchers and runtime entry points a named profile config without making each profile duplicate the base user config. The base `$CODEX_HOME/config.toml` still loads first, then `$CODEX_HOME/<name>.config.toml` layers above it and becomes the active writable user config for that session. That keeps shared defaults, plugin/MCP setup, and managed/user constraints in one place while letting a named profile override only the pieces that need to differ. ## What Changed - Added the shared `--profile-v2 <name>` runtime option with validated plain names, now represented by `ProfileV2Name`. - Extended config layer state so the base user config and selected profile config are both `User` layers; APIs expose the active user layer and merged effective user config. - Threaded profile selection through runtime entry points: `codex`, `codex exec`, `codex review`, `codex resume`, `codex fork`, and `codex debug prompt-input`. - Made user-facing config writes go to the selected profile file when active, including TUI/settings persistence, app-server config writes, and MCP/app tool approval persistence. - Made plugin, marketplace, MCP, hooks, and config reload paths read from the merged user config so base and profile layers both participate. - Updated app-server config layer schemas to mark profile-backed user layers. ## Limits `--profile-v2` is still rejected for config-management subcommands such as feature, MCP, and marketplace edits. Those paths remain tied to the base `config.toml` until they have explicit profile-selection semantics. Some adjacent background writes may still update base or global state rather than the selected profile: - marketplace auto-upgrade metadata - automatic MCP dependency installs from skills - remote plugin sync or uninstall config edits - personality migration marker/default writes ## Verification Added targeted coverage for profile name validation, layer ordering/merging, selected-profile writes, app-server config writes, session hot reload, plugin config merging, hooks/config fixture updates, and MCP/app approval persistence. --------- Co-authored-by: Codex <noreply@openai.com>
jif-oai ·
2026-05-14 15:16:15 +02:00 -
Relax remote plugin sync gate (#22594)
## Summary - Allow remote installed-plugin cache refresh to start whenever plugins are enabled. - Allow remote installed-plugin bundle sync to start whenever plugins are enabled. - Remove the extra local `remote_plugin_enabled` guard from those background sync paths. ## Context Server-side installed plugin state and optional bundle URL behavior are owned by plugin-service `/public/plugins/installed`, so these local sync paths only need the overall plugin enablement gate. ## Test plan - `just fmt` - `cargo test -p codex-core-plugins`
xli-oai ·
2026-05-14 03:38:30 +00:00 -
enable/disable remote control at runtime, not via features (#22578)
## Why reapplies https://github.com/openai/codex/pull/22386 which was previously reverted Also, introduce `remoteControl/enable` and `remoteControl/disable` app-server APIs to toggle on/off remote control at runtime for a given running app-server instance. ## What Changed - Adds experimental v2 RPCs: - `remoteControl/enable` - `remoteControl/disable` - Adds `RemoteControlRequestProcessor` and routes the new RPCs through it instead of `ConfigRequestProcessor`. - Adds named `RemoteControlHandle::enable`, `disable`, and `status` methods. - Makes `remoteControl/enable` return an error when sqlite state DB is unavailable, while keeping enrollment/websocket failures as async status updates. - Adds `AppServerRuntimeOptions.remote_control_enabled` and hidden `--remote-control` flags for `codex app-server` and `codex-app-server`. - Updates managed daemon startup to use `codex app-server --remote-control --listen unix://`. - Marks `Feature::RemoteControl` as removed and ignores `[features].remote_control`. - Updates app-server README entries for the new remote-control methods.
Owen Lin ·
2026-05-14 01:07:46 +00:00 -
[codex] Canonicalize shared workspace plugin IDs (#22564)
## Summary - Canonicalize private and unlisted workspace shared plugin IDs to `workspace-shared-with-me`. - Keep `plugin/list` private/unlisted shared-with-me buckets as UI grouping only. - Update share read/list/checkout and cache cleanup coverage for the canonical namespace. ## Tests - `cargo test -p codex-app-server --test all plugin_list_fetches_shared_with_me_kind` - `cargo test -p codex-app-server --test all plugin_read_returns_share_context_for_shared_remote_plugin` - `cargo test -p codex-app-server --test all suite::v2::plugin_share` - `cargo test -p codex-core-plugins list_remote_plugin_shares_fetches_created_workspace_plugins` - `cargo test -p codex-core-plugins stale_remote_plugin_cleanup_removes_old_shared_with_me_cache_and_keeps_canonical_cache` - `git diff --check`
xl-openai ·
2026-05-13 16:29:47 -07:00 -
fix: prevent codex-backend from stealing originator (#22533)
## Why Remote control starts by letting `codex-backend` initialize against the app-server as an infrastructure health/proxy client before the real remote client connects. App-server initialization also sets the process-wide `originator` from `client_info.name`, so `codex-backend` could become the sticky originator for later model/API requests even after the real client initialized. ## What changed - Treat `codex-backend` as a non-originating initialize client, alongside the existing `codex_app_server_daemon` probe client. - Preserve normal per-connection initialize behavior, including session metadata and initialize analytics. - Add regression coverage that verifies `codex-backend` initialize does not replace the default originator. ## Testing - `cargo test -p codex-app-server --test all initialize_codex_backend_does_not_override_originator`
Owen Lin ·
2026-05-13 12:38:34 -07:00 -
chore(config) rm tools.view_image (#22501)
## Summary It appears this config flag has been broken/a noop for quite some time: since https://github.com/openai/codex/pull/8850. Let's simplify and get rid of this. ## Testing - [x] Updated unit tests
Dylan Hurd ·
2026-05-13 12:35:37 -07:00 -
config: add strict config parsing (#20559)
## Why Codex intentionally ignores unknown `config.toml` fields by default so older and newer config files keep working across versions. That leniency also makes typo detection hard because misspelled or misplaced keys disappear silently. This change adds an opt-in strict config mode so users and tooling can fail fast on unrecognized config fields without changing the default permissive behavior. This feature is possible because `serde_ignored` exposes the exact signal Codex needs: it lets Codex run ordinary Serde deserialization while recording fields Serde would otherwise ignore. That avoids requiring `#[serde(deny_unknown_fields)]` across every config type and keeps strict validation opt-in around the existing config model. ## What Changed ### Added strict config validation - Added `serde_ignored`-based validation for `ConfigToml` in `codex-rs/config/src/strict_config.rs`. - Combined `serde_ignored` with `serde_path_to_error` so strict mode preserves typed config error paths while also collecting fields Serde would otherwise ignore. - Added strict-mode validation for unknown `[features]` keys, including keys that would otherwise be accepted by `FeaturesToml`'s flattened boolean map. - Kept typed config errors ahead of ignored-field reporting, so malformed known fields are reported before unknown-field diagnostics. - Added source-range diagnostics for top-level and nested unknown config fields, including non-file managed preference source names. ### Kept parsing single-pass per source - Reworked file and managed-config loading so strict validation reuses the already parsed `TomlValue` for that source. - For actual config files and managed config strings, the loader now reads once, parses once, and validates that same parsed value instead of deserializing multiple times. - Validated `-c` / `--config` override layers with the same base-directory context used for normal relative-path resolution, so unknown override keys are still reported when another override contains a relative path. ### Scoped `--strict-config` to config-heavy entry points - Added support for `--strict-config` on the main config-loading entry points where it is most useful: - `codex` - `codex resume` - `codex fork` - `codex exec` - `codex review` - `codex mcp-server` - `codex app-server` when running the server itself - the standalone `codex-app-server` binary - the standalone `codex-exec` binary - Commands outside that set now reject `--strict-config` early with targeted errors instead of accepting it everywhere through shared CLI plumbing. - `codex app-server` subcommands such as `proxy`, `daemon`, and `generate-*` are intentionally excluded from the first rollout. - When app-server strict mode sees invalid config, app-server exits with the config error instead of logging a warning and continuing with defaults. - Introduced a dedicated `ReviewCommand` wrapper in `codex-rs/cli` instead of extending shared `ReviewArgs`, so `--strict-config` stays on the outer config-loading command surface and does not become part of the reusable review payload used by `codex exec review`. ### Coverage - Added tests for top-level and nested unknown config fields, unknown `[features]` keys, typed-error precedence, source-location reporting, and non-file managed preference source names. - Added CLI coverage showing invalid `--enable`, invalid `--disable`, and unknown `-c` overrides still error when `--strict-config` is present, including compound-looking feature names such as `multi_agent_v2.subagent_usage_hint_text`. - Added integration coverage showing both `codex app-server --strict-config` and standalone `codex-app-server --strict-config` exit with an error for unknown config fields instead of starting with fallback defaults. - Added coverage showing unsupported command surfaces reject `--strict-config` with explicit errors. ## Example Usage Run Codex with strict config validation enabled: ```shell codex --strict-config ``` Strict config mode is also available on the supported config-heavy subcommands: ```shell codex --strict-config exec "explain this repository" codex review --strict-config --uncommitted codex mcp-server --strict-config codex app-server --strict-config --listen off codex-app-server --strict-config --listen off ``` For example, if `~/.codex/config.toml` contains a typo in a key name: ```toml model = "gpt-5" approval_polic = "on-request" ``` then `codex --strict-config` reports the misspelled key instead of silently ignoring it. The path is shortened to `~` here for readability: ```text $ codex --strict-config Error loading config.toml: ~/.codex/config.toml:2:1: unknown configuration field `approval_polic` | 2 | approval_polic = "on-request" | ^^^^^^^^^^^^^^ ``` Without `--strict-config`, Codex keeps the existing permissive behavior and ignores the unknown key. Strict config mode also validates ad-hoc `-c` / `--config` overrides: ```text $ codex --strict-config -c foo=bar Error: unknown configuration field `foo` in -c/--config override $ codex --strict-config -c features.foo=true Error: unknown configuration field `features.foo` in -c/--config override ``` Invalid feature toggles are rejected too, including values that look like nested config paths: ```text $ codex --strict-config --enable does_not_exist Error: Unknown feature flag: does_not_exist $ codex --strict-config --disable does_not_exist Error: Unknown feature flag: does_not_exist $ codex --strict-config --enable multi_agent_v2.subagent_usage_hint_text Error: Unknown feature flag: multi_agent_v2.subagent_usage_hint_text ``` Unsupported commands reject the flag explicitly: ```text $ codex --strict-config cloud list Error: `--strict-config` is not supported for `codex cloud` ``` ## Verification The `codex-cli` `strict_config` tests cover invalid `--enable`, invalid `--disable`, the compound `multi_agent_v2.subagent_usage_hint_text` case, unknown `-c` overrides, app-server strict startup failure through `codex app-server`, and rejection for unsupported commands such as `codex cloud`, `codex mcp`, `codex remote-control`, and `codex app-server proxy`. The config and config-loader tests cover unknown top-level fields, unknown nested fields, unknown `[features]` keys, source-location reporting, non-file managed config sources, and `-c` validation for keys such as `features.foo`. The app-server test suite covers standalone `codex-app-server --strict-config` startup failure for an unknown config field. ## Documentation The Codex CLI docs on developers.openai.com/codex should mention `--strict-config` as an opt-in validation mode for supported config-heavy entry points once this ships.
Michael Bolin ·
2026-05-13 16:08:05 +00:00 -
feat: Add plugin share checkout (#22435)
Adds plugin/share/checkout to turn a shared remote plugin into a local working copy under ~/plugins/<name>. Registers the copy in the managed personal marketplace and records the remote-to-local mapping for later share/save flows. --------- Co-authored-by: Codex <noreply@openai.com>
xl-openai ·
2026-05-13 00:50:29 -07:00 -
Use root repo hooks in linked worktrees (#21969)
# Why Linked worktrees currently load their own project hook declarations, so the same repo can present different hook definitions depending on which checkout is active. https://github.com/openai/codex/pull/21762 tried to share trust by giving matching worktree hooks a shared synthetic key, but review pointed out that divergent worktree hook definitions would then fight over one `trusted_hash`. Instead of introducing a second trust model, this makes linked worktrees use the root checkout as the single source of truth for project hook declarations. Worktree-local project config can still diverge for unrelated settings, but project hooks now keep one real source path and one trust state per repo. # What - Teach project config loading to remember the matching root-checkout `.codex/` folder for actual linked-worktree project layers. - Keep ordinary project config sourced from the worktree, but replace project hook declarations with the root checkout's matching layer before hook discovery runs, including linked-worktree layers with `.codex/` but no local `config.toml`. - Make hook discovery use that authoritative hook folder for both `hooks.json` and TOML hook source paths, so linked worktrees produce the same hook key and trust state as the root checkout. - Cover the linked-worktree path plus regressions for missing worktree `config.toml` and nested non-worktree project roots.
Abhinav ·
2026-05-13 06:58:58 +00:00 -
feat: Split shared workspace plugins by discoverability (#22425)
- Keep shared-with-me as the plugin/list request kind, but return private plugins under workspace-shared-with-me-private. - Add workspace-shared-with-me-unlisted for installed workspace plugins with UNLISTED discoverability,
xl-openai ·
2026-05-12 21:11:19 -07:00 -
Restore app-server websocket listener with auth guard (#22404)
## Why PR #21843 removed the TCP websocket app-server listener, but that also removed functionality that still needs to exist. Restoring it as-is would reopen the old remote exposure problem, so this keeps the restored listener while making remote and non-loopback usage require explicit auth. ## What Changed - Mostly reverts #21843 and reapplies the small merge-conflict resolutions needed on top of current main. - Restores ws://IP:PORT parsing, the app-server TCP websocket acceptor, websocket auth CLI flags, and the associated tests. - The only intentional behavior change from the restored code is that non-loopback websocket listeners now fail startup unless --ws-auth capability-token or --ws-auth signed-bearer-token is configured. Loopback listeners remain available for local and SSH-forwarding workflows. ## Reviewer Focus Please focus review on the small auth-enforcement delta layered on top of the revert: - codex-rs/app-server-transport/src/transport/websocket.rs: start_websocket_acceptor now rejects unauthenticated non-loopback websocket binds before accepting connections. - codex-rs/app-server-transport/src/transport/auth.rs: helper logic classifies unauthenticated non-loopback listeners. - codex-rs/app-server/tests/suite/v2/connection_handling_websocket.rs: tests cover unauthenticated ws://0.0.0.0 startup rejection and authenticated non-loopback capability-token startup. Everything else is intended to be revert/merge-conflict restoration rather than new product behavior. ## Verification - Manually verified that TUI remoting is restored and that auth is enforced for non-localhost urls.
Eric Traut ·
2026-05-12 18:40:53 -07:00 -
feat: Expose plugin versions and gate plugin sharing (#22397)
- Adds localVersion to plugin summaries and remoteVersion to share context, including generated API schemas. - Hydrates local and remote plugin versions from manifests and remote release metadata. - Adds default-on plugin_sharing gate for shared-with-me listing and plugin/share/save, with disabled-path errors and focused coverage.xl-openai ·
2026-05-12 17:56:30 -07:00 -
Unify thread metadata updates above store (#22236)
- make ThreadStore::update_thread_metadata accept a broad range of metadata patches - keep ThreadStore::append_items as raw canonical history append (no metadata side effects) - in the local store, write these metadata updates to a combination of sqlite and rollout jsonl files for backwards-compat. It special cases which fields need to go into jsonl vs sqlite vs whatever, confining the awkwardness to just this implementation - in remote stores we can simply persist the metadata directly to a database, no special casing required. - move the "implicit metadata updates triggered by appending rollout items" from the RolloutRecorder (which is local-threadstore-specific) to the LiveThread layer above the ThreadStore, inside of a private helper utility called ThreadMetadataSync. LiveThread calls ThreadStore append_items and update_metadata separately. - Add a generic update metadata method to ThreadManager that works on both live threads and "cold" threads - Call that ThreadManager method from app server code, so app server doesn't need to worry about whether the thread is live or not
Tom ·
2026-05-13 00:28:15 +00:00 -
feat: Normalize remote plugin summary identities. (#22265)
Makes plugin summaries use config-style plugin@marketplace IDs while exposing backend remote IDs separately as remotePluginId. Also fix the consistency issue of REMOTE_SHARED_WITH_ME_MARKETPLACE_NAME
xl-openai ·
2026-05-12 00:58:37 -07:00 -
Add Windows hook command overrides (#22159)
# Why Managed hook configs need a shared cross-platform shape without making the existing `command` field polymorphic. The common case is still one command string, with Windows needing a different entrypoint only when the runtime is actually Windows. Keeping `command` as the portable/default path and adding an optional Windows override keeps the config easier to read, preserves the existing scalar shape for non-Windows users, and avoids forcing every caller into a `{ unix, windows }` object when only one platform needs special handling. # What - Add optional `command_windows` / `commandWindows` alongside the existing hook `command` field. - Resolve `command_windows` only on Windows during hook discovery; other platforms continue to use `command` unchanged. - Keep trust hashing aligned to the effective command selected for the current runtime. # Docs The Codex hooks/config reference should document `command_windows` as the Windows-only override for command hooks.Abhinav ·
2026-05-11 22:22:29 +00:00 -
fix(app-server): thread history redaction for remote clients (#22178)
## Summary Remote clients can still receive large `thread/resume` histories when prior turns include MCP tool call payloads or image-generation results. This adds a temporary response-only redaction path for the known remote client names. Longer term we will move towards fully paginated APIs backed by SQLite. ## Changes - Redact MCP tool call payload-bearing fields in `thread/resume` responses for `codex_chatgpt_android_remote` and `codex_chatgpt_ios_remote`. - Drop `imageGeneration` items from those `thread/resume` responses. - Keep redaction out of persisted rollout files, `thread/read`, `thread/turns/list`, live notifications, and token usage replay. - Cover the behavior with app-server helper tests and a v2 resume integration test that checks both remote clients plus a non-target control client. ## Testing - `cargo test -p codex-app-server thread_resume_redaction` - `cargo test -p codex-app-server thread_resume_redacts_payloads_for_chatgpt_remote_clients`
Owen Lin ·
2026-05-11 11:45:25 -07:00 -
Unified mentions in TUI (#19068)
This PR replaces the TUI’s file-only `@mention` popup with a unified mentions experience. Typing `@...` now searches across filesystem matches, installed plugins, and skills in one popup, with result types clearly labeled and selectable from the same flow. - Adds a unified `@mentions` popup that returns: - plugins - skills - files - directories - Adds search modes so users can narrow the popup without changing their query: - All Results _(default/same as Codex App)_ - Filesystem Only - Plugins _(...and skills)_ - Preserves existing insertion behavior: - selected file paths are inserted into the prompt - paths with spaces are quoted - image file selections still attach as images when possible - selecting a plugin or skill inserts the corresponding `$name` - the composer records the canonical mention binding, such as `plugin://...` or the skill path - Expanded `@mentions` rendering: - type tags for Plugin, Skill, File, and Dir - distinct plugin/filesystem colors - stable fixed-height layout (8 rows) - truncation behavior for narrow terminals Note: - The unified mentions popup does not display app connectors under `@mention` results for Codex App parity. Connector mentions remain available through the existing `$mention` path. https://github.com/user-attachments/assets/f93781ed-57d3-4cb5-9972-675bc5f3ef3f
canvrno-oai ·
2026-05-11 11:34:52 -07:00 -
Fix goal update and add
/goal editcommand in TUI (#21954)## Why Users have requested the ability to edit a goal's objective after a goal has been created. This PR exposes a new `/goal edit` command in the TUI to address this request. In the process of implementing this, I also noticed an existing bug in the goal runtime. When a goal's objective is updated through the `thread/goal/set` app server API, the goal runtime didn't emit a new steering prompt to tell the agent about the new objective. This PR also fixes this hole. ## What Changed - Adds `/goal edit` in the TUI, opening an edit box prefilled with the current goal objective. - Keeps active and paused goals in their current state, resets completed goals to active, keeps budget-limited goals budget-limited, and preserves the existing token budget. - Changes the existing `thread/goal/set` behavior so editing an objective preserves goal accounting instead of resetting it. The older reset-on-new-objective behavior was left over from before `thread/goal/clear`; clients that need to reset accounting can now clear the existing goal and create a new one. - Reuses the existing goal set API path; this does not add or change app-server protocol surface area. - Adds a dedicated goal runtime steering prompt when an externally persisted goal mutation changes the objective, so active turns receive the updated objective. ## Validation - Make sure `/goal edit` returns an error if no goal currently exists - Make sure `/goal edit` displays an edit box that can be optionally canceled with no side effects - Make sure that an edited goal results in a steer so the agent starts pursuing the new objective - Make sure the new objective is reflected in the goal if you use `/goal` to display the goal summary - Make sure that `/goal edit` doesn't reset the token budget, time/token accounting on the updated goal
Eric Traut ·
2026-05-11 10:49:19 -07:00 -
app-server: remove TCP websocket listener (#21843)
## Why The app-server no longer needs to expose a TCP websocket listener. Keeping that transport also kept around a separate listener/auth surface that is unnecessary now that local clients can use stdio or the Unix-domain control socket, while remote connectivity is handled by `remote_control`. ## What Changed - Removed `ws://IP:PORT` parsing and the `AppServerTransport::WebSocket` startup path. - Deleted the app-server websocket listener auth module and removed related CLI flags/dependencies. - Kept websocket framing only where it is still needed: over the Unix-domain control socket and in the outbound `remote_control` connection. - Updated app-server CLI/help text and `app-server/README.md` to document only `stdio://`, `unix://`, `unix://PATH`, and `off` for local transports. - Converted affected app-server integration coverage from TCP websocket listeners to UDS-backed websocket connections, and added a parse test that rejects `ws://` listen URLs. - Removed the now-unused workspace `constant_time_eq` dependency and refreshed `Cargo.lock` after `cargo shear` caught the drift. - Moved test app-server UDS socket paths to short Unix temp paths so macOS Bazel test sandboxes do not exceed Unix socket path limits. ## Verification - Added/updated tests around UDS websocket transport behavior and `ws://` listen URL rejection. - `cargo shear` - `cargo metadata --no-deps --format-version 1` - `cargo test -p codex-app-server unix_socket_transport` - `cargo test -p codex-app-server unix_socket_disconnect` - `just fix -p codex-app-server` - `git diff --check` Local full Rust test execution was blocked before compilation by an external fetch failure for the pinned `nornagon/crossterm` git dependency. `just bazel-lock-update` and `just bazel-lock-check` were retried after the manifest cleanup but remain blocked by external BuildBuddy/V8 fetch timeouts.
Ruslan Nigmatullin ·
2026-05-11 10:17:26 -07:00 -
Read cached metadata for installed Git plugins (#20825)
## Summary - Populate `plugin/list` interface metadata for installed Git-sourced marketplace plugins from the active cached plugin bundle. - Preserve marketplace category precedence so list behavior matches `plugin/read`. - Keep existing fallback behavior when the cache or manifest is missing or invalid. ## Test Plan - `cd codex-rs && just fmt` - `cd codex-rs && cargo test -p codex-core-plugins list_marketplaces_installed_git_source_reads_metadata_from_cache_without_cloning` - `cd codex-rs && cargo test -p codex-app-server plugin_list_returns_installed_git_source_interface_from_cache` - `cd codex-rs && just fix -p codex-core-plugins` - `cd codex-rs && just fix -p codex-app-server` - `git diff --check` Server-truth check: OpenAI monorepo app-server generated types already expose `PluginSummary.interface`, and the webview consumes it for plugin cards. This PR keeps the protocol/schema unchanged and fills the existing field from the cached installed bundle for Git-backed cross-repo plugins.
xli-oai ·
2026-05-10 16:59:57 -07:00 -
feat: Add role-aware plugin share context APIs (#21867)
Expose discoverability and full share principals in share context, carry roles through save/updateTargets, hydrate local shared plugin reads, and keep share URLs only under plugin.shareContext.
xl-openai ·
2026-05-08 20:46:39 -07:00 -
Reapply "Move skills watcher to app-server" (#21652)
## Why PR #21460 reverted the earlier move of skills change watching from `codex-core` into app-server. This reapplies that boundary change so app-server owns client-facing `skills/changed` notifications and core no longer carries the watcher. ## What - Restore the app-server `SkillsWatcher` and register it from thread listener setup. - Remove the core-owned skills watcher and its core live-reload integration surface. - Restore app-server coverage for `skills/changed` notifications after a watched skill file changes. ## Validation - `cargo test -p codex-app-server --test all suite::v2::skills_list::skills_changed_notification_is_emitted_after_skill_change -- --exact --nocapture` - `cargo test -p codex-core --lib --no-run`
pakrym-oai ·
2026-05-08 17:41:15 -07:00 -
app-server: support daemon-safe restart handling (#21831)
## Why The app-server daemon work needs two app-server behaviors to be safe when lifecycle management is driven by a helper process: - a readiness probe must not become the process-wide client identity just because it connects first - a graceful reload signal needs to keep draining active turns even if it is delivered more than once ## What changed - Treat `codex_app_server_daemon` initialization as a probe-only client for process-global originator and user-agent suffix state. - Distinguish forceable shutdown signals from graceful-only ones, and treat Unix `SIGHUP` as graceful-only while leaving `SIGTERM` and Ctrl-C forceable. - Add regression coverage for daemon probe initialization and repeated `SIGHUP` delivery while a turn is still running. ## Testing - `cargo test -p codex-app-server` - The new daemon-probe and repeated-`SIGHUP` coverage passed. - The run still failed in the existing `suite::conversation_summary::get_conversation_summary_by_relative_rollout_path_resolves_from_codex_home` and `suite::conversation_summary::get_conversation_summary_by_thread_id_reads_rollout` tests because their initialize handshake timed out. - `cargo test -p codex-app-server --test all suite::conversation_summary::` - Reproduced the same two existing initialize-timeout failures in isolation.
Ruslan Nigmatullin ·
2026-05-08 15:47:51 -07:00 -
Make environment provider snapshots path-free (#21794)
## Summary - make EnvironmentProvider::snapshot path-free and keep providers focused on provider-owned remote environments - let provider snapshots request local inclusion via include_local, with environments.toml including local and CODEX_EXEC_SERVER_URL excluding local - move reserved local environment construction into EnvironmentManager using ExecServerRuntimePaths Follow-up to https://github.com/openai/codex/pull/20667 ## Testing - just fmt - git diff --check - devbox: bazel build --bes_backend= --bes_results_url= //codex-rs/exec-server:exec-server - devbox: bazel test --bes_backend= --bes_results_url= //codex-rs/exec-server:exec-server-unit-tests Co-authored-by: Codex <noreply@openai.com>
starr-openai ·
2026-05-08 15:30:00 -07:00 -
[codex] request desktop attestation from app (#20619)
## Summary TL;DR: teaches `codex-rs` / app-server to request a desktop-provided attestation token and attach it as `x-oai-attestation` on the scoped ChatGPT Codex request paths.  ## Details This PR teaches the Codex app-server runtime how to request and attach an attestation token. It does not generate DeviceCheck tokens directly; instead, it relies on the connected desktop app to advertise that it can generate attestation and then asks that app for a fresh header value when needed. The flow is: 1. The Codex desktop app connects to app-server. 2. During `initialize`, the app can advertise that it supports `requestAttestation`. 3. Before app-server calls selected ChatGPT Codex endpoints, it sends the internal server request `attestation/generate` to the app. 4. app-server receives a pre-encoded header value back. 5. app-server forwards that value as `x-oai-attestation` on the scoped outbound requests. The code in this repo is mostly protocol and runtime plumbing: it adds the app-server request/response shape, introduces an attestation provider in core, wires that provider into Responses / compaction / realtime setup paths, and covers the intended scoping with tests. The signed macOS DeviceCheck generation remains owned by the desktop app PR. ## Related PR - Codex desktop app implementation: https://github.com/openai/openai/pull/878649 ## Validation <details> <summary>Tests run</summary> ```sh cargo test -p codex-app-server-protocol cargo test -p codex-core attestation --lib cargo test -p codex-app-server --lib attestation ``` Also ran: ```sh just fix -p codex-core just fix -p codex-app-server just fix -p codex-app-server-protocol just fmt just write-app-server-schema ``` </details> <details> <summary>E2E DeviceCheck validation</summary> First validated the signed desktop app boundary directly: launched a packaged signed `Codex.app`, sent `attestation/generate`, decoded the returned `v1.` attestation header, and validated the extracted DeviceCheck token with `personal/jm/verify_devicecheck_token.py` using bundle ID `com.openai.codex`. Apple returned `status_code: 200` and `is_ok: true`. Then ran the fuller app + app-server flow. The packaged `Codex.app` launched a current-branch app-server via `CODEX_CLI_PATH`, and a local MITM proxy intercepted outbound `chatgpt.com` traffic. The app-server requested `attestation/generate` from the real Electron app process, and the intercepted `/backend-api/codex/responses` traffic included `x-oai-attestation` on both routes: ```text GET /backend-api/codex/responses Upgrade: websocket x-oai-attestation: present POST /backend-api/codex/responses Upgrade: none x-oai-attestation: present ``` The captured header decoded to a DeviceCheck token that also validated with Apple for `com.openai.codex` (`status_code: 200`, `is_ok: true`, team `2DC432GLL2`). </details> --------- Co-authored-by: Codex <noreply@openai.com>
Jiaming Zhang ·
2026-05-08 12:36:02 -07:00 -
[codex] Generalize service tier slash commands (#21745)
## Why `/fast` was wired as a one-off slash command even though model metadata now exposes service tiers as catalog data. That meant adding another tier, such as a slower/cheaper tier, would require more hardcoded TUI plumbing instead of letting the model catalog drive the available commands. This change makes service-tier commands data-driven: each advertised `service_tiers` entry becomes a `/name` command using the catalog description, while the request path sends the tier `id` only when the selected model supports it. ## What Changed - Removed the hardcoded `/fast` slash-command variant and introduced dynamic service-tier command items in the composer and command popup. - Added toggle behavior for service-tier commands: invoking `/name` selects that tier, and invoking it again clears the selection. - Preserved the existing Fast-mode keybinding/status affordances by resolving the current model tier whose name is `fast`, while still sending the tier request value such as `priority`. - Persisted service-tier selections as raw request strings so non-fast tiers can round-trip through config. - Updated the Bedrock catalog entry to advertise fast support through `service_tiers` with `id: "priority"` and `name: "fast"`. - Added defensive filtering in core so unsupported selected service tiers are omitted from `/responses` requests. ## Validation - Added/updated coverage for dynamic service-tier slash command lookup, popup descriptions, composer dispatch, TUI fast toggling, and unsupported-tier omission in core request construction. - Local tests were not run per request. --------- Co-authored-by: Codex <noreply@openai.com>
Ahmed Ibrahim ·
2026-05-08 20:09:51 +03:00 -
feat: Update plugin share settings with discoverability (#21637)
Requires discoverability on plugin/share/updateTargets so the server can manage workspace link access consistently, including auto-adding the workspace principal for UNLISTED. Also rejects LISTED on share creation and blocks client-supplied workspace principals while preserving response parsing for LISTED.
xl-openai ·
2026-05-07 21:28:18 -07:00 -
Remove skills list extra roots (#21485)
## Summary - Remove `perCwdExtraUserRoots` / `SkillsListExtraRootsForCwd` from the `skills/list` app-server API. - Drop Rust app-server and `codex-core-skills` extra-root plumbing so skill scans are keyed by the normal cwd/user/plugin roots only. - Regenerate app-server schemas and update docs/tests that only existed for the removed extra-roots behavior. ## Validation - `just write-app-server-schema` - `just fmt` - `cargo test -p codex-app-server-protocol` - `cargo test -p codex-core-skills` - `just fix -p codex-app-server-protocol` - `just fix -p codex-core-skills` - `just fix -p codex-app-server` - `just fix -p codex-tui` ## Notes - `cargo test -p codex-app-server --test all skills_list` ran the edited skills-list cases, but the full filtered run ended on existing `skills_changed_notification_is_emitted_after_skill_change` timeout after a websocket `401`. - `cargo test -p codex-tui --lib` compiled the changed TUI callers, then failed two unrelated status permission tests because local `/etc/codex/requirements.toml` forbids `DangerFullAccess`. - Source-truth check found the OpenAI monorepo still has generated/app-server-kit mirror references to the removed field; those should be cleaned up when generated app-server types are synced or in a companion OpenAI cleanup.
xli-oai ·
2026-05-07 20:56:42 -07:00 -
[codex] Remove remote thread store implementation (#21596)
Remove the remote thread-store backend and checked-in protobuf artifacts. We've moved these into another crate that link against this one. Also remove the config settings for thread store backend selection, since we'll instead pass an instantiated thread store into the core-api crate's main entrypoint.
Tom ·
2026-05-08 00:02:46 +00:00 -
feat(app-server, threadstore): Thread pagination APIs and ThreadStore contract (#21566)
## Why The goal of this PR is to align on app-server and `ThreadStore` API updates for paginating through large threads. #### app-server ##### `thread/turns/list` - Updates `thread/turns/list` to support `itemsView?: "notLoaded" | "summary" | "full" | null`, defaulting to `summary`. - Implements the current `thread/turns/list` behavior over the existing persisted rollout-history fallback: - `notLoaded` returns turn envelopes with empty `items`. - `summary` returns the first user message and final assistant message when available. - `full` preserves the existing full item behavior. Note that this method still uses the naive approach of loading the entire rollout file, and returns just the filtered slice of the data. Real pagination will come later by leveraging SQLite. ##### `thread/turns/items/list` - Adds the experimental `thread/turns/items/list` protocol, schema, dispatcher, and processor stub. The app-server currently returns JSON-RPC `-32601` with `thread/turns/items/list is not supported yet`. #### ThreadStore - Adds the experimental `thread/turns/items/list` protocol, schema, dispatcher, and processor stub. The app-server currently returns JSON-RPC `-32601` with `thread/turns/items/list is not supported yet`. - Adds `ThreadStore` contract types and stubbed methods for listing thread turns and listing items within a turn. - Adds a typed `StoredTurnStatus` and `StoredTurnError` to avoid baking app-server API enums or lossy string status values into the store-facing turn contract. - Adds a typed `StoredTurnStatus` and `StoredTurnError` to avoid baking app-server API enums or lossy string status values into the store-facing turn contract. This also sketches the storage abstraction we expect to need once turns are indexed/stored. In particular, `notLoaded` is useful only if ThreadStore can eventually list turn metadata without loading every persisted item for each turn. ## Validation - Added/updated protocol serialization coverage for the new request and response shapes. - Added app-server integration coverage for `thread/turns/list` default summary behavior and all three `itemsView` modes. - Added app-server integration coverage that `thread/turns/items/list` returns the expected unsupported JSON-RPC error when experimental APIs are enabled. - Added thread-store coverage that the default trait methods return `ThreadStoreError::Unsupported`. No developers.openai.com documentation update is needed for this internal experimental app-server API surface.
Owen Lin ·
2026-05-07 15:44:43 -07:00 -
Disable empty Cargo test targets (#21584)
## Summary `cargo test` has entails both running standard Rust tests and doctests. It turns out that the doctest discovery is fairly slow, and it's a cost you pay even for crates that don't include any doctests. This PR disables doctests with `doctest = false` for crates that lack any doctests. For the collection of crates below, this speeds up test execution by >4x. E.g., before this PR: ``` Benchmark 1: cargo test -p codex-utils-absolute-path -p codex-utils-cache -p codex-utils-cli -p codex-utils-home-dir -p codex-utils-output-truncation -p codex-utils-path -p codex-utils-string -p codex-utils-template -p codex-utils-elapsed -p codex-utils-json-to-toml Time (mean ± σ): 1.849 s ± 4.455 s [User: 0.752 s, System: 1.367 s] Range (min … max): 0.418 s … 14.529 s 10 runs ``` And after: ``` Benchmark 1: cargo test -p codex-utils-absolute-path -p codex-utils-cache -p codex-utils-cli -p codex-utils-home-dir -p codex-utils-output-truncation -p codex-utils-path -p codex-utils-string -p codex-utils-template -p codex-utils-elapsed -p codex-utils-json-to-toml Time (mean ± σ): 428.6 ms ± 6.9 ms [User: 187.7 ms, System: 219.7 ms] Range (min … max): 418.0 ms … 436.8 ms 10 runs ``` For a single crate, with >2x speedup, before: ``` Benchmark 1: cargo test -p codex-utils-string Time (mean ± σ): 491.1 ms ± 9.0 ms [User: 229.8 ms, System: 234.9 ms] Range (min … max): 480.9 ms … 512.0 ms 10 runs ``` And after: ``` Benchmark 1: cargo test -p codex-utils-string Time (mean ± σ): 213.9 ms ± 4.3 ms [User: 112.8 ms, System: 84.0 ms] Range (min … max): 206.8 ms … 221.0 ms 13 runs ``` Co-authored-by: Codex <noreply@openai.com>
Charlie Marsh ·
2026-05-07 15:44:17 -07:00 -
[codex] Fix pathless thread summaries (#21266)
## Summary Fix `getConversationSummary` so thread-id summaries work for stored threads that do not have a local rollout path, such as remote thread stores. The root cause was that `summary_from_stored_thread` returned `None` when `StoredThread.rollout_path` was absent, and `get_thread_summary_response_inner` treated that as an internal error. This made conversation-id lookups depend on a local-only field even though the thread store can address the thread by id.
Tom ·
2026-05-07 11:18:16 -07:00 -
feat: Expose plugin share metadata in shareContext (#21495)
Extends PluginSummary.shareContext with shareUrl and reader shareTargets
xl-openai ·
2026-05-07 10:07:03 -07:00 -
Ruslan Nigmatullin ·
2026-05-07 09:01:44 -07:00 -
Show plugin hooks in plugin details (#21447)
Supersedes the abandoned #19859, rebuilt on latest `main`. # Why PR #19705 adds discovery for hooks bundled with plugins, but `/plugins` still only shows skills, apps, and MCP servers. This follow-up makes bundled hooks visible in the same plugin detail view so users can inspect the full plugin surface in one place. We also need `PluginHookSummary` to populate Plugin Hooks in the app; `hooks/list` is not enough there because plugin detail needs to show hooks for disabled plugins too. # What - extend `plugin/read` with `PluginHookSummary` entries for bundled hooks - summarize plugin hooks while loading plugin details - render a `Hooks` row in the `/plugins` detail popup <img width="3456" height="848" alt="CleanShot 2026-04-27 at 11 45 34@2x" src="https://github.com/user-attachments/assets/fe3a38d6-a260-4351-8513-fb04c93d725b" />
Abhinav ·
2026-05-07 00:21:14 -07:00 -
Revert state DB injection and agent graph store (#21481)
## Why Reverts #20689 to restore the previous optional state DB plumbing. The conflict resolution keeps the newer installation ID and session/thread identity changes that landed after #20689, while removing the mandatory state DB and agent graph store dependency from ThreadManager construction. ## What changed - Restored `Option<StateDbHandle>` through app-server, MCP server, prompt debug, and test entry points. - Removed the `codex-core` dependency on `codex-agent-graph-store` and reverted descendant lookup back to the existing state DB path when available. - Kept newer `installation_id` forwarding by passing it beside the optional DB handle. - Kept local thread-name updates working when the optional state DB handle is absent. ## Validation - `git diff --check` - `cargo test -p codex-thread-store` - `cargo test -p codex-state -p codex-rollout -p codex-app-server-protocol` - Attempted `env CARGO_INCREMENTAL=0 cargo test -p codex-core -p codex-app-server -p codex-app-server-client -p codex-mcp-server -p codex-thread-manager-sample -p codex-tui`; blocked locally by a rustc ICE while compiling `v8 v146.4.0` with `rustc 1.93.0 (254b59607 2026-01-19)` on `aarch64-apple-darwin`.
pakrym-oai ·
2026-05-06 22:48:29 -07:00 -
[codex] Parallelize skills list cwd loading (#21441)
## Summary - process `skills/list` cwd entries with bounded concurrency of 5 - preserve the caller's requested cwd order in the response - add coverage that verifies response ordering remains stable ## Why Cold-start desktop traces showed that `skills/list` can dominate the shared config queue when it scans many workspace roots serially. The expensive work is largely independent per cwd, so the request was paying the sum of all cwd costs instead of the cost of the slowest bounded batch. ## Impact This keeps current request semantics intact while reducing the wall-clock time of large multi-root `skills/list` calls. That should also reduce how long later config-family requests, such as `plugin/list`, wait behind `skills/list` during startup. ## Validation - `just fmt` - `cargo test -p codex-app-server` - `cargo test -p codex-app-server skills_list_preserves_requested_cwd_order`
xli-oai ·
2026-05-06 21:25:24 -07:00 -
pakrym-oai ·
2026-05-07 02:24:20 +00:00 -
feat: Add marketplace source filtering and plugin share context (#21419)
Adds marketplaceKinds to plugin/list for local, workspace-directory, and shared-with-me; omitted params keep default local plus gated global behavior, while explicit kinds are exact. Exposes shareContext on plugin summaries from local share mappings and remote workspace/shared responses, including remotePluginId and nullable creator metadata. Adds shared-with-me listing through /ps/plugins/workspace/shared, renames the workspace remote namespace to workspace-directory, and keeps direct remote read/share/install/update/delete paths gated by plugins rather than remote_plugin.
xl-openai ·
2026-05-06 16:12:23 -07:00 -
Move skills watcher to app-server (#21287)
## Why Skills update notifications are app-server API behavior, but the watcher lived in `codex-core` and surfaced through `EventMsg::SkillsUpdateAvailable`. Moving the watcher out keeps core focused on thread execution and lets app-server own both cache invalidation and the `skills/changed` notification. ## What changed - Added an app-server-owned skills watcher that watches local skill roots, clears the shared skills cache, and emits `skills/changed` directly. - Registers skill watches from the common app-server thread listener attach path, including direct starts, resumes, and app-server-observed child or forked threads. - Stores the `WatchRegistration` on `ThreadState`, so listener replacement, thread teardown, idle unload, and app-server shutdown deregister by dropping the RAII guard. - Removed `EventMsg::SkillsUpdateAvailable`, the core watcher, and the old core live-reload test. - Extended the app-server skills change test to verify a cached skills list is refreshed after a filesystem change without forcing reload. ## Validation - `cargo check -p codex-core -p codex-app-server -p codex-mcp-server -p codex-rollout -p codex-rollout-trace` - `cargo test -p codex-app-server skills_changed_notification_is_emitted_after_skill_change`
pakrym-oai ·
2026-05-06 15:38:11 -07:00 -
2- Use string service tiers in session protocol (#20971)
## Summary - break service tier session/op/app-server protocol fields from the closed enum to string tier ids - send the service tier string directly through model requests, prewarm, compaction, memories, and TUI/app-server turn starts - regenerate app-server protocol JSON/TypeScript schemas, removing the standalone ServiceTier TS enum ## Verification - just fmt - cargo check -p codex-core -p codex-app-server -p codex-tui - just write-app-server-schema --------- Co-authored-by: Codex <noreply@openai.com>
Ahmed Ibrahim ·
2026-05-06 18:00:21 +03:00 -
feat(app-server): move v2
sessionIdontoThread(#21336)## Why `session_id` and `thread_id` are separate identities after #20437, but app-server only surfaced `sessionId` on the `thread/start`, `thread/resume`, and `thread/fork` response envelopes. Other thread-bearing surfaces such as `thread/list`, `thread/read`, `thread/started`, `thread/rollback`, `thread/metadata/update`, and `thread/unarchive` either lacked the grouping key or forced clients to special-case those three responses. Making `sessionId` part of the reusable `Thread` payload gives every v2 API surface one place to expose session-tree identity. ## Mental model 1. thread.sessionId lives on `Thread` 2. It is a view/runtime identity for the current live session tree, not durable stored lineage metadata 3. When app-server has a live loaded thread, it copies the real value from core’s session_configured.session_id 4. When it only has stored/unloaded data, it falls back to thread.sessionId = thread.id ## What changed - Added `sessionId` to the v2 [`Thread`](https://github.com/openai/codex/blob/8fc9e9b4cf81b6f61d432e71f1eb266f6f104b63/codex-rs/app-server-protocol/src/protocol/v2/thread_data.rs#L105-L109). - Removed the duplicate top-level `sessionId` fields from `thread/start`, `thread/resume`, and `thread/fork`; clients should now read `response.thread.sessionId`. - Populated `thread.sessionId` when building live thread responses, replaying loaded threads, and returning stored-thread summaries so the field is present across start, resume, fork, list, read, rollback, metadata-update, unarchive, and `thread/started` paths. See [`load_thread_from_resume_source_or_send_internal`](https://github.com/openai/codex/blob/8fc9e9b4cf81b6f61d432e71f1eb266f6f104b63/codex-rs/app-server/src/request_processors/thread_processor.rs#L2824-L2918) and [`thread_from_stored_thread`](https://github.com/openai/codex/blob/8fc9e9b4cf81b6f61d432e71f1eb266f6f104b63/codex-rs/app-server/src/request_processors/thread_processor.rs#L3671-L3719). - Preserved the stored-thread fallback: if a thread has not been loaded into a live session tree yet, `thread.sessionId` falls back to `thread.id`; once the thread is live again, the field reports the active session tree root. - Regenerated the JSON/TypeScript schemas and updated the app-server README examples to show [`thread.sessionId`](https://github.com/openai/codex/blob/8fc9e9b4cf81b6f61d432e71f1eb266f6f104b63/codex-rs/app-server/README.md#L306-L310) on the thread object.
jif-oai ·
2026-05-06 15:23:25 +02:00 -
feat: return session ID from thread/fork (#21332)
## Why `thread/start` and `thread/resume` already return `sessionId`, but `thread/fork` only returned the new thread. That left clients to infer the forked thread's session identity from `thread.id`, which kept the new `session_id` / `thread_id` split implicit at one lifecycle boundary. Follow-up to #20437. ## What changed - Add `sessionId` to `ThreadForkResponse`. - Populate it from the forked session configuration. - Regenerate the v2 JSON/TypeScript schema fixtures and update the app-server docs/example. - Extend the fork integration test to assert the returned `sessionId`. ## Verification - Added coverage in `thread_fork_creates_new_thread_and_emits_started` for the new response field.
jif-oai ·
2026-05-06 12:04:27 +02:00 -
feat: add
session_id(#20437)## Summary Related to https://openai.slack.com/archives/C095U48JNL9/p1777537279707449 TLDR: We update the meaning of session ids and thread ids: * thread_id stays as now * session_id become a shared id between every thread under a /root thread (i.e. every sub-agent share the same session id) This PR introduces an explicit `SessionId` and threads it through the protocol/client boundary so `session_id` and `thread_id` can diverge when they need to, while preserving compatibility for older serialized `session_configured` events. --------- Co-authored-by: Codex <noreply@openai.com>
jif-oai ·
2026-05-06 10:48:37 +02:00 -
Support Codex Apps auth elicitations (#19193)
## Summary - request URL-mode MCP elicitations when Codex Apps tool calls fail with connector auth metadata - route Codex Apps auth URL elicitations into the TUI app-link flow ## Test plan - `just fmt` - `cargo test -p codex-core mcp_tool_call::tests` - `cargo test -p codex-mcp` - `cargo test -p codex-tui bottom_pane::app_link_view::tests` - `just fix -p codex-core` - `just fix -p codex-mcp` - `just fix -p codex-tui` Also attempted broader local runs: - `cargo test -p codex-core` fails in unrelated config/request-permission/proxy-sensitive tests under the current Codex Desktop environment. - `cargo test -p codex-tui` fails in unrelated status snapshots/trust-default tests because the ambient environment renders workspace-write/network permission defaults.
Matthew Zeng ·
2026-05-06 07:18:00 +00:00 -
app-server: align dynamic tool identifiers with Responses API (#20724)
## Why Codex currently accepts dynamic tool names and namespaces that the upstream Responses function-tool path does not actually support. In practice, that means app-server can register a dynamic tool successfully and only discover later that the LLM-facing tool contract will reject or mishandle it. This PR tightens the app-server-side dynamic tool contract to match the Responses API before we stack dynamic tool hook support on top of it. ## What changed - validate dynamic tool `name` against the Responses function-tool identifier contract: `^[a-zA-Z0-9_-]+$`, length `1..128` - validate dynamic tool `namespace` the same way, with the Responses namespace length limit `1..64` - reject namespaces that collide with the always-reserved Responses runtime namespaces such as `functions`, `multi_tool_use`, `file_search`, `web`, `browser`, `image_gen`, `computer`, `container`, `terminal`, `python`, `python_user_visible`, `api_tool`, `tool_search`, and `submodel_delegator` - escape invalid identifiers in error messages so control characters do not spill raw into logs or client-visible error text - document the tightened dynamic tool identifier contract in `codex-rs/app-server/README.md` - add both unit coverage for the validator and an app-server integration test that rejects a `thread/start` request with Responses-incompatible dynamic tool identifiers ## Verification - `cargo test -p codex-app-server validate_dynamic_tools_` - `cargo test -p codex-app-server --test all thread_start_rejects_dynamic_tools_not_supported_by_responses`
Andrei Eternal ·
2026-05-05 21:05:00 -07:00