## Why
This finishes the config-type move out of `codex-core` by removing the
temporary compatibility shim in `codex_core::config::types`. Callers now
depend on `codex-config` directly, which keeps these config model types
owned by the config crate instead of re-expanding `codex-core` as a
transitive API surface.
## What Changed
- Removed the `codex-rs/core/src/config/types.rs` re-export shim and the
`core::config::ApprovalsReviewer` re-export.
- Updated `codex-core`, `codex-cli`, `codex-tui`, `codex-app-server`,
`codex-mcp-server`, and `codex-linux-sandbox` call sites to import
`codex_config::types` directly.
- Added explicit `codex-config` dependencies to downstream crates that
previously relied on the `codex-core` re-export.
- Regenerated `codex-rs/core/config.schema.json` after updating the
config docs path reference.
## Why
`codex-core` was re-exporting APIs owned by sibling `codex-*` crates,
which made downstream crates depend on `codex-core` as a proxy module
instead of the actual owner crate.
Removing those forwards makes crate boundaries explicit and lets leaf
crates drop unnecessary `codex-core` dependencies. In this PR, this
reduces the dependency on `codex-core` to `codex-login` in the following
files:
```
codex-rs/backend-client/Cargo.toml
codex-rs/mcp-server/tests/common/Cargo.toml
```
## What
- Remove `codex-rs/core/src/lib.rs` re-exports for symbols owned by
`codex-login`, `codex-mcp`, `codex-rollout`, `codex-analytics`,
`codex-protocol`, `codex-shell-command`, `codex-sandboxing`,
`codex-tools`, and `codex-utils-path`.
- Delete the `default_client` forwarding shim in `codex-rs/core`.
- Update in-crate and downstream callsites to import directly from the
owning `codex-*` crate.
- Add direct Cargo dependencies where callsites now target the owner
crate, and remove `codex-core` from `codex-rs/backend-client`.
## Why
`codex-mcp` already owns the shared MCP API surface, including `auth`,
`McpConfig`, `CODEX_APPS_MCP_SERVER_NAME`, and tool-name helpers in
[`codex-rs/codex-mcp/src/mcp/mod.rs`](f61e85dbfb/codex-rs/codex-mcp/src/mcp/mod.rs (L1-L35)).
Re-exporting that surface from `codex_core::mcp` gives downstream crates
two import paths for the same API and hides the real crate dependency.
This PR keeps `codex_core::mcp` focused on the local `McpManager`
wrapper in
[`codex-rs/core/src/mcp.rs`](f61e85dbfb/codex-rs/core/src/mcp.rs (L13-L40))
and makes consumers import shared MCP APIs from `codex_mcp` directly.
## What
- Remove the `codex_mcp::mcp` re-export surface from `core/src/mcp.rs`.
- Update `codex-core` internals plus `codex-app-server`, `codex-cli`,
and `codex-tui` test code to import MCP APIs from `codex_mcp::mcp`
directly.
- Add explicit `codex-mcp` dependencies where those crates now use that
API surface, and refresh `Cargo.lock`.
## Verification
- `just bazel-lock-check`
- `cargo test -p codex-core -p codex-cli -p codex-tui`
- `codex-cli` passed.
- `codex-core` still fails five unrelated config tests in
`core/src/config/config_tests.rs` (`approvals_reviewer_*` and
`smart_approvals_alias_*`).
- A broader `cargo test -p codex-core -p codex-app-server -p codex-cli
-p codex-tui` run previously hung in `codex-app-server` test
`in_process_start_uses_requested_session_source_for_thread_start`.
Fix paste-driven bottom-pane completion teardown (#16192)
`BottomPane::handle_paste()` could leave a completed modal flow mounted
while re-enabling the composer, putting the TUI in an inconsistent state
where stale views could still affect rendering and input routing. Align
the paste path with the existing key-driven completion logic by tearing
down the active modal flow before restoring composer input, and add a
regression test covering the stacked-view case that exposed the bug.
Big thanks to @iqdoctor for identifying the root cause for this issue.
Addresses #16283
Problem: TUI app-server permission approvals could drop filesystem
grants because request and response payloads were round-tripped through
mismatched camelCase and snake_case JSON shapes.
Solution: Replace the lossy JSON round-trips with typed app-server/core
permission conversions so requested and granted permission profiles,
including filesystem paths and scope, are preserved end to end.
Addresses a recent TUI regression
Problem: Pressing Ctrl+C during early TUI startup could route an
interrupt with no active turn into the generic unsupported-op fallback,
showing “Not available in app-server TUI yet for thread …” repeatedly.
Solution: Treat interrupt requests as handled when no active turn exists
yet, preventing fallback error spam during startup, and add a regression
test covering interrupt-without-active-turn behavior.
## Description
Previously the `action` field on `EventMsg::GuardianAssessment`, which
describes what Guardian is reviewing, was typed as an arbitrary JSON
blob. This PR cleans it up and defines a sum type representing all the
various actions that Guardian can review.
This is a breaking change (on purpose), which is fine because:
- the Codex app / VSCE does not actually use `action` at the moment
- the TUI code that consumes `action` is updated in this PR as well
- rollout files that serialized old `EventMsg::GuardianAssessment` will
just silently drop these guardian events
- the contract is defined as unstable, so other clients have a fair
warning :)
This will make things much easier for followup Guardian work.
## Why
The old guardian review payloads worked, but they pushed too much shape
knowledge into downstream consumers. The TUI had custom JSON parsing
logic for commands, patches, network requests, and MCP calls, and the
app-server protocol was effectively just passing through an opaque blob.
Typing this at the protocol boundary makes the contract clearer.
## Why
Now that workspace crate features have been removed and
`.github/scripts/verify_cargo_workspace_manifests.py` hard-bans new
ones, Rust CI should stop building and testing with `--all-features`.
Keeping `--all-features` in CI no longer buys us meaningful coverage for
`codex-rs`, but it still makes the workflow look like we rely on Cargo
feature permutations that we are explicitly trying to eliminate. It also
leaves stale examples in the repo that suggest `--all-features` is a
normal or recommended way to run the workspace.
## What changed
- removed `--all-features` from the Rust CI `cargo chef cook`, `cargo
clippy`, and `cargo nextest` invocations in
`.github/workflows/rust-ci-full.yml`
- updated the `just test` guidance in `justfile` to reflect that
workspace crate features are banned and there should be no need to add
`--all-features`
- updated the multiline command example and snapshot in
`codex-rs/tui/src/history_cell.rs` to stop rendering `cargo test
--all-features --quiet`
- tightened the verifier docstring in
`.github/scripts/verify_cargo_workspace_manifests.py` so it no longer
talks about temporary remaining exceptions
## How tested
- `python3 .github/scripts/verify_cargo_workspace_manifests.py`
- `cargo test -p codex-tui`
## Why
`voice-input` is the only remaining TUI crate feature, but it is also a
default feature and nothing in the workspace selects it explicitly. In
practice it is just acting as a proxy for platform support, which is
better expressed with target-specific dependencies and cfgs.
## What changed
- remove the `voice-input` feature from `codex-tui`
- make `cpal` a normal non-Linux target dependency
- replace the feature-based voice and audio cfgs with pure
Linux-vs-non-Linux cfgs
- shrink the workspace-manifest verifier allowlist to remove the
remaining `codex-tui` exception
## How tested
- `python3 .github/scripts/verify_cargo_workspace_manifests.py`
- `cargo test -p codex-tui`
- `just bazel-lock-check`
- `just argument-comment-lint -p codex-tui`
## Why
The remaining `vt100-tests` and `debug-logs` features in `codex-tui`
were only gating test-only and debug-only behavior. Those feature
toggles add Cargo and Bazel permutations without buying anything, and
they make it easier for more crate features to linger in the workspace.
## What changed
- delete `vt100-tests` and `debug-logs` from `codex-tui`
- always compile the VT100 integration tests in the TUI test target
instead of hiding them behind a Cargo feature
- remove the unused textarea debug logging branch instead of replacing
it with another gate
- add the required argument-comment annotations in the VT100 tests now
that Bazel sees those callsites during linting
- shrink the manifest verifier allowlist again so only the remaining
real feature exceptions stay permitted
## How tested
- `cargo test -p codex-tui`
- `just argument-comment-lint -p codex-tui`
## Why
Follow-up to #16351.
That PR synchronized Bazel clippy lint levels with Cargo, but two
intentional `expect()` calls in `codex-rs/tui/src/status/card.rs` still
tripped `clippy::expect_used` (I believe #16201 raced with #16351, which
is why it was missed).
Fix stale weekly limit in `/status` (#16194): /status reused the
session’s cached rate-limit snapshot, so the weekly remaining limit
could stay frozen within an active session.
With this change, we now dynamically update the rate limits after status
is displayed.
I needed to delete a few low-value test cases from the chatWidget tests
because the test.rs file is really large, and the new tests in this PR
pushed us over the 512K mandated limit. I'm working on a separate PR to
refactor that test file.
Problem: `chatwidget/tests.rs` had grown into a single oversized test
blob that was hard to maintain and exceeded the repo's blob size limit.
Solution: split the chatwidget tests into topical modules with a thin
root `tests.rs`, shared helper utilities, preserved snapshot naming, and
hermetic test config so the refactor stays stable and passes the
`codex-tui` test suite.
The TUI’s `/feedback` flow was still uploading directly through the
local feedback crate, which bypassed app-server behavior such as
auth-derived feedback tags like chatgpt_user_id and made TUI feedback
handling diverge from other clients. It also meant that remove TUI
sessions failed to upload the correct feedback logs and session details.
Testing: Manually tested `/feedback` flow and confirmed that it didn't
regress.
## Summary
A Windows-only snapshot assertion in the app-server MCP startup warning
test compared the raw rendered path, so CI saw `C:\tmp\project` instead
of the normalized `/tmp/project` snapshot fixture.
## Fix
Route that snapshot assertion through the existing
`normalize_snapshot_paths(...)` helper so the test remains
platform-stable.
Fixes#16092
The app-server-backed TUI could accumulate ghost subagent entries in
`/agent` after resume/backfill flows. Some of those rows were no longer
live according to the backend, but still appeared selectable in the
picker and could open as blank threads.
*Cause*
Unlike the legacy tui behavior, tui_app_server was creating local
picker/replay state for subagents discovered through metadata refresh
and loaded-thread backfill, even when no real local session or
transcript had been attached. That let stale ids survive in the picker
as if they were replayable threads.
*Fix*
Stop creating empty local thread channels during subagent metadata
hydration and loaded-thread backfill.
When opening /agent, prune metadata-only entries that thread/read
reports as terminally unavailable.
When selecting a discovered subagent that is still live but not yet
locally attached, materialize a real local session on demand from
thread/read instead of falling back to an empty replay state.
This addresses #16038
The default `tui_app_server` path stopped surfacing MCP startup failures
during cold start, even though the legacy TUI still showed warnings like
`MCP startup incomplete (...)`. The app-server bridge emitted per-server
startup status notifications, but `tui_app_server` ignored them, so
failed MCP handshakes could look like a clean startup.
This change teaches `tui_app_server` to consume MCP startup status
notifications, preserve the immediate per-server failure warning, and
synthesize the same aggregate startup warning the legacy TUI shows once
startup settles.
Resolve the remaining TUI-side merge drift after restacking the watchdog and subagent behavior branch onto the refreshed TUI foundation branch.
Co-authored-by: Codex <noreply@openai.com>