`codex-cli/` published `@hanzo/dev`, so the directory carrying our npm
package was named after someone else's product. It is `npm/`.
`patches/codex.json` is `patches/upstream.json` — it anchors edits against
upstream, and the file should say so rather than name one of them.
Deleted outright: `justfile`, whose first line was
`set working-directory := "codex-rs"` for a directory this repository has
never had; `announcement_tip.toml`, an example file for a TUI we do not
ship; and `.codex/` and `.code/`, which held upstream's own process skills
— babysit-pr, codex-bug, pushing-ci-changes — that were never ours.
Three branding leaks a real run turned up, none of which the help text
showed: `dev exec` announced "OpenAI Codex v0.7.0-dev.1" as its first
line, the status card was missed when the session header was anchored,
and both bubblewrap warnings said "Codex's Linux sandbox".
README: say what ships. It claimed the agent drives a browser, which is
the port that has not landed, and showed a screenshot of it doing so.
Both are gone until the bridge is back. The model count is "hundreds" —
`/v1/models` answers 458 today, an earlier line here said "over 500", and
hanzo.ai derives its own count precisely because typed ones drift.
Document the npm install beside the curl one; both give the same build.
Replaces the Rust tree. `code-rs/` was a fork of just-every/code carrying
its own copy of everything; `vendor/` held 219 MB of upstream snapshots
beside it. Both are gone.
In their place: Hanzo writes the command surface, upstream keeps the
engines. `crates/hanzo-dev/src/main.rs` is a real file that dispatches
into libraries — codex_tui::run_main, codex_exec::run_main, and the rest
— rather than an include! of upstream's 5156-line binary main. Owning the
front door is what makes a single unified command surface expressible.
Upstream arrives as submodules at upstream/codex and upstream/code, both
at latest. The gitlink is the pin, so no lockfile of hashes sits beside
it and a bump is a two-line diff instead of forty-five thousand. Crates
are consumed by ordinary path dependency; nothing is copied.
The whole Hanzo delta on upstream is sixteen anchored substitutions in
patches/codex.json, applied in place by `make prepare` and visible in one
`git -C upstream/codex status`. Each carries an exact match count, so
upstream moving the ground under one stops preparation and names the file
rather than branding the wrong line. Two are upstreamable: they publish
mcp_cmd, plugin_cmd and doctor from upstream's library instead of burying
them in its binary.
`dev` covers exec, login, logout, serve, resume, fork, review, agents,
queue, archive, unarchive, delete, cloud, mcp, plugin, doctor, features,
sandbox and completion. Auto Drive and the browser bridge are not ported
yet; migration/STATUS.md records that, and the defects the v1 patch was
already carrying, so they are fixed as features are ported rather than
copied across.
Releases build from the root after `make prepare`, with submodules
checked out. Scripts that existed only to manage a fork-diff — the
upstream-merge set and the codex path-dep check — go with the fork.
The GitHub Actions lane was dropped and nothing replaced it, so v0.6.95 was
tagged and never published; npm and every installer still hand out 0.6.94.
The reason given — no runner for four of the five targets — is not true of a
Mac: it builds darwin natively, both linux-musl through cargo-zigbuild and
windows-msvc through cargo-xwin, all verified from this machine. So the
release is .hanzo/workflows/release.yml on the dbc-metal host runner, one
job, every push to main: build, GitHub Release + forge release, npm, Homebrew,
then the bump commit and tag. hanzo_identity guards the new file.
Two things found while proving it end to end:
- `dev login` on the Hanzo path died on a Cloudflare 502 page mid-poll —
"unexpected token response: <!DOCTYPE html>". A body that is not an OAuth
error is the edge, not the issuer; keep polling and let the device code's
lifetime end it.
- The troubleshooting link in agent_tool still pointed at just-every/code.
Merges the forge's 0faa6fe so both remotes share one history; the blob-size
gate it ported into hanzo.yml stays.
Co-authored-by: Hanzo Dev <[email protected]>
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 move to vendor/ left four references behind. check-codex-path-deps.sh
hard-failed every build ("Expected both code-rs/ and codex-rs/"), and the
auto-review scope excluded a prefix that now matches nothing — so all 5,624
vendored files were eligible for review context. That exclusion is vendor/
now, which covers whatever else we vendor later.
scripts/install/{install.sh,install.ps1,test_install_sh.py} arrived with the
v0.6.169 merge and nothing in this repo references them. install.sh fetches
releases.openai.com/codex, writes ~/.local/bin/codex, and uninstalls via
@openai/codex — an install path under our name that delivers a different
product.
The installer we actually publish lives in hanzoai/cli and consumes the
canonical <bin>-<os>-<arch>.tar.gz assets release.yml builds. Nothing here
fed it.
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]>
hanzoai/dev went public defaulting to someone else's cloud. Four things were
wrong, and all four now have a test that fails if they come back.
DEFAULT PROVIDER AND MODEL. built_in_model_providers() gains `hanzo` -- the
Hanzo Cloud at api.hanzo.ai/v1, Responses wire, bearer from HANZO_USER_KEY --
and it is the default. The default model is zen5-coder. This was not cosmetic:
the old default is not in the gateway catalog, so it 400s against our own
cloud. Measured, not assumed:
POST api.hanzo.ai/v1/responses model=gpt-5-codex -> 400 "model is not
available. Use GET /v1/models to list available models"
POST api.hanzo.ai/v1/responses model=zen5-coder -> 200, clean output
Our own CLI already documented the bug from the other side -- dev.rs says
"Name the model too -- codex's built-in default is not in the gateway catalog
and would 400" and passes `-c model=` on every launch to work around it. It
also asserts that on the native gateway NO model_provider override is needed,
which is only true once `hanzo` is the built-in default. It is now.
zen5-coder over enso because dev is a coding agent and because enso returns
system-prompt text on the Responses wire that dev actually speaks; zen5-coder
returns the answer. Model ids were read from GET /v1/models with a bearer, not
guessed. Other providers stay fully configurable -- this is the default, not
the only choice.
THE LOGIN COMMAND. Messages said `code login` / `codex login`. The real command
is `hanzo auth login` (`hanzo login` is not a command -- it is swallowed as an
AI task). It now lives once, as auth::LOGIN_COMMAND, so no message can drift
into naming a command that does not exist. References to this binary's own
subcommand became `dev login`.
A BINARY NAMED dev. HEAD built `code` and `codex` and nothing named `dev`, so a
release cut today would ship no `dev` -- and `hanzo code` launches a bare `dev`
off PATH, so every new install would break. `dev` is now the canonical bin,
declared first; `code` remains as an alias to the same program, never the
reverse. The CLI identifies as `dev` / "Hanzo Dev", not "OpenAI Codex".
OUR NAMESPACES. The pipeline published to @just-every/* on npm and pushed
formulae to just-every/homebrew-tap. Both of ours already exist and are already
populated at v0.6.91 -- @hanzo/dev plus all five @hanzo/dev-<target> packages,
and hanzoai/homebrew-tap's Formula/hanzo-dev.rb, which installs `dev` and
expects assets named dev-<triple>. Nothing here is squatted; this is our own
distribution, reclaimed. Assets are renamed to match the formula.
Two live supply-chain bugs fell out of that, both worse than a naming problem:
postinstall.js (runs on every npm install) and the tui auto-updater fetched
from a third party's releases -- the updater also told our users to
`npm install -g @just-every/code@latest`. Worse, a shadowed `isWSL` const put
the two fast paths in the temporal dead zone, so their catch blocks swallowed
the error and EVERY install fell through to that download: the five published
platform packages were never used, and the third-party fetch was not an edge
case but the only path that ran. Fixed and exercised in a sandbox across all
three paths. codex-cli/.pack/ -- a committed `npm pack` artifact CI
regenerates, and the reason the bad URL had two homes -- is now untracked.
DURABILITY, because upstream-merge.yml merges openai/codex every 30 minutes.
A one-time edit to a default is a suggestion that survives until the next
merge. Two mechanisms:
- .github/merge-policy.json prefer_ours_globs listed only codex-rs/** while
the workspace that SHIPS is code-rs/**, so it protected nothing that
ships. The identity-bearing code-rs files are now listed.
- code-rs/core/tests/hanzo_identity.rs asserts all four properties -- the
provider, a Zen default, a bin named dev, and no third-party publish
target. Upstream has no such file, so a merge cannot conflict with it or
carry the guard away with the thing it guards. Policy can be edited;
a red build cannot be ignored.
The gate is not decorative: it failed on the un-retargeted pipeline
("release.yml still references `@just-every/`") and went green only when the
pipeline was actually fixed.
Verified: cargo build --bin dev clean; hanzo_identity 4/4; code-core lib
332 passed, 1 failed -- git_info::test_collect_git_info_with_remote, which
fails identically on a clean origin/main checkout here because this machine
has a global [email protected]:.insteadof rewrite. Pre-existing and
environmental, not from this change.
$ dev exec "say OK" # fresh profile, no config
Hanzo Dev v0.0.0
model: zen5-coder
provider: hanzo
Co-authored-by: Hanzo Dev <[email protected]>
- Resolve merge conflict in codex-rs/Cargo.lock by adopting upstream version (outside prefer-ours globs).
- Add RUSTUP_HOME export in scripts/upstream-merge/verify.sh to avoid CI HOME permission issues during cargo check.
- Verified via scripts/upstream-merge/verify.sh: build-fast OK, API check OK, static guards OK, branding clean.
- Remove auto-branding worktree + commit and failing guard
- Keep perma-deleted guard; generate VERIFY_branding.log for guidance
- verify.sh: record branding findings as notice, never fail rc; write branding log
Rationale: branding should be a suggestion, not a gate. Code/maintainers can
apply suggested changes explicitly in follow-ups while upstream merge is gated
solely by build + API invariants.
- Prefer release-assets/* when present to compute sha256 for Homebrew formula.\n- Retry curl with backoff if local file missing; print warnings instead of failing.\n- Keep formula URLs pointing to GitHub Releases; add best-effort HEAD checks.\n- Eliminates 404-induced failures right after uploading assets.
- Add to and parse/write in config
- Apply per-server timeout to and initial
- Treat per-server errors as non-fatal; record and skip those servers
- Keep manager creation successful even if some servers time out
- Export so local smoke tool can exercise it
- Add (stdio JSON-RPC) and binary for manual validation
- Update TUI to set by default
This resolves GitHub issue #91 where a slow MCP server caused manager creation to time out and fail entirely.
- Add docs/fork-enhancements.md (initial list; instruct agent to scan repo for more)
- Inject the overview into the merge prompt
- Generalize verify guards to handler↔tool parity by family (browser_*, agent_*, web_fetch), and keep UA/version check
Prevents silent loss of fork features and gives the agent richer context.
- Keep ours for (resume picker not reintroduced)
- Initially took upstream for core, but reverted to ours to maintain API compatibility and pass build
- Adopted upstream elsewhere where non-conflicting
- Guard: keep codex-core re-exports and models alias intact
- Verify script: disable sccache outside GHA to allow local verify
- Fix: remove unused imports in theme selection view (warnings-as-failure policy)
Build: scripts/upstream-merge/verify.sh => build_fast=ok api_check=ok
Use one CARGO_HOME/CARGO_TARGET_DIR across agent and verify. Remove redundant actions/cache steps; rely on Swatinem/rust-cache and sccache GHA backend for incremental builds. verify.sh now respects env and uses KEEP_ENV=1 so builds share caches.