## Why
hook semantics treat `session_id` as shared across a root session and
its subagents. Codex hooks were still emitting the current thread ID,
which made spawned agents look like independent sessions and made it
harder for hook integrations to correlate work across a root thread and
its spawned helpers
This change makes hooks use Codex's existing shared session identity so
hook `session_id` matches the root-thread session across spawned
subagents.
## What Changed
- switch hook payloads to use the existing shared session identity from
core instead of the current thread ID
- cover all hook surfaces that expose `session_id`, including
`SessionStart`, tool hooks, compact hooks, prompt-submit hooks, stop
hooks, and legacy after-agent dispatch
## Why
Guardian review selection was hard-coded in `core`, which worked for the
default OpenAI path but did not give provider implementations a way to
choose backend-specific reviewer model IDs. That matters for Amazon
Bedrock: guardian review should run through the Bedrock/Mantle provider
using Bedrock's `openai.gpt-5.4` model ID, instead of accidentally
selecting a reviewer model that implies the OpenAI backend.
## What Changed
- Added provider-owned approval review model selection via
`ModelProvider::approval_review_model_selection`.
- Moved the existing default selection policy into the provider
abstraction: prefer the requested reviewer model when it is available,
otherwise fall back to the active turn model, preferring `Low` reasoning
when supported.
- Added an Amazon Bedrock override that pins guardian review to
`openai.gpt-5.4` with `Low` reasoning.
## 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.
- 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.
## Summary
Plugin Creator now documents the shorter local-plugin handoff URL that
the app can interpret directly.
[#22221](https://github.com/openai/codex/pull/22221) teaches the skill
to end marketplace-backed creation flows with named View and Share
links; this follow-up updates those examples so the skill only emits the
normalized plugin name, the absolute marketplace path, and optional
share mode.
The documented shape is:
```txt
codex://plugins/<normalized-plugin-name>?marketplacePath=<absolute-marketplace-json-path>
codex://plugins/<normalized-plugin-name>?marketplacePath=<absolute-marketplace-json-path>&mode=share
```
The skill text now states exactly where the normalized plugin name
belongs, exactly where the absolute marketplace path belongs, and that
it should not add `pluginName` or `hostId` query parameters.
## Testing
Tests: plugin-creator skill validation.
## Why
`remote_control` can appear in `config.toml`, CLI feature overrides, and
the app-server config APIs. Before this PR, app-server startup treated
`config.features.enabled(Feature::RemoteControl)` as the signal to start
remote control ([base
code](5e3ee5eddf/codex-rs/app-server/src/lib.rs (L678-L680))).
That meant a user with:
```toml
[features]
remote_control = true
```
would accidentally opt every app-server process into remote control.
Remote-control startup should instead be a per-process launch decision
made by CLI flags.
## What Changed
- Marks `Feature::RemoteControl` as `Stage::Removed`, keeping
`remote_control` as a known compatibility key while making it
config-inert.
- Adds a hidden `--remote-control` process flag to `codex app-server`
and standalone `codex-app-server`.
- Plumbs that flag through
`AppServerRuntimeOptions.remote_control_enabled` and makes app-server
startup use only that runtime option to decide whether to start remote
control.
- Removes the app-server config mutation hook that reloaded config and
toggled remote control at runtime.
- Updates managed daemon spawning to use `codex app-server
--remote-control --listen unix://` instead of `--enable remote_control`.
Config APIs can still list, read, write, and set `remote_control`; those
operations just no longer affect remote-control process enrollment.
## Why
`tool_search` still carries the server-specific result-cap path added in
#17684 for `computer-use`: when the model omitted `limit`, a matching
result expanded the search to 20 and then `limit_results_by_bucket`
applied per-bucket caps. That makes default result handling depend on a
one-off server exception instead of the single
`TOOL_SEARCH_DEFAULT_LIMIT` path.
This PR removes that custom branch so omitted `limit` values use the
ordinary global default consistently. The implementation being retired
is the pre-change bucketed search path in
[`tool_search.rs`](5e3ee5eddf/codex-rs/core/src/tools/handlers/tool_search.rs (L121-L190)).
## What changed
- Collapse `ToolSearchHandler::search` back to one BM25 search with the
resolved limit.
- Remove `limit_results_by_bucket`, the `computer-use` constants, and
the omitted-limit plumbing that only existed for the override.
- Drop dead `ToolSearchEntry::limit_bucket` metadata from deferred MCP
and dynamic search entries.
- Remove tests and helpers that only asserted the deleted override
behavior.
- Add direct handler-level unit coverage for omitted/default and
explicit `tool_search` result limits.
## Validation
- `cargo test -p codex-core tool_search`
- The matching unit tests passed, including the new omitted/default and
explicit result-limit coverage.
- The broader `--test all` search-tool fixture phase then failed before
sending mocked response requests in
`tool_search_indexes_only_enabled_non_app_mcp_tools` and
`tool_search_uses_non_app_mcp_server_instructions_as_namespace_description`.
- `cargo test -p codex-core`
- The touched tool-search coverage passed before the run later aborted
in
`tools::handlers::multi_agents::tests::tool_handlers_cascade_close_and_resume_and_keep_explicitly_closed_subtrees_closed`
with a stack overflow.
## Why
`chatwidget.rs` is still carrying too many unrelated responsibilities in
one file. After #21866 consolidated some of the state it tracks, this
starts the next phase by moving coherent state/helper clusters out of
the main module without changing behavior.
This PR is intentionally mechanical: it only moves existing functions,
structs, and helpers into focused modules so the boundaries are easier
to review before the less mechanical refactors that should follow.
## What Changed
- Moved user-message, composer, queue, pending steer, and merge/remap
helpers into `codex-rs/tui/src/chatwidget/user_messages.rs`.
- Added `codex-rs/tui/src/chatwidget/exec_state.rs` for unified exec
bookkeeping helpers.
- Added `codex-rs/tui/src/chatwidget/rate_limits.rs` for rate-limit
warning, prompt, and error classification state.
- Moved plugin list fetch and install auth-flow state into
`codex-rs/tui/src/chatwidget/plugins.rs`.
- Made a couple of test-only `VecDeque` imports explicit now that those
tests no longer inherit the parent module import.
## Verification
- `cargo test -p codex-tui` was run
## Follow-On Refactor Phases
This PR is phase 1: mechanical helper and state moves. Planned follow-up
PRs:
- Phase 2: extract input and submission flow, including queued user
messages, shell prompt submission, pending steer restoration, and thread
input snapshot/restore behavior.
- Phase 3: extract protocol, replay, streaming, and tool lifecycle
handling, while preserving active-cell grouping, transcript
invalidation, interrupt deferral, and final-message separator behavior.
- Phase 4: extract settings, popups, and status surfaces, including
model/reasoning/collaboration/personality popups, permission prompts,
rate-limit UI, and connectors helpers.
- Phase 5: clean up the remaining constructor and orchestration code
once the larger behavior domains have moved out, leaving `chatwidget.rs`
as the composition layer.