Fixes every test failure caused by the codex->dev rename + hanzo-default-provider
overlay, and the clearly-stale ones:
- cargo_bin(codex)->dev (29), help/usage assertions, doctest, doctor snapshot
- RUST_MIN_STACK=8MiB so cargo test matches nextest's main-thread stack
- exec harness DRY mock_server_config_overrides + resume (provider pin)
- cli_stream (5) provider-pin, guardian (3) HANZO_PROVIDER_ID
- tui status snapshots (20): the legit 'Model provider: Hanzo' line
- code_mode (1): the intended truncation warning
Verified via nextest: the fixed clusters are green. Remaining local failures are
provably env-bound to this WSL box (cwd/HOME/git-context/webrtc/network + exec
partial-stdout capture, ACTUAL_LEN=11980 vs 50000) and pass in CI's clean runner.
[skip ci]: the verifying fleet release is a deliberate workflow_dispatch.
truncate_code_mode_result intentionally prepends 'Warning: truncated output
(original token count: N)' (confirmed by the passing unit test
truncated_text_output_starts_with_warning); the printf-based integration
expectation predated it. The 5 python3-based code_mode tests fail only on this
box due to partial exec stdout capture (ACTUAL_LEN=11980 vs 50000 — the
documented skip_if_wine_exec class); they pass in CI's full-capture Linux.
- integration_creates_and_checks_session_file runs a SECOND (resume) command
that also set openai_base_url without a provider; pin model_provider=openai.
- status snapshots: several tests have multiple assert_snapshot! calls; insta
panics on the first, hiding later ones. Updated the chained snapshots (only the
legit 'Model provider: Hanzo' line; git diff verified no other drift).
The fork defaults to the hanzo provider, which breaks upstream tests that assume
openai. Fix the consolidation-adjacent + stale clusters:
- cli_stream (5): pin model_provider=openai in the 4 command builders that set
openai_base_url but no provider (PAT/ChatGPT + openai_base_url-routing tests
need the openai provider; the passing builders already pin a provider).
- guardian (3): the review records the configured provider id; expectation
OPENAI_PROVIDER_ID -> HANZO_PROVIDER_ID (the fork default).
- tui status snapshots (16): accept the legit new 'Model provider: Hanzo' line
the status card now renders. (Env-dependent project-name/paste-hint snapshots
left untouched.)
Verified via nextest: guardian 3/3 + cli_stream pass. Pre-existing code_mode
truncation-policy drift + env-bound-to-this-box failures are NOT addressed here.
codex's large async futures overflow cargo test's 2 MiB spawned-thread stacks
(SIGABRT in startup tests). nextest (.config/nextest.toml, used by CI) runs each
test in its own process on the 8 MiB main thread, so they pass there. Set
RUST_MIN_STACK=8 MiB for cargo-launched test processes to match. Additive:
nextest, the Windows /STACK link-arg, and the directly-executed shipped binary
are all unaffected.
After the bin rename (codex->dev) and the hanzo default provider, upstream tests broke:
- 29 cargo_bin("codex") -> cargo_bin("dev") (integration tests spawned a
non-existent `codex` binary).
- exec integration tests (28) reached the real api.hanzo.ai because the mock
harness only overrode openai_base_url while the default provider is hanzo.
Fix: ONE DRY helper mock_server_config_overrides() (sets openai_base_url AND
pins the openai provider), consumed by cmd_with_server AND the resume test
(which had duplicated the override inline — the actual cause of its failure).
- doctor insta snapshot prefix codex__ -> dev__ (snapshot name tracks the bin
crate name).
- core feedback_tags doctest: bind the example vars so it compiles.
- main.rs plugin-marketplace help assertions codex -> dev (bin_name is dev).
Full workspace: 4552 passed. The remaining agent-graph-store failures are sqlite
pool-acquire saturation under full-workspace parallelism (30s timeout exceeded
when 100+ test binaries hit /tmp sqlite at once); they pass in isolation. CI
bounds this with nextest.
Brings the develop-vs-ship split to an end. release.yml now builds & ships the
live codex-rs workspace (musl via prebuilt rusty_v8 artifacts), the frozen
hanzo-dev fork + 4 other parallel trees are deleted, the code-version crate is
ported so `dev --version` is real, and the binary is branded `dev`/Hanzo Dev.
[skip ci] is intentional: the first codex-rs-based fleet release (which builds
all platforms AND publishes @hanzo/dev to npm) is a deliberate ship decision,
triggered via workflow_dispatch — not auto-fired by this integration merge.
hanzo-dev was a 53-day-frozen diverged fork that release.yml shipped only
because codex-rs's v8 dep was believed to block musl. It doesn't — the prebuilt
rusty_v8 musl artifacts already exist (rust-release.yml uses them). So collapse
to the single canonical tree.
- Delete hanzo-dev/ (1416 paths). codex-rs has zero deps on it; its 'unique'
crates (zap/sse/backoff) aren't needed (codex-rs has its own upstream impls);
zt/zap zero-trust was feature-gated OFF in release builds so it never shipped
(external ~/work/hanzozt SDKs + docs unaffected; design notes kept in LLM.md).
- Repoint every remaining hanzo-dev build/path ref to codex-rs: workflows
(preview-build, issue-code, issue-comment), scripts (ci-tests.sh,
generate-homebrew-formula.sh, pre-release.sh, build-fast.sh, hanzo.sh,
hanzo-cli), code-sign actions, dependabot.yaml, merge-policy.json, docs.
- Port the dev-fast cargo profile into codex-rs/Cargo.toml (build-fast.sh /
pre-release.sh / release.yml preflight all use it).
- Delete obsolete hanzo-dev-only tooling (check-codex-path-deps.sh,
upstream-merge/diff-crates.sh) + repoint their callers.
- package.json/build-fast.sh build only --bin dev (codex-rs has no
dev-tui/dev-exec split bins).
Verified locally: codex-rs builds `dev` (Hanzo Dev header, CODE_VERSION-aware);
zero dangling source refs (only npm package names + Homebrew formula name kept).
codex-rs had no way to consume the CODE_VERSION the release CI injects, so
`dev --version` printed `codex-cli 0.0.0`. Port hanzo-dev's proven code-version
crate (build.rs reads CODE_VERSION env → rustc-env → option_env! const) as
codex-rs/code-version (package codex-version), wire codex-cli to it, and set clap
name/bin_name/usage/help to `dev` + header to `Hanzo Dev`.
Verified: CODE_VERSION=1.2.3 build → `dev --version` = `dev 1.2.3`; default → `dev 0.0.0`.
This is the only thing codex-rs needed from hanzo-dev before hanzo-dev is removed.
release.yml built the frozen hanzo-dev workspace because codex-rs's v8/code-mode
dep blocked musl static linking. But the musl rusty_v8 prebuilt artifacts already
exist and rust-release.yml already consumes them — so this was CI plumbing, not a
real blocker. Wire the same 'Configure musl rusty_v8 artifact overrides' step into
the @hanzo/dev release build and point every step (preflight build+test, binary
build, toolchain read, rust-cache, prefetch, smoke, package, timings) at codex-rs.
Releases now ship the live tree (codex-rs) instead of a 53-day-frozen snapshot.
The musl+v8 link needs one fleet CI run to validate end-to-end.
Removes the unambiguously-dead parallel trees (code-rs, codex-rs/tui2,
standalone-hanzo-dev, published-hanzo-dev) and 996 force-committed target/
build artifacts. codex-rs (canonical) and hanzo-dev (release) untouched.
target/ already gitignored so it won't recur.
One engine everywhere — hanzo-node can serve the same hanzo-server-core
(/v1/responses + /v1/messages + /v1/chat/completions) in-process alongside
gRPC. Default-off so the no-features build is unchanged.
Make hanzo-node natively serve the canonical Hanzo inference engine (OpenAI /
Anthropic / Responses HTTP API) in-process, alongside the existing gRPC server,
behind a new default-off `engine` Cargo feature. Purely additive: with the
feature off the node builds and behaves exactly as before.
- Cargo.toml: optional path-deps on hanzo-server-core (default-features=false)
and hanzo-engine; `engine` feature gating them; cuda/cudnn/metal/rocm/vulkan/
accelerate/mkl/nccl/flash-attn[-v3] features each forwarding to the matching
engine + server-core features (mirrors hanzo-server/Cargo.toml). default = [].
- .cargo/config.toml: rustflags target-cpu=native (engine's candle fork needs it).
- lib.rs: add EngineConfig (enabled/cpu/engine_api_addr default 0.0.0.0:36900, +
cfg-gated ModelSelected) to NodeConfig; cfg-gated hanzo_state on HanzoNode built
in new() via HanzoForServerBuilder; start() runs gRPC + axum engine API
concurrently (spawn + tokio::join!) when state is present, else unchanged.
All engine code is #[cfg(feature = "engine")]; errors map to crate::Error,
no unwrap/expect.
- bin: --engine-port/HANZO_ENGINE_ADDR, --model/HANZO_ENGINE_MODEL, --engine-cpu;
logs the engine URL on startup.
Validation (CPU box, GPU-blocked, no weights):
- cargo check -p hanzo-node (no features): pass, 0 warnings.
- cargo check -p hanzo-node --features engine: pass; warnings only from upstream
hanzo-engine/hanzo-server-core, none from hanzo-node.
GPU feature graphs (cuda/rocm/metal/...) resolve via cargo metadata but are not
compiled here (no GPU toolchains).
Removes four redundant, unreferenced trees verified as not wired into any
Cargo workspace, CI workflow, justfile, bazel build, or build-fast.sh.
Workspaces still resolve after removal (cargo metadata --no-deps --locked
exit 0 for both: codex-rs = 127 members, hanzo-dev = 47 members).
Removed (1878 files, ~175 MB reclaimed):
- published-hanzo-dev/ single-crate dead copy (pkg "dev"); 1000 files,
~166 MB (a committed build target/ dir). 0 refs.
- standalone-hanzo-dev/ single-crate dead copy (pkg "dev"); 3 files, ~28 KB.
0 refs.
- code-rs/ stale partial checkout: 80 files, ~2.6 MB, NO
Cargo.toml anywhere (not a buildable workspace),
no .git. Not a path-dep/member of anything.
- codex-rs/tui2/ prototype crate "codex-tui2"; 795 files, ~6.1 MB.
NOT in codex-rs/Cargo.toml [workspace] members and
nothing depends on codex-tui2/codex_tui2.
Verified-but-KEPT (NOT deleted):
- hanzo-dev/core/*_prompt.md duplicates: although byte-identical to the
codex-rs/core copies, hanzo-dev/core/src/model_family.rs embeds all 6
via include_str!("../<file>.md") at compile time, so deleting them would
break the hanzo-dev build. Left in place per the verify-then-delete rule.
Out of scope / untouched: codex-rs and hanzo-dev source crates, login,
providers, and the unrelated in-progress hanzo-node/rust/ engine changes.
hanzo-desktop's embedded_engine serves an OpenAI-compatible API on
localhost:36900 (/v1/chat/completions,/v1/embeddings,/v1/models). Point the
`node` provider there by default so `dev -c model_provider=node` taps the
desktop's running node out of the box; HANZO_NODE_URL overrides for remote
Hanzo/Lux/Zoo nodes. Standalone `hanzo serve` (:1234) remains `hanzo-local`.
Co-authored-by: Hanzo Dev <[email protected]>
Migrate every release.yml job from GitHub-hosted runners (ubuntu-latest/macos-14/
windows-latest) to the self-hosted Hanzo fleet labels ([self-hosted, linux|macos|
windows, amd64|arm64]; topology in hanzoai/universe infra/runners). Build payload
unchanged (frozen hanzo-dev) — this restores the publish pipe off GitHub billing
first; codex-rs cutover ships separately via the @next dist-tag.
Co-authored-by: Hanzo Dev <[email protected]>
`dev -c model_provider=node` targets a local node (localhost:1234) or any node
via HANZO_NODE_URL (e.g. a Lux or Zoo node). Same OpenAI-compatible serve API.
Co-authored-by: Hanzo Dev <[email protected]>
hanzo engine (`hanzo serve`) / hanzo-node expose an OpenAI-compatible API on
http://localhost:1234/v1 (and Anthropic /v1/messages with Claude Code harness
support). Add a built-in 'hanzo-local' provider pointing there so `dev` can use
local Hanzo inference natively: `dev -c model_provider=hanzo-local`.
Cloud default stays 'hanzo' (api.hanzo.ai).
Co-authored-by: Hanzo Dev <[email protected]>
The device-code flow hit OpenAI-shaped endpoints (/api/accounts/deviceauth/*)
that hanzo.id (Casdoor) does not serve. Fix: hanzo login now uses the browser
PKCE flow with issuer https://hanzo.id/v1/iam, so authorize/token resolve to
https://hanzo.id/v1/iam/oauth/{authorize,token} (verified vs hanzo.id OIDC
discovery). Verified the emitted authorize URL is correct.
Co-authored-by: Hanzo Dev <[email protected]>
linux-sandbox/build.rs compiles bubblewrap from codex-rs/vendor/bubblewrap on
Linux. Vendor it in-tree (LGPL-2.0+) so local and CI release builds are
self-contained (CI already installs libcap-dev + node22). Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
Old main (broken merge, does not build) is retained in history via this merge's
second parent and on backup/broken-merge-main-20260616. This tree is the working,
tested pre-merge baseline + Hanzo overlay (api.hanzo.ai default, auth fixes,
schema/bin-name test fixes). Upstream-latest re-port tracked separately.
- Add built-in 'hanzo' model provider (api.hanzo.ai/v1, Responses wire API,
HTTP transport) and make it the default model_provider_id. Auth flows through
the auth layer (Hanzo IAM OAuth from `dev login`, or HANZO_API_KEY/CODEX_API_KEY),
mirroring the OpenAI provider so managed-auth tests keep working.
- Live-verified: `dev exec` now targets api.hanzo.ai/v1/responses (was api.openai.com).
- Fix token refresh: persist_tokens no longer aborts when a refresh response
omits a parseable id_token; keeps existing claims, applies new access/refresh.
- core lib: 1631 passed / 0 failed.
Co-authored-by: Hanzo Dev <[email protected]>
- Regenerated schema fixtures to include Hanzo/Claude/OpenAI LoginAccount auth
params (json + typescript) so schema_fixtures tests pass.
- Updated 10 test files: cargo_bin("codex") -> cargo_bin("dev") to match the
renamed binary, fixing all CLI integration tests that shell out.
Co-authored-by: Hanzo Dev <[email protected]>
Working pre-merge baseline build of the dev CLI. hanzo.id-default login
(--provider hanzo|openai|claude, --with-api-key) intact. Build setup on
Linux: vendor bubblewrap into codex-rs/vendor + libcap-dev (see memory).
Co-authored-by: Hanzo Dev <[email protected]>
@zap-proto/zap moved from the old MCP-misnamed Cap'n Proto package to
the native ZAP wire runtime, and rejoined the 1.x line at 1.1.0. The
new canonical surface has a single root export (builder, client/
ZapClient, envelope, pipeline, view, wire) and NO ./protocol, ./transport,
or ./rpc subpaths — and no Client/Server/BatchClient/MessageType symbols.
The wrapper's prior src (protocol/transport/rpc/client/server/types/error
re-exporting those now-nonexistent symbols and subpaths) no longer
compiles against it. Collapse the wrapper to its honest shape: a single
`export * from "@zap-proto/zap"` root re-export. ZapClient flows through
natively, so the old `Client as ZapClient` alias is dropped (it aliased
a symbol the canonical package no longer exports; ZapClient is now the
canonical name).
- dep: @zap-proto/zap ^1.0.0 -> ^1.1.0
- version: 1.0.0 -> 1.1.0 (minor; matches the underlying line, no major break)
- build: single-entry tsup (drop the dead multi-entry subpath build)
- exports: drop ./protocol ./transport ./rpc (canonical has no such subpaths)
- repository.directory: correct to hanzo-dev/zap/sdk/typescript
- test: --passWithNoTests (pure re-export; nothing of its own to test)
Reverts violations of the durable rule that current-state docs belong
in LLM.md and history belongs in git log. Removed files were session
handoffs, agent-style "complete success" / "1000%" reports, dated
audit dumps, and stub NOTES.
## Why
Codex Review now supports repository-specific review rules in AGENTS.md.
Adding the review prompts there makes the guidance available as
repository review rules next to the code it governs while keeping the
existing local review skills intact.
## What changed
- Added a `## Code Review Rules` section to `AGENTS.md` with the
existing review prompts for model context, breaking changes, test
authoring, and change size.
- Preserved the existing `.codex/skills/code-review*` skill files.
## Verification
- `git diff --check origin/main...HEAD`
## Why
The root formatting entrypoints could drift: `just fmt` did not format
the Justfile itself, and the CI-facing check recipe only checked Python
scripts instead of matching everything formatted by `just fmt`.
## What changed
- Add a shared cross-platform Python formatter driver used by both `just
fmt` and `just fmt-check`.
- Run Justfile, Rust, Python SDK, and internal-script formatter groups
concurrently while buffering each formatter group's output until it
finishes.
- Log formatter starts immediately, then print each formatter group's
labeled output when it completes.
- Keep the SDK lint-fix and Ruff formatting passes ordered, with source
comments explaining their distinct roles and the check-mode equivalents.
- Run Ruff through shared `uv run --no-sync --with ruff` overlays so
formatting works on clean glibc Linux checkouts without installing the
platform-specific SDK runtime wheel.
- Show `fmt-check` help text in `just -l` and simplify CI to call the
shared driver through `just fmt-check`.
- Pin the general CI workflow to `[email protected].0` so its formatter agrees
with the checked-in Justfile.
- Add regression coverage for the thin Just recipes and the driver's
formatter graph.
## Validation
- `just fmt`
- `just fmt-check`
- `python3 -m pytest
sdk/python/tests/test_artifact_workflow_and_binaries.py -k 'root_fmt or
root_format' -q`
- `pnpm run format`
- `git diff --check`
- `just -l | rg -n '^ fmt|fmt-check'`
- `uvx --from uv==0.7.22 uv run --frozen --project sdk/python --no-sync
--with ruff ruff check --diff sdk/python`
## Why
Remote control enrollment authorizes a desktop server, but app-server v2
did not expose the follow-up pairing operation needed to mint a
short-lived controller pairing artifact from that enrolled server.
Clients need a narrow RPC that starts pairing without exposing the
backend `serverId` or conflating pairing with websocket connection
state.
Issue: N/A; internal remote-control pairing API change.
## What Changed
Added experimental app-server v2 `remoteControl/pairing/start` with
`manualCode` input and `pairingCode`, nullable `manualPairingCode`,
`environmentId`, and Unix-seconds `expiresAt` output. The method
serializes under its own `global("remote-control-pairing")` scope and is
documented in `app-server/README.md`.
Extended the remote-control transport with private `/server/pair`
request/response types and normalized `pair_url` handling. Pairing uses
the current enrolled server bearer, refreshes that bearer when needed,
keeps backend `server_id` private, validates returned `server_id` and
`environment_id` against the current enrollment, and preserves backend
status/header/body context for failures and malformed responses.
Wired the request through `RemoteControlRequestProcessor` and
`MessageProcessor`, mapping unavailable/disabled pairing to
`invalid_request` and backend failures to internal errors.
## Verification
- `just test -p codex-app-server-transport`
- `just test -p codex-app-server
remote_control_pairing_start_returns_pairing_artifacts`
## Summary
- Moves the existing `codex-cloud-requirements` crate to
`codex-cloud-config`.
- Updates workspace dependencies and imports to the new crate name.
- Intentionally keeps runtime behavior unchanged: this still fetches the
legacy cloud requirements endpoint.
## Details
This PR exists to make the lineage obvious before the bundle migration.
GitHub should show the old `codex-rs/cloud-requirements/src/lib.rs`
implementation as moved to `codex-rs/cloud-config/src/lib.rs`, rather
than as unrelated new code.
The follow-up PR adapts this moved crate to the new config bundle API
and switches runtime consumers over.
## Summary
Remove the dead experimental `persistExtendedHistory` app-server flag
and collapse rollout persistence to the single policy app-server already
used.
## What Changed
- Removed `persistExtendedHistory` from v2 thread start/resume/fork
params and deleted its deprecation notice path.
- Removed the persistence-mode enums and plumbing through core, rollout,
and thread-store.
- Made rollout filtering mode-free, keeping the existing limited
persisted-history behavior.
## Test Plan
- `just write-app-server-schema`
- `cargo nextest run --no-fail-fast -p codex-app-server-protocol
schema_fixtures`
- `cargo nextest run --no-fail-fast -p codex-app-server
thread_shell_command_history_responses_exclude_persisted_command_executions`
- `cargo nextest run --no-fail-fast -p codex-rollout -p
codex-thread-store`
- final `rg` for removed flag/type names
## Stack
1. Parent PR: #18240 uses named MITM permissions config.
2. This PR wires managed MITM CA trust into spawned child processes.
## Why
When Codex terminates HTTPS for limited mode or MITM hooks, child HTTPS
clients need to trust Codex's managed MITM CA. Exporting proxy URLs
alone is not enough, but blindly replacing user CA settings would be
wrong: it can break custom enterprise/test roots, leak unreadable CA
files into generated bundles, or make the child env disagree with its
sandbox policy.
## Summary
1. Build immutable managed CA bundles under `$CODEX_HOME/proxy` that
include native roots, the managed MITM CA, and only inherited or
command-scoped CA bundles the child is allowed to read.
2. Export curated CA env vars alongside managed proxy env vars while
preserving user CA override semantics, including nested Codex
`SSL_CERT_FILE` precedence.
3. Thread generated CA bundle paths into child sandbox readable roots,
including debug sandbox execution, so the exported env vars work inside
sandboxed commands.
4. Remove only Codex-generated MITM CA bundle env when a child
intentionally drops managed proxying for escalation or no-proxy retry.
5. Document the managed CA bundle behavior and cover env injection,
per-child bundle generation, sandbox readable roots, and no-proxy
cleanup in tests.
## Validation
1. Ran `just test -p codex-network-proxy`.
2. Ran `just test -p codex-protocol`.
3. Ran `just fix -p codex-network-proxy -p codex-protocol`.
4. Tried focused `codex-core` validation, but the crate currently fails
to compile in `core/tests/suite/guardian_review.rs` because an existing
`Op::UserInput` initializer is missing `additional_context`.
---------
Co-authored-by: Eva Wong <[email protected]>
## Why
Fixesopenai/codex#20944.
Desktop side chats are intentionally ephemeral and pathless. They can
still accept live turns while loaded, but after a reload there is no
persisted rollout to resume. In the reported failure mode, Desktop could
send `$CODEX_HOME` as the resume/fork path for one of these pathless
side chats.
`thread/resume` and `thread/fork` prefer an explicit `path` over
`threadId`, and rollout path lookup only checked that a candidate
existed. That let `$CODEX_HOME` pass as a rollout path, so the later
rollout reader tried to open a directory and surfaced the low-level `Is
a directory` error.
## What Changed
- Reject explicit rollout paths that resolve to a directory or other
non-file before attempting to read rollout history.
- Make `codex_rollout::existing_rollout_path` return only plain or
compressed rollout candidates that are actual files.
- Add an app-server regression test that creates an ephemeral fork, runs
a turn while the side thread is loaded, simulates reload, then verifies
both `thread/resume` and `thread/fork` reject `$CODEX_HOME` with `path
is a directory` instead of the OS-level directory-read error.
- Rebase over the `TestAppServer` rename and update the remaining stale
test harness call sites to use `TestAppServer` with `app_server` local
variables.
Relevant code:
- `thread-store/src/local/read_thread.rs` validates explicit rollout
paths before rollout reading:
https://github.com/openai/codex/blob/25b47c8f425d351aaba4baa955a8092064a1707b/codex-rs/thread-store/src/local/read_thread.rs#L146-L165
- `rollout/src/compression.rs` now requires file metadata for plain and
compressed rollout candidates:
https://github.com/openai/codex/blob/25b47c8f425d351aaba4baa955a8092064a1707b/codex-rs/rollout/src/compression.rs#L940-L950
- The repro test covers the pathless ephemeral side-chat reload case:
https://github.com/openai/codex/blob/25b47c8f425d351aaba4baa955a8092064a1707b/codex-rs/app-server/tests/suite/v2/thread_fork.rs#L774-L886
## Verification
- `just test -p codex-app-server
pathless_ephemeral_thread_rejects_codex_home_path_after_reload`
## Why
Production Codex binaries are stripped for distribution, which leaves
crashes and samples from released builds without the symbols needed for
useful stack traces. Publish symbols as separate release assets so
production artifacts stay small while released builds remain
symbolicateable.
## What changed
- Add `.github/scripts/archive-release-symbols-and-strip-binaries.sh` to
package platform-native symbols into `codex-symbols-<artifact>.tar.gz`
assets while stripping the corresponding Unix binaries before signing.
- Build release binaries with full debug information before producing
distribution artifacts.
- Publish macOS `.dSYM` bundles, Linux `.debug` files with
`.gnu_debuglink`, and Windows `.pdb` files.
- Strip Linux `bwrap` before computing its packaged-resource digest, but
intentionally omit `bwrap` from symbol archives.
- Preserve symbols artifacts in the unsigned macOS promotion flow.
## Verification
- Ran `shellcheck` and `bash -n` on
`.github/scripts/archive-release-symbols-and-strip-binaries.sh`.
- Parsed the modified workflow YAML files and ran `git diff --check`.
- Built a macOS release smoke binary and verified that the archived
`.dSYM` contains DWARF application source information and has the same
UUID as the stripped production binary.
- Built Linux smoke binaries and verified that the symbol archive
contains `codex.debug`, excludes `bwrap.debug`, leaves the expected
`.gnu_debuglink` in `codex`, and does not mutate the separately stripped
`bwrap` digest.
- Staged a Windows smoke archive and verified that it contains the
expected `.pdb` file.
## Why
The TUI shortcut overlay used static labels for `Tab` and `Ctrl+C`, even
though both keys change behavior while a task is running. That made the
visible help misleading: idle `Tab` submits rather than queues, and
active-turn `Ctrl+C` interrupts rather than exits.
Closes#25531.
Closes#25564.
## What Changed
- Pass task-running state into the shortcut overlay renderer.
- Render `Tab` as `submit message` while idle and `queue message` while
work is running.
- Render `Ctrl+C` as `exit` while idle and `interrupt` while work is
running.
- Add snapshot coverage for the active-work shortcut overlay and update
idle overlay snapshots.
## How to Test
1. Start Codex and open the shortcut overlay with `?` while no task is
running.
2. Confirm the overlay shows `tab to submit message` and `ctrl + c to
exit`.
3. Start a task, then open or keep the shortcut overlay visible while
work is running.
4. Confirm the overlay shows `tab to queue message` and `ctrl + c to
interrupt`.
5. Type a follow-up prompt during active work and press `Tab`; confirm
it queues rather than submitting immediately.
Targeted tests:
- `just test -p codex-tui footer_snapshots`
- `just test -p codex-tui footer_mode_snapshots`
## Validation Notes
`just test -p codex-tui` currently has two unrelated guardian
feature-flag test failures on this base:
-
`app::tests::update_feature_flags_disabling_guardian_clears_manual_review_policy_without_history`
-
`app::tests::update_feature_flags_disabling_guardian_clears_review_policy_and_restores_default`
`just argument-comment-lint codex-rs/tui/src/bottom_pane/footer.rs`
could not run locally because the prebuilt wrapper requires `dotslash`;
the touched Rust diff was manually inspected for opaque positional
literals.
Deferred tools need to be searchable even when they are not implemented
inside `codex-core`. Extension-provided tools can be registered for
later discovery, but the search metadata path was still owned by
core-specific runtime hooks, which meant the shared `ToolExecutor`
abstraction could not describe how a deferred extension tool should
appear in `tool_search`.
## Changes
- Move `ToolSearchEntry` and `ToolSearchInfo` into `codex-tools` and
re-export them from the shared tools crate.
- Add a default `ToolExecutor::search_info` implementation that derives
loadable tool-search metadata from function and namespace specs.
- Forward search metadata through extension adapters and exposure
overrides while keeping custom search text/source metadata for dynamic,
MCP, and multi-agent tools.
- Remove the old core-local `tool_search_entry` module now that search
metadata lives with the shared executor APIs.
## Testing
- Added `deferred_extension_tools_are_discoverable_with_tool_search`
coverage in `core/src/tools/spec_plan_tests.rs`.
## Why
#25701 renamed the app-server test harness to `TestAppServer`, but it
raced with #25681, which added a new `plugin_list` test call site still
using the old `McpProcess` name. Once both changes met on `main`,
app-server test builds failed before running the suite because
`McpProcess` no longer exists in that scope.
This PR fixes that CI break by updating the remaining stale call site to
the renamed helper.
## What Changed
- Replaced the `McpProcess::new(...)` use in
`codex-rs/app-server/tests/suite/v2/plugin_list.rs` with
`TestAppServer::new(...)`.
- Renamed the local variable from `mcp` to `app_server` at the same call
site to match the helper rename.
Relevant code:
https://github.com/openai/codex/blob/aadd9c999b4e0789f7afb2b9b8cc43000bb47e86/codex-rs/app-server/tests/suite/v2/plugin_list.rs#L234-L246
## Verification
Not run locally; this is a compile fix for the app-server test harness
rename.
## Summary
- opt the extension-backed standalone `web.run` tool into parallel tool
execution
- update the existing extension registration test to assert that the
tool advertises parallel-call support
## Why
The standalone web-search API endpoint now supports parallel requests.
The extension executor still inherited the shared serial default,
causing multiple `web.run` calls to acquire the exclusive runtime lock.
## Impact
Models that emit multiple standalone web-search calls can now execute
them concurrently when model-level parallel tool calls are enabled.
## Validation
- `just fmt`
- `just test -p codex-web-search-extension`
- `git diff --check origin/main...HEAD`
This PR brought to you via VS Code rather than Codex...
- opened `codex-rs/app-server/tests/common/mcp_process.rs`
- put the cursor on `McpServer`
- hit `F2` and renamed the symbol to `TestAppServer`
- went to the file tree
- hit enter and renamed `mcp_process.rs` to `test_app_server.rs`
- ran **Save All Files** from the Command Palette
- ran `just fmt`
The End
(Admittedly, most of the local variables for `TestAppServer` are still
named `mcp`, though.)
## Why
Python contributions in this repository should target the declared
Python 3 runtime instead of carrying Python 2 compatibility patterns
forward. When compatibility across Python 3 point releases matters,
contributors need a consistent source of truth for the minimum supported
version.
## What changed
- Added Python development guidance to `AGENTS.md` stating that the
repository uses Python 3+ and should not use the `__future__` module.
- Documented that contributors should check the nearest `pyproject.toml`
`requires-python` field when evaluating Python 3 point-release
compatibility.
## Testing
Not run (guidance-only change).