457 sites carried an upstream prefix into every surface a user reaches — shell
exports, docs, CI, the SDK. CODEX_ is not our name and it was never going to
stop arriving on its own: it is what upstream writes, and every sync brings more.
Two namespaces, because they answer different questions.
DEV_* the app's own configuration — DEV_HOME, DEV_PROFILE, the rest
HANZO_API_KEY a credential for the Hanzo stack, which is not app config
CODEX_API_KEY held the literal string "CODEX_API_KEY", so the rename moves the
value and not just the constant. It becomes HANZO_API_KEY, which is what
create_hanzo_provider already reads through HANZO_MACHINE_ENV_KEYS — one name
for one credential instead of two spellings of it.
vendor/ is untouched, which is the point of vendor/: upstream code keeps
upstream names, and the boundary is a path rather than a habit.
The Auto Drive routing test asserted the gpt-5.5/gpt-5.4-mini defaults I had
just replaced, and the sync moved app-server-protocol/v2 without regenerating
the vendored schema fixtures, so MultiAgentVersion.ts was missing.
Both were visible only by running the suite. I ran hanzo_identity and the TUI
tests and pushed on that, and `make check` compiles test targets without
running them — neither is the gate CI applies.
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.
63 commits since the recorded sync point, including just-every's own refresh
of the codex-rs mirror to openai/codex:main. 371 files, but 361 of them are
mirror; the product delta is 8 files in code-rs/ (remote model discovery,
client retry, theme persistence, rollout recorder) plus a package bump.
codex-rs/models-manager/models.json — the one mirror file compiled into the
shipping binary — is unchanged by this delta and already byte-identical to
upstream, so the mirror refresh is hygiene, not function.
Note for the next sync: generate the delta with `git diff --binary`. Two .zst
schema fixtures reject a plain patch, and git apply is atomic, so it rolls
back all 371 files while printing "cleanly" for each one.
`schema_fixtures_match_generated` compares the checked-in fixture tree against
freshly generated output, and it was red before this sync: 0a1b157d2c added
QueueUserMessage to the app-server protocol without regenerating, so json/v1
and typescript/ were each missing QueueUserMessageParams/Response.
Regenerated with the crate's own writer:
cargo run -p code-app-server-protocol --bin write_schema_fixtures
That closes the pre-existing gap and picks up what this sync added — the diff
carries both the QueueUserMessage definitions and 15 transparent_background
occurrences from the image-generation metadata backport.
Takes the upstream delta e4fe007150..00910569e0 from just-every/code, our
proximate upstream. hanzo/dev has no merge-base with any upstream (its history
was rewritten, so every SHA differs while the root trees are identical), so
this lands as a 3-way apply of the delta rather than a merge. Zero conflicts:
the upstream delta touches 249 files, our fork diverges in 140, and the two
sets intersect in exactly 2 files (protocol.rs, chatwidget.rs), both pure
additions that leave every Hanzo identity line alone.
Carries the surface the sandbox agent needs, with the codex PR numbers intact:
57f42a8113 tool search: no clone of immutable metadata on cache hits (#37279)
e1831db7c3 reuse MCP handlers across sampling steps (#37273)
bfb6a6ea22 plugin roots in the host skill loader (#37267)
1151b23f01 start cached MCP servers lazily for subagents (#37261)
7a0e974e08 harden network proxy MITM authorization (#37211)
98da2c4499 reserve the `tool_search` namespace for the search tool (#37188)
1dc93cdeb0 refresh the codex-rs mirror to codex main
codex-rs/ is a vendored mirror that just-every refreshes wholesale; patching it
directly would be overwritten by the next refresh, so we take their refresh
instead of cherry-picking from openai/codex.
Three things the last pass left flagged. Two are done; the third turned out to
belong somewhere else and is reported rather than forced in.
## exec --json emits the schema instead of the SDK guessing it
`exec_events.rs` and `experimental_event_processor_with_json_output.rs` had no
`mod` declaration, so 683 lines defining the `thread.*`/`item.*` schema never
compiled. `sdk/typescript/src/events.ts` says "based on event types from
code-rs/exec/src/exec_events.rs" and then rebuilt those events client-side from
raw core events — the contract existed only in TypeScript, and nothing checked
the two halves agreed.
Declared the modules and fixed what drifted while dead: TaskStarted became a
unit variant, WebSearchEnd became WebSearchComplete, StreamError folded into
Error, ExecCommandEndEvent lost `aggregated_output`, print_config_summary lost a
parameter. `--json` now uses it (`--experimental-json` is an alias, matching
upstream), and the old raw-event processor is deleted rather than left as a
second way to do this. thread.started needed a route because exec consumes
SessionConfigured before the event loop, so EventProcessor grew a defaulted
`on_session_configured`.
Making it real immediately found a lie: the SDK's `Usage` declares five fields
and we emitted three. core::TokenUsage had `cache_write_input_tokens` and
`reasoning_output_tokens` all along; the processor dropped them. Against a mock
model:
{"type":"thread.started","thread_id":"2bd35c77-..."}
{"type":"turn.started"}
{"type":"item.completed","item":{"id":"item_0","type":"agent_message","text":"Hello from the model."}}
{"type":"turn.completed","usage":{"input_tokens":11,"cached_input_tokens":2,
"cache_write_input_tokens":0,"output_tokens":5,"reasoning_output_tokens":1}}
The SDK now passes those through instead of reconstructing them. Its test suite
did not compile — at HEAD and in just-every upstream: runStreamed.test.ts uses
`path` and `createMockClient` without importing either, testCodex.ts passes
`config` to a type declaring `configOverrides`, and findCodexPath() referenced
four names (`moduleRequire`, `CODEX_NPM_NAME`, `createRequire`,
`PLATFORM_PACKAGE_BY_TARGET`) that were never declared anywhere. Declared them
against @hanzo/dev, added `env` to CodexOptions, pointed the harness at
code-rs/target/debug/dev instead of codex-rs/target/debug/codex.
pnpm exec jest tests/runStreamed.test.ts --testTimeout=120000
3 passed (asserts thread.started, turn.started, item.completed, turn.completed
and item.type === "agent_message" against the real binary)
## queueUserMessage: steer a turn instead of tearing it
`sendUserMessage` submits Op::UserInput, and core/src/codex/streaming.rs:998
calls `sess.abort()` before spawning a new turn — over app-server you could
interrupt a turn, never redirect one. Op::QueueUserInput folds items into the
running task instead, and only the TUI used it. It is now an app-server method.
Separate method, not a flag: interrupting and steering are different acts and a
caller should not pick the destructive one by accident.
→ {"method":"queueUserMessage","id":3,"params":{"conversationId":"999222eb-…",
"items":[{"type":"text","data":{"text":"steer me"}}]}}
← {"id":3,"jsonrpc":"2.0","result":{}}
← {"error":{"code":-32600,"message":"conversation not found: 00000000-…"},"id":4}
## zrok: not ours to build
Assessed and deliberately not implemented here. `hanzo link` already composes
ttyd + share::start + publish_terminal into exactly this feature, and
cli/src/commands/share.rs calls itself "the ONE implementation of 'publish a
local port on the fabric'". `dev` has no framable surface anyway — app-server is
raw JSON-RPC — and no IAM identity to reach POST /v1/share/enable. The gap is in
cloud/cmd/boxd, which already execs `dev`. Details in the report.
Also: git.hanzo.ai release migration precondition written into LLM.md (four
call sites, forge serves /v1/ not /api/v1/, publish to both for a cycle before
moving the updater). SDK package was @openai/codex-sdk; now @hanzo/dev-sdk.
cargo test -p {code-core,code-protocol,code-cli,code-app-server,
code-exec,code-mcp-server,code-tui} -- --test-threads=1
1311 passed; 1 failed
The failure is git_info::test_collect_git_info_with_remote, still environmental:
the new narrower insteadOf rule only covers hanzoai/*, and the test's URL is
github.com/example/repo, which the broad rule still rewrites.
Version 0.2.189 -> 0.2.190.
Co-authored-by: Hanzo Dev <[email protected]>
Our history is just-every's with author emails rewritten, so the graphs are
disjoint and git finds no merge base. Supplied one by hand: d1f1f51a41, the
just-every commit matching our Oct-2025 fork point (22 files apart). 9618
upstream commits, 7004 files, +1.81M/-159k, 37 conflicts.
Resolution:
- Upstream code where our side was the Oct-2025 prototype of a feature they
have since reimplemented 3-5x larger (agent_runs, browser_sessions,
history_cell/{agent,browser}, the vt100 harness and its snapshots).
- Upstream's config.rs module split (builder/defaults/sources/validation)
kept; zen5-coder and the provider-follows-model rule re-applied on top.
- Ours where the file IS the identity: README, package.json, postinstall,
release notes pipeline, integration-zed.
- Hybrid where upstream improved a file we had branded: updates.rs (their
release-repo migration, our hanzoai/dev), release.yml (their fail-fast npm
auth check, our package name), chatwidget.rs (their turn handling, our
HANZO_USER_KEY hint), exec human output (their 237 lines, our banner).
Superseded and dropped deliberately: our resume_command_name() coder-alias
hack — upstream's derive_resume_command_name() reads the invocation basename
generically, which yields "dev" for us.
LLM.md now records the real topology and the sync point; AGENTS.md and
CLAUDE.md are symlinks to it again. Single parent on purpose: adopting
jecode/main as a second parent would re-import 13,742 commits carrying the
upstream author emails a prior rewrite deliberately removed.
Version 0.2.188 -> 0.2.189.
Co-authored-by: Hanzo Dev <[email protected]>