## Why
`codex-core` was carrying the embedded system-skill sample assets (and a
`build.rs` that walks those files to register rerun triggers). Those
assets change infrequently, but any change under `codex-core` still ties
them to `codex-core`'s build/cache lifecycle.
This change moves the embedded system-skills packaging into a dedicated
`codex-skills` crate so it can be cached independently. That reduces
unnecessary invalidation/rebuild pressure on `codex-core` when the
skills bundle is the only thing that changes.
## What Changed
- Added a new `codex-rs/skills` crate (`codex-skills`) with:
- `Cargo.toml`
- `BUILD.bazel`
- `build.rs` to track skill asset file changes for Cargo rebuilds
- `src/lib.rs` containing the embedded system-skills install/cache logic
previously in `codex-core`
- Moved the embedded sample skill assets from
`codex-rs/core/src/skills/assets/samples` to
`codex-rs/skills/src/assets/samples`.
- Updated `codex-rs/core/Cargo.toml` to depend on `codex-skills` and
removed `codex-core`'s direct `include_dir` dependency.
- Removed `codex-core`'s `build.rs`.
- Replaced `codex-rs/core/src/skills/system.rs` implementation with a
thin re-export wrapper to keep existing `codex-core` call sites
unchanged.
- Updated workspace manifests/lockfile (`codex-rs/Cargo.toml`,
`codex-rs/Cargo.lock`) for the new crate.
## Why
`codex-rs/arg0` only needed two things from `codex-core`:
- the `find_codex_home()` wrapper
- the special argv flag used for the internal `apply_patch`
self-invocation path
That made `codex-arg0` depend on `codex-core` for a very small surface
area. This change removes that dependency edge and moves the shared
`apply_patch` invocation flag to a more natural boundary
(`codex-apply-patch`) while keeping the contract explicitly documented.
## What Changed
- Moved the internal `apply_patch` argv[1] flag constant out of
`codex-core` and into `codex-apply-patch`.
- Renamed the constant to `CODEX_CORE_APPLY_PATCH_ARG1` and documented
that it is part of the Codex core process-invocation contract (even
though it now lives in `codex-apply-patch`).
- Updated `arg0`, the core apply-patch runtime, and the `codex-exec`
apply-patch test to import the constant from `codex-apply-patch`.
- Updated `codex-rs/arg0` to call
`codex_utils_home_dir::find_codex_home()` directly instead of
`codex_core::config::find_codex_home()`.
- Removed the `codex-core` dependency from `codex-rs/arg0` and added the
needed direct dependency on `codex-utils-home-dir`.
- Added `codex-apply-patch` as a dev-dependency for `codex-rs/exec`
tests (the apply-patch test now imports the moved constant directly).
## Verification
- `cargo test -p codex-apply-patch`
- `cargo test -p codex-arg0`
- `cargo test -p codex-core --lib apply_patch`
- `cargo test -p codex-exec
test_standalone_exec_cli_can_use_apply_patch`
- `cargo shear`
## Why
`codex-rs/core/src/lib.rs` re-exported a broad set of types and modules
from `codex-protocol` and `codex-shell-command`. That made it easy for
workspace crates to import those APIs through `codex-core`, which in
turn hides dependency edges and makes it harder to reduce compile-time
coupling over time.
This change removes those public re-exports so call sites must import
from the source crates directly. Even when a crate still depends on
`codex-core` today, this makes dependency boundaries explicit and
unblocks future work to drop `codex-core` dependencies where possible.
## What Changed
- Removed public re-exports from `codex-rs/core/src/lib.rs` for:
- `codex_protocol::protocol` and related protocol/model types (including
`InitialHistory`)
- `codex_protocol::config_types` (`protocol_config_types`)
- `codex_shell_command::{bash, is_dangerous_command, is_safe_command,
parse_command, powershell}`
- Migrated workspace Rust call sites to import directly from:
- `codex_protocol::protocol`
- `codex_protocol::config_types`
- `codex_protocol::models`
- `codex_shell_command`
- Added explicit `Cargo.toml` dependencies (`codex-protocol` /
`codex-shell-command`) in crates that now import those crates directly.
- Kept `codex-core` internal modules compiling by using `pub(crate)`
aliases in `core/src/lib.rs` (internal-only, not part of the public
API).
- Updated the two utility crates that can already drop a `codex-core`
dependency edge entirely:
- `codex-utils-approval-presets`
- `codex-utils-cli`
## Verification
- `cargo test -p codex-utils-approval-presets`
- `cargo test -p codex-utils-cli`
- `cargo check --workspace --all-targets`
- `just clippy`
## Why
Compiling `codex-rs/core` is a bottleneck for local iteration, so this
change continues the ongoing extraction of config-related functionality
out of `codex-core` and into `codex-config`.
The goal is not just to move code, but to reduce `codex-core` ownership
and indirection so more code depends on `codex-config` directly.
## What Changed
- Moved config diagnostics logic from
`core/src/config_loader/diagnostics.rs` into
`config/src/diagnostics.rs`.
- Updated `codex-core` to use `codex-config` diagnostics types/functions
directly where possible.
- Removed the `core/src/config_loader/diagnostics.rs` shim module
entirely; the remaining `ConfigToml`-specific calls are in
`core/src/config_loader/mod.rs`.
- Moved `CONFIG_TOML_FILE` into `codex-config` and updated existing
references to use `codex_config::CONFIG_TOML_FILE` directly.
- Added a direct `codex-config` dependency to `codex-cli` for its
`CONFIG_TOML_FILE` use.
## Summary
- move regular-turn context diff/full-context persistence into
`run_turn` so pre-turn compaction runs before incoming context updates
are recorded
- after successful pre-turn compaction, rely on a cleared
`reference_context_item` to trigger full context reinjection on the
follow-up regular turn (manual `/compact` keeps replacement history
summary-only and also clears the baseline)
- preserve `<model_switch>` when full context is reinjected, and inject
it *before* the rest of the full-context items
- scope `reference_context_item` and `previous_model` to regular user
turns only so standalone tasks (`/compact`, shell, review, undo) cannot
suppress future reinjection or `<model_switch>` behavior
- make context-diff persistence + `reference_context_item` updates
explicit in the regular-turn path, with clearer docs/comments around the
invariant
- stop persisting local `/compact` `RolloutItem::TurnContext` snapshots
(only regular turns persist `TurnContextItem` now)
- simplify resume/fork previous-model/reference-baseline hydration by
looking up the last surviving turn context from rollout lifecycle
events, including rollback and compaction-crossing handling
- remove the legacy fallback that guessed from bare `TurnContext`
rollouts without lifecycle events
- update compaction/remote-compaction/model-visible snapshots and
compact test assertions (including remote compaction mock response
shape)
## Why
We were persisting incoming context items before spawning the regular
turn task, which let pre-turn compaction requests accidentally include
incoming context diffs without the new user message. Fixing that exposed
follow-on baseline issues around `/compact`, resume/fork, and standalone
tasks that could cause duplicate context injection or suppress
`<model_switch>` instructions.
This PR re-centers the invariants around regular turns:
- regular turns persist model-visible context diffs/full reinjection and
update the `reference_context_item`
- standalone tasks do not advance those regular-turn baselines
- compaction clears the baseline when replacement history may have
stripped the referenced context diffs
## Follow-ups (TODOs left in code)
- `TODO(ccunningham)`: fix rollback/backtracking baseline handling more
comprehensively
- `TODO(ccunningham)`: include pending incoming context items in
pre-turn compaction threshold estimation
- `TODO(ccunningham)`: inject updated personality spec alongside
`<model_switch>` so some model-switch paths can avoid forced full
reinjection
- `TODO(ccunningham)`: review task turn lifecycle
(`TurnStarted`/`TurnComplete`) behavior and emit task-start context
diffs for task types that should have them (excluding `/compact`)
## Validation
- `just fmt`
- CI should cover the updated compaction/resume/model-visible snapshot
expectations and rollout-hydration behavior
- I did **not** rerun the full local test suite after the latest
resume-lookup / rollout-persistence simplifications
## Why
Developers are frequently running low on disk space, and routine use of
`--all-features` contributes to larger Cargo build caches in `target/`
by compiling additional feature combinations.
This change updates local workflow guidance to avoid `--all-features` by
default and reserve it for cases where full feature coverage is
specifically needed.
## What Changed
- Updated `AGENTS.md` guidance for `codex-rs` to recommend `cargo test`
/ `just test` for full-suite local runs, and to call out the disk-usage
cost of routine `--all-features` usage.
- Updated the root `justfile` so `just fix` and `just clippy` no longer
pass `--all-features` by default.
- Updated `docs/install.md` to explicitly describe `cargo test
--all-features` as an optional heavier-weight run (more build time and
`target/` disk usage).
## Verification
- Confirmed the `justfile` parses and the recipes list successfully with
`just --list`.
## Summary
`gpt-5.3-codex` really likes to write complicated shell scripts, and
suggest a partial prefix_rule that wouldn't actually approve the
command. We should only show the `prefix_rule` suggestion from the model
if it would actually fully approve the command the user is seeing.
This will technically cause more instances of overly-specific
suggestions when we fallback, but I think the UX is clearer,
particularly when the model doesn't necessarily understand the current
limitations of execpolicy parsing.
## Testing
- [x] Add unit tests
- [x] Add integration tests
## Why
The generated unnamespaced JSON envelope schemas (`ClientRequest` and
`ServerNotification`) still contained both v1 and v2 variants, which
pulled legacy v1/core types and v2 types into the same `definitions`
graph. That caused `schemars` to produce numeric suffix names (for
example `AskForApproval2`, `ByteRange2`, `MessagePhase2`).
This PR moves JSON codegen toward v2-only output while preserving the
unnamespaced envelope artifacts, and avoids reintroducing numeric-suffix
tolerance by removing the v1/internal-only variants that caused the
collisions in those envelope schemas.
## What Changed
- In `codex-rs/app-server-protocol/src/export.rs`, JSON generation now
excludes v1 schema artifacts (`v1/*`) while continuing to emit
unnamespaced/root JSON schemas and the JSON bundle.
- Added a narrow JSON v1 allowlist (`JSON_V1_ALLOWLIST`) so
`InitializeParams` and `InitializeResponse` are still emitted.
- Added JSON-only post-processing for the mixed envelope schemas before
collision checks run:
- `ClientRequest`: strips v1 request variants from the generated `oneOf`
using the temporary `V1_CLIENT_REQUEST_METHODS` list
- `ServerNotification`: strips v1 notifications plus the internal-only
`rawResponseItem/completed` notification using the temporary
`EXCLUDED_SERVER_NOTIFICATION_METHODS_FOR_JSON` list
- Added a temporary local-definition pruning pass for those envelope
schemas so now-unreferenced v1/core definitions are removed from
`definitions` after method filtering.
- Updated the variant-title naming heuristic for single-property literal
object variants to use the literal value (when available), avoiding
collisions like multiple `state`-only variants all deriving the same
title.
- Collision handling remains fail-fast (no numeric suffix fallback map
in this PR path).
## Verification
- `just write-app-server-schema`
---
[//]: # (BEGIN SAPLING FOOTER)
Stack created with [Sapling](https://sapling-scm.com). Best reviewed
with [ReviewStack](https://reviewstack.dev/openai/codex/pull/12408).
* __->__ #12408
* #12406
## Summary
- switch a few app-server `turn_start` tests from
`codex/event/task_complete` waits to `turn/completed` waits
- avoid matching unrelated/background `task_complete` events
- keep this flaky test fix separate from the /title feature PR
## Why
On Windows ARM CI, these tests can return early after observing a
generic `codex/event/task_complete` notification from another task. That
can leave the mock Responses server with fewer calls than expected and
fail the test with a wiremock verification mismatch.
Using `turn/completed` matches the app-server turn lifecycle
notification the tests actually care about.
## Validation
- `cargo test -p codex-app-server
turn_start_updates_sandbox_and_cwd_between_turns_v2 -- --nocapture`
- `cargo test -p codex-app-server turn_start_exec_approval_ --
--nocapture`
- `just fmt`
https://github.com/openai/codex/pull/10455 introduced the `phase` field,
and then https://github.com/openai/codex/pull/12072 introduced a
`MessagePhase` type in `v2.rs` that paralleled the `MessagePhase` type
in `codex-rs/protocol/src/models.rs`.
The app server protocol prefers `camelCase` while the Responses API uses
`snake_case`, so this meant we had two versions of `MessagePhase` with
different serialization rules. When the app server protocol refers to
types from the Responses API, we use the wire format of the the
Responses API even though it is inconsistent with the app server API.
This PR deletes `MessagePhase` from `v2.rs` and consolidates on the
Responses API version to eliminate confusion.
## Why
`thread/resume` responses for already-running threads can be reported as
`Idle` even while a turn is still in progress. This is caused by a
timing window where the runtime watch state has not yet observed the
running-thread transition, so API clients can receive stale status
information at resume time.
Possibly related: https://github.com/openai/codex/pull/11786
## What
- Add a shared status normalization helper, `resolve_thread_status`, in
`codex-rs/app-server/src/thread_status.rs` that resolves
`Idle`/`NotLoaded` to `Active { active_flags: [] }` when an in-progress
turn is known.
- Reuse this helper across thread response paths in
`codex-rs/app-server/src/codex_message_processor.rs` (including
`thread/start`, `thread/unarchive`, `thread/read`, `thread/resume`,
`thread/fork`, and review/thread-started notification responses).
- In `handle_pending_thread_resume_request`, use both the in-memory
`active_turn_snapshot` and the resumed rollout turns to decide whether a
turn is in progress before resolving thread status for the response.
- Extend `thread_status` tests to validate the new status-resolution
behavior directly.
## Verification
- `cargo test -p codex-app-server
suite::v2::thread_resume::thread_resume_rejoins_running_thread_even_with_override_mismatch`