vendor: upstream lives under vendor/, so ours is what is left

codex-rs/ is a read-only mirror of openai/codex that just-every refreshes and
we never edit. It sat at the repo root next to code-rs/, the product, and the
only thing separating them was that everyone knew. Nothing checked it.

That knowing is what makes branding endless. There are ~400 upstream-brand
literals in code-rs today and ~224 of ours, hand-placed on the same lines the
sync delta lands on, so every sync re-fights the same 17 files. You cannot fix
that while the line between "theirs" and "ours" is a convention.

vendor/codex/ makes it a boundary. Everything under vendor/ is upstream: never
branded, never edited, replaced wholesale on sync. Everything outside it is
ours and must carry our name — which is now a question a test can ask.

code-rs coupled to the mirror through exactly one line, an include_str! of
models.json, and it still does. The other 17 files are path strings.

Syncing changes by one sed: just-every's delta names codex-rs/, so rewrite the
patch paths to vendor/codex/ before applying it.
This commit is contained in:
2026-08-07 21:22:34 -07:00
parent 68d83e82e6
commit 25f1f1da4f
5643 changed files with 45 additions and 45 deletions
+1 -1
View File
@@ -8,4 +8,4 @@ script = "python ./.codex/environments/setup.py"
[[actions]]
name = "Run"
icon = "run"
command = "cargo +1.95.0 run --manifest-path=codex-rs/Cargo.toml --bin codex -- -c mcp_oauth_credentials_store=file"
command = "cargo +1.95.0 run --manifest-path=vendor/codex/Cargo.toml --bin codex -- -c mcp_oauth_credentials_store=file"
+2 -2
View File
@@ -87,13 +87,13 @@ the Linux host. The cross-platform build dependency means they only run in Bazel
For core integration tests:
```sh
bazel test //codex-rs/core:core-all-wine-exec-test
bazel test //vendor/codex/core:core-all-wine-exec-test
```
For app-server integration tests:
```sh
bazel test //codex-rs/app-server:app-server-all-wine-exec-test
bazel test //vendor/codex/app-server:app-server-all-wine-exec-test
```
## Devboxes
+2 -2
View File
@@ -37,10 +37,10 @@ To build the contributor image locally for x64 and then run it with the repo mou
```shell
CODEX_DOCKER_IMAGE_NAME=codex-linux-dev
docker build --platform=linux/amd64 -t "$CODEX_DOCKER_IMAGE_NAME" ./.devcontainer
docker run --platform=linux/amd64 --rm -it -e CARGO_TARGET_DIR=/workspace/codex-rs/target-amd64 -v "$PWD":/workspace -w /workspace/codex-rs "$CODEX_DOCKER_IMAGE_NAME"
docker run --platform=linux/amd64 --rm -it -e CARGO_TARGET_DIR=/workspace/vendor/codex/target-amd64 -v "$PWD":/workspace -w /workspace/codex-rs "$CODEX_DOCKER_IMAGE_NAME"
```
Note that `/workspace/target` will contain the binaries built for your host platform, so we include `-e CARGO_TARGET_DIR=/workspace/codex-rs/target-amd64` in the `docker run` command so that the binaries built inside your container are written to a separate directory.
Note that `/workspace/target` will contain the binaries built for your host platform, so we include `-e CARGO_TARGET_DIR=/workspace/vendor/codex/target-amd64` in the `docker run` command so that the binaries built inside your container are written to a separate directory.
For arm64, specify `--platform=linux/arm64` instead for both `docker build` and `docker run`.
+1 -1
View File
@@ -16,7 +16,7 @@
"containerEnv": {
"RUST_BACKTRACE": "1",
"CARGO_TARGET_DIR": "${containerWorkspaceFolder}/codex-rs/target-arm64"
"CARGO_TARGET_DIR": "${containerWorkspaceFolder}/vendor/codex/target-arm64"
},
"remoteUser": "ubuntu",
+1 -1
View File
@@ -38,7 +38,7 @@ runs:
env:
CACHE_SCOPE: ${{ inputs.cache-scope }}
TARGET: ${{ inputs.target }}
CACHE_HASH: ${{ hashFiles('MODULE.bazel', 'codex-rs/Cargo.lock', 'codex-rs/Cargo.toml') }}
CACHE_HASH: ${{ hashFiles('MODULE.bazel', 'vendor/codex/Cargo.lock', 'vendor/codex/Cargo.toml') }}
run: |
echo "repository-cache-key=bazel-cache-${CACHE_SCOPE}-${TARGET}-${CACHE_HASH}" >> "${GITHUB_OUTPUT}"
echo "repository-cache-restore-key=bazel-cache-${CACHE_SCOPE}-${TARGET}-" >> "${GITHUB_OUTPUT}"
+1 -1
View File
@@ -49,7 +49,7 @@ runs:
{
echo "files<<EOF"
for binary in ${BINARIES}; do
echo "${GITHUB_WORKSPACE}/codex-rs/target/${TARGET}/release/${binary}.exe"
echo "${GITHUB_WORKSPACE}/vendor/codex/target/${TARGET}/release/${binary}.exe"
done
echo "EOF"
} >> "$GITHUB_OUTPUT"
+1 -1
View File
@@ -11,7 +11,7 @@ updates:
- package-ecosystem: cargo
directories:
- codex-rs
- codex-rs/*
- vendor/codex/*
schedule:
interval: weekly
cooldown:
+10 -10
View File
@@ -1,5 +1,5 @@
{
"_comment": "code-rs/** is the workspace that SHIPS. The codex-rs/** entries below guard the vendored upstream copy; the code-rs/** entries guard the product. Files carrying Hanzo identity (default provider, default model, binary name, login command) are listed explicitly so an upstream merge cannot take them back. code-rs/core/tests/hanzo_identity.rs asserts the same invariants and fails the build if it does.",
"_comment": "code-rs/** is the workspace that SHIPS. The vendor/codex/** entries below guard the vendored upstream copy; the code-rs/** entries guard the product. Files carrying Hanzo identity (default provider, default model, binary name, login command) are listed explicitly so an upstream merge cannot take them back. code-rs/core/tests/hanzo_identity.rs asserts the same invariants and fails the build if it does.",
"prefer_ours_globs": [
"code-rs/core/src/model_provider_info.rs",
"code-rs/core/src/config.rs",
@@ -10,13 +10,13 @@
"code-rs/exec/src/event_processor_with_human_output.rs",
"code-rs/mcp-server/src/message_processor.rs",
"code-rs/tui/**",
"codex-rs/tui/**",
"vendor/codex/tui/**",
"codex-cli/**",
"codex-rs/core/src/openai_tools.rs",
"codex-rs/core/src/codex.rs",
"codex-rs/core/src/agent_tool.rs",
"codex-rs/core/src/default_client.rs",
"codex-rs/protocol/src/models.rs",
"vendor/codex/core/src/openai_tools.rs",
"vendor/codex/core/src/codex.rs",
"vendor/codex/core/src/agent_tool.rs",
"vendor/codex/core/src/default_client.rs",
"vendor/codex/protocol/src/models.rs",
".github/workflows/**",
"docs/**",
"AGENTS.md",
@@ -24,9 +24,9 @@
"CHANGELOG.md"
],
"prefer_theirs_globs": [
"codex-rs/common/**",
"codex-rs/exec/**",
"codex-rs/file-search/**"
"vendor/codex/common/**",
"vendor/codex/exec/**",
"vendor/codex/file-search/**"
],
"purge_globs": [
".github/codex-cli-*.png",
@@ -31,7 +31,7 @@ read_query_labels() {
rm -f "$query_stdout" "$query_stderr"
}
final_build_targets=(//codex-rs/...)
final_build_targets=(//vendor/codex/...)
if [[ "${RUNNER_OS:-}" == "Windows" ]]; then
# Bazel's local Windows platform currently lacks a default test toolchain for
# `rust_test`, so target the concrete Rust crate rules directly. The lint
@@ -41,7 +41,7 @@ if [[ "${RUNNER_OS:-}" == "Windows" ]]; then
while IFS= read -r label; do
[[ -n "$label" ]] || continue
final_build_targets+=("$label")
done < <(read_query_labels 'kind("rust_(library|binary|proc_macro) rule", //codex-rs/...)')
done < <(read_query_labels 'kind("rust_(library|binary|proc_macro) rule", //vendor/codex/...)')
if [[ ${#final_build_targets[@]} -eq 0 ]]; then
echo "Failed to discover Windows Bazel lint targets." >&2
+3 -3
View File
@@ -329,13 +329,13 @@ jobs:
echo "## Fork-relevant non-merge commits"
echo
git log --no-merges --no-color --format='* %h %s (%an)' --abbrev=8 "$RANGE" -- \
':!codex-rs/**' \
':!vendor/codex/**' \
':!codex-cli/.pack/**' \
':!docs/release-notes/**' \
':!CHANGELOG.md' \
| sed -n '1,160p' || true
total=$(git log --no-merges --format='%H' "$RANGE" -- \
':!codex-rs/**' \
':!vendor/codex/**' \
':!codex-cli/.pack/**' \
':!docs/release-notes/**' \
':!CHANGELOG.md' \
@@ -348,7 +348,7 @@ jobs:
echo "## First-parent changed files"
echo
git diff --stat "$RANGE" -- \
':!codex-rs/**' \
':!vendor/codex/**' \
':!codex-cli/.pack/**' \
':!docs/release-notes/**' \
':!CHANGELOG.md' \
+9 -9
View File
@@ -38,18 +38,18 @@ these are contract, not preference:
| Homebrew | `hanzoai/homebrew-tap`, `Formula/hanzo-dev.rb`, assets `dev-<triple>` | `scripts/generate-homebrew-formula.sh` |
| Release repo | `hanzoai/dev` | `code-rs/tui/src/updates.rs`, `codex-cli/postinstall.js` |
**`code-rs/` is the workspace that SHIPS.** `codex-rs/` is the vendored upstream
copy. A change that only edits `codex-rs/` changes nothing a user runs — this is
**`code-rs/` is the workspace that SHIPS.** `vendor/codex/` is the vendored upstream
copy. A change that only edits `vendor/codex/` changes nothing a user runs — this is
the single easiest mistake to make here, and `.github/merge-policy.json` made it
for a long time (every glob pointed at `codex-rs/**`).
for a long time (every glob pointed at `vendor/codex/**`).
That sentence only became true with the v0.6.169 merge. Before it, building
`dev` compiled ten crates out of `codex-rs/` — they were real path
`dev` compiled ten crates out of `vendor/codex/` — they were real path
dependencies, so the "read-only mirror" was load-bearing. Upstream finished
the migration and the two workspaces are now separate. One thread remains:
`codex-rs/models-manager/models.json` is `include_str!`'d by
`vendor/codex/models-manager/models.json` is `include_str!`'d by
`code-version/src/lib.rs`, `core/src/model_family.rs` and
`core/src/agent_defaults.rs`. Deleting `codex-rs/` would not build.
`core/src/agent_defaults.rs`. Deleting `vendor/codex/` would not build.
**Why there is a test for all of this.** A one-time edit to a default is a
suggestion that lasts until the next merge. `code-rs/core/tests/hanzo_identity.rs`
@@ -106,7 +106,7 @@ Read this before attempting a sync. The directory names lie about the topology.
is just-every's history with every author email rewritten to `[email protected]`,
which is why `git merge-base` against just-every returns nothing: identical
trees, different SHAs, disjoint graph.
- **`codex-rs/` is not ours to track.** just-every carries it as a read-only
- **`vendor/codex/` is not ours to track.** just-every carries it as a read-only
mirror of `openai/codex:main` and refreshes it with "Refresh codex-rs mirror
to upstream/main" commits. It reaches us through them. We never merge
openai/codex directly. (The `upstream` git remote pointing at openai/codex is
@@ -123,7 +123,7 @@ commit our tree currently matches is recorded here, and nowhere else:
method 3-way apply of the delta (see below)
Generate the delta with `git diff --binary`. Two schema fixtures under
`codex-rs/app-server-protocol/schema/precomputed/` are `.zst` blobs, and
`vendor/codex/app-server-protocol/schema/precomputed/` are `.zst` blobs, and
`git apply` is atomic: without full index lines it rejects those two hunks and
silently rolls back all 371 files, reporting "Applied patch … cleanly" for
every other file on the way. A clean worktree after an apply that printed
@@ -143,7 +143,7 @@ in 140, and the intersection was 2 files — both pure additions.
**Do not merge `openai/codex` directly**, whatever the `upstream` remote
suggests. Measured 2026-08-06: `origin/main` and `openai/codex` share no merge
base at all (different root commits), our `codex-rs/` mirror differs from
base at all (different root commits), our `vendor/codex/` mirror differs from
upstream by 341 shadowed files and ~175k lines, and 72 upstream crates have no
counterpart here. The subsystems people ask for by name — `tool_search`,
`thread_manager`, `multi_agents_v2`, MCP `connection_manager`, `resize_reflow` —
+1 -1
View File
@@ -2,7 +2,7 @@ load("@crates//:defs.bzl", "all_crate_deps")
load("@rules_rust//rust:defs.bzl", "rust_binary")
load("//:defs.bzl", "workspace_root_test")
_WORKSPACE_ROOT_MARKER = "//codex-rs/utils/cargo-bin:repo_root.marker"
_WORKSPACE_ROOT_MARKER = "//vendor/codex/utils/cargo-bin:repo_root.marker"
def codex_e2e_benchmark(name, binaries = [], data = [], deps = []):
"""Defines a Bazel-only Divan end-to-end benchmark.
+6 -6
View File
@@ -4,7 +4,7 @@ This guide documents the process for moving shared crates from `codex-rs` into `
## Overview
The `code-rs` repository currently contains thin wrapper crates that re-export functionality from their `codex-rs` counterparts. This creates a cross-repository dependency via relative paths (`../codex-rs/...`). The migration process moves the implementation into `code-rs` so that the crate owns its code and no longer depends on `codex-rs`.
The `code-rs` repository currently contains thin wrapper crates that re-export functionality from their `codex-rs` counterparts. This creates a cross-repository dependency via relative paths (`../vendor/codex/...`). The migration process moves the implementation into `code-rs` so that the crate owns its code and no longer depends on `codex-rs`.
## Case Study: linux-sandbox Migration
@@ -20,7 +20,7 @@ We successfully migrated `code-linux-sandbox` as a representative example. This
### 1. Pre-Migration Analysis
Before starting, understand:
- **Source crate location**: `/home/azureuser/code/codex-rs/<crate-name>/`
- **Source crate location**: `/home/azureuser/code/vendor/codex/<crate-name>/`
- **Destination crate location**: `/home/azureuser/code/code-rs/<crate-name>/`
- **Current wrapper structure**: Usually just `pub use codex_<crate>::*;`
- **Dependencies**: What other crates does this depend on?
@@ -32,11 +32,11 @@ Copy all implementation files from codex-rs to code-rs:
```bash
# Source modules (excluding lib.rs which needs special handling)
cp codex-rs/<crate>/src/*.rs code-rs/<crate>/src/
cp vendor/codex/<crate>/src/*.rs code-rs/<crate>/src/
# Exception: main.rs will need modification
# Tests (if they exist)
cp -r codex-rs/<crate>/tests/ code-rs/<crate>/tests/
cp -r vendor/codex/<crate>/tests/ code-rs/<crate>/tests/
```
**Files to copy:**
@@ -104,7 +104,7 @@ pub fn run_main() -> ! {
```
**Key considerations:**
- Copy the exact module structure from `codex-rs/<crate>/src/lib.rs`
- Copy the exact module structure from `vendor/codex/<crate>/src/lib.rs`
- Keep platform-specific conditional compilation (`#[cfg(...)]`)
- Preserve all public exports
- Update any codex-specific naming to code-specific
@@ -162,7 +162,7 @@ Remove the cross-repository dependency reference.
```toml
[workspace.dependencies]
# ...
codex-linux-sandbox = { path = "../codex-rs/linux-sandbox" }
codex-linux-sandbox = { path = "../vendor/codex/linux-sandbox" }
# ...
```
+1 -1
View File
@@ -21,7 +21,7 @@ find <crate-name>/src -name '*.rs' -exec sed -i 's/codex_core/code_core/g' {} +
find <crate-name>/src -name '*.rs' -exec sed -i 's/codex_<old_name>/code_<new_name>/g' {} +
# 6. Remove from workspace Cargo.toml
vim Cargo.toml # Delete the codex-<crate> = { path = "../codex-rs/..." } line
vim Cargo.toml # Delete the codex-<crate> = { path = "../vendor/codex/..." } line
# 7. Build and verify
cargo build -p code-<crate-name>
@@ -48,7 +48,7 @@ impl ThreadHistoryBuilder {
}
/// This function should handle all EventMsg variants that can be persisted in a rollout file.
/// See `should_persist_event_msg` in `codex-rs/core/rollout/policy.rs`.
/// See `should_persist_event_msg` in `vendor/codex/core/rollout/policy.rs`.
fn handle_event(&mut self, event: &EventMsg) {
match event {
EventMsg::UserMessage(payload) => self.handle_user_message(payload),
+1 -1
View File
@@ -14,7 +14,7 @@ pub const CODE_VERSION: &str = {
};
const ANNOUNCEMENT_TIP: &str = include_str!("../../../announcement_tip.toml");
const MODELS_MANIFEST: &str = include_str!("../../../codex-rs/models-manager/models.json");
const MODELS_MANIFEST: &str = include_str!("../../../vendor/codex/models-manager/models.json");
pub const MIN_WIRE_COMPAT_VERSION_FALLBACK: &str = "0.101.0";
static MIN_WIRE_COMPAT_VERSION: LazyLock<String> = LazyLock::new(|| {
+1 -1
View File
@@ -33,7 +33,7 @@ const QWEN_3_CODER_READ_ONLY: &[&str] = &[];
const QWEN_3_CODER_WRITE: &[&str] = &["-y"];
const CLOUD_GPT5_CODEX_READ_ONLY: &[&str] = &[];
const CLOUD_GPT5_CODEX_WRITE: &[&str] = &[];
const MODELS_MANIFEST: &str = include_str!("../../../codex-rs/models-manager/models.json");
const MODELS_MANIFEST: &str = include_str!("../../../vendor/codex/models-manager/models.json");
/// Canonical list of built-in agent model slugs used when no `[[agents]]`
/// entries are configured. The ordering here controls priority for legacy
+1 -1
View File
@@ -36,7 +36,7 @@ const CONTEXT_WINDOW_1M: u64 = 1_047_576;
const MAX_OUTPUT_DEFAULT: u64 = 128_000;
static UPSTREAM_MODELS: Lazy<Vec<ModelInfo>> = Lazy::new(|| {
serde_json::from_str::<ModelsResponse>(include_str!("../../../codex-rs/models-manager/models.json"))
serde_json::from_str::<ModelsResponse>(include_str!("../../../vendor/codex/models-manager/models.json"))
.map(|response| response.models)
.unwrap_or_else(|err| panic!("failed to parse upstream models.json: {err}"))
});
View File
View File
View File
View File

Some files were not shown because too many files have changed in this diff Show More