The first state's first call is begun as soon as the state is ranked, against its revision. The
search settling the task, or a kept step moving the state, cancels it; a cancelled call closes its
stream and leaves an estimated line in the spend file. Past its cap the search goes on while that
call has not answered, to 8 s, and a visible test too slow for the cap is narrowed to the failing
tests it names instead of the search being skipped. The tests around the failing ones run beside
the visible test, and what failed among them before any edit is read only when they fail after
it. A test run in the tree leaves no file git neither tracks nor ignores, and Hypothesis keeps its
examples in the run's own temporary directory.
Model-free on 60 dev-split tasks on evo, A/B interleaved: search-settled tasks 1.74x faster (95%
1.64-1.85, 13 of 13), solves 13 to 19: five exact pyrsistent fixes no longer fail on the
.hypothesis files the runs wrote, and a lark task with an 18 s test file is searched.
hanzoai/codex e7a4d438: the update check reads hanzoai/dev's latest release and
offers the installer that put Dev there (@hanzo/dev by npm, bun or pnpm, the
hanzoai/tap/hanzo-dev formula, hanzo.sh otherwise), and the empty-state
animation draws the Hanzo mark. 6fd3f345: the fork's doctor, daemon and composer
snapshots say Dev. install-context now reads its npm marker from `hanzo`, which
is the lock's one new edge.
hanzoai/codex names nothing outside its tree now (d1d710452): Dev's names,
defaults, model catalog, `/model <name>` match, controller interface and
version live in its `hanzo` crate, and Dev's crates depend on that, never
the reverse. hanzo-loop moves there whole; hanzo-tui keeps only the Hanzo
account; hanzo-config reads API_BASE, DEFAULT_MODEL and is_hanzo from it.
hanzo-dev's main registers what Dev adds before anything starts:
`codex_app_server::register(hanzo_kai::install)` puts Kai on every thread,
and `codex_tui::register(Account { login, logout, show })` puts the Hanzo
CLI's sign-in behind /login, /logout, /auth and /status. launch.rs holds
that /login is offered, which it is only when an account is registered.
make test-upstream runs locked against the fork's own lock.
Nothing in release.yml, hanzo.yml, the Makefile or scripts/ names any of
them: the zsh release script and its dotslash config (upstream dropped the
zsh fork), verify_cargo_workspace_manifests.py and
verify_tui_core_boundary.py (checks of a codex-rs this repository does not
hold), the Linux, macOS and Windows code-signing actions and the macOS
notarizing scripts (upstream's identities), and upstream's issue templates,
which asked about the Codex app and CLI.
`copy` reached for std::os::unix::fs::symlink unguarded, so the windows-amd64 build of v0.7.0 failed at
hanzo-kai while the four other targets built. Each platform's symlink call sits under its cfg; the
other two unix-only sites in the Hanzo crates were already gated at the function and module.
hanzo-config, hanzo-kai, hanzo-loop and hanzo-tui keep 0.0.0, and each
says why beside it: upstream crates depend on them, so a version that
moved would recompile everything above them. None is a crate anyone
installs from a registry, so `publish = false`.
Nothing here runs Bazel: make, hanzo.yml and release.yml build with cargo.
The root carried upstream's own Bazel setup anyway: MODULE.bazel (which
already named a patch that was not here) and its lock, BUILD.bazel,
.bazelrc, .bazelversion, .bazelignore, defs.bzl, rbe.bzl, bazel/, the test
launcher templates, third_party's BUILD files and V8 wiring (scripts/v8.sh
reads the fork's), the buildifier pin and format.py's Starlark group, the
Bazel CI actions and scripts under .github (setup-rusty-v8-musl read its V8
version through one of them), and argument-comment-lint, whose runs go
through a Bazel aspect over codex-rs, which is the fork's. hanzo-dev's
cargo-shear note named Bazel-only benches that do not exist.
The version, by hand: the root Cargo.toml's [workspace.package] (which
hanzo-dev alone takes), npm/package.json and its platform packages, and
the lock. The changelog says what 0.7.0 carries: openai/codex at
3ee47c105 through hanzoai/codex, the delta as commits there, Kai's kept
calls and repaired answers, and versions assigned by hand.
upstream/codex is now hanzoai/codex, whose main is openai/codex with
Hanzo's commits on it, and dev builds that checkout as committed: no
`make prepare`, nothing rewritten, `git -C upstream/codex status` empty
after a build and a test run. A bump is `git merge upstream/main` on the
fork's main, with conflicts in git, then the gitlink here.
openai/codex moves from 11da6b9e to 3ee47c105 (288 commits). Of the 106
anchored edits one had lost its ground, the --sandbox-state-json help that
upstream reworded, and was re-anchored before the delta became commits on
the fork: hanzo (Dev's crates in its workspace), tui, cli, config, core,
words, brand (the name rule's 227 literals) and version (the version
rule's 126 reads). The edit that set upstream's workspace version to
0.7.0-dev.1 is dropped: no upstream code reads its own version any more.
None of the anchors touched the zsh fork, shell-escalation or gateway_auth
code upstream removed or renamed, and the Hanzo crates built against the
moved APIs unchanged.
The version: hanzo-version moves into the fork, hanzo-dev hands it its own
CARGO_PKG_VERSION at startup, and DEV_VERSION is gone. The root
[workspace.package] version is the release's, and release.yml holds the
tag to it as well as to npm/package.json. Dev's libraries stay 0.0.0,
since upstream crates depend on them, so a release still recompiles
hanzo-dev alone. cli.rs fails on any upstream read of its own version.
Gone: patches/ (upstream.json, brand.json, and the Bazel patches only the
root MODULE.bazel names, which no build here runs), crates/hanzo-upstream
and crates/hanzo-version. The V8 fetch for `make test-upstream` is
scripts/v8.sh; `make bump` prints the merge steps; `make reset` goes. The
root Cargo.toml mirrors the fork's workspace dependencies: shell-escalation
and mxc-sdk out, the split mxc crates, gix 0.89, rmcp 3.5.1 and rustls
0.23.46 in.
Nothing built from it: its crates carry their own codex-core, so linking
them beside ours would put two cores in one binary. Its clone lives at
~/work/just-every/code; what was ported from it is recorded in migration/.
The submodule sat at 41f66ca5d, their main.
A release runs from a tag vX.Y.Z and ships that version: the tag must equal npm/package.json's version
(checked twice, in the version job and before npm publish), a version already published is refused, and
nothing is committed, tagged or bumped from CI. Until now every push to main took the next patch above
whatever was published and landed a chore(release) commit; the owner's rule is manual semver everywhere.
The Homebrew formula is generated at publish and pushed to the tap alone, so its in-tree copy goes.
npm/package.json: 0.6.185, the first version assigned so.
Each call is an action in the ledger (stage first, repair or fallback) and the trace line
lists every call. The generator is never an Anthropic model. An answer of no edits is not
said again. The edit is tested as before.
No edits, JSON that does not read or is no edit, and no JSON were all 'holds no JSON'.
spelling() tells a refusal of how an answer is written from one of what it says, and
near() shows the file's own lines where an edit's old text was meant to stand.
A call that came back without text (finish length, 3,072 of 3,072 completion tokens
reasoning) was neither kept nor written to the spend file; now every call that reached
the model is kept with its request, finish reason and usage (reasoning tokens apart),
a call without text or ended by the server with an error is kept with its error, billed
and asked again. At Hanzo's API the answer is a strict json_schema with at least one
edit; the generator's answer room is 2,048 where 512 cut off its thinking aloud.
fix.turn@1 answering escalate, two failed attempts, or recover finding
nothing changed hands the next attempt to generate.escalate (openai/gpt-6-sol
at Hanzo's API, never an Anthropic model); the ledger records the decision
selected and applied and the model that wrote each edit. A run that passes
the failing command is not done until the pytest directory around it shows no
new failure, capped at 20 s. Every model call is kept by the hash of its
request and a repeat is answered from there, marked cached.
A candidate that leaves the code unreadable or adds tests that cannot run is no
step. kill -9 -PGID without -- killed nothing, so a looping candidate kept its
pipe and hung the run: every test the flow starts is now killed with its
children, and a search stops its running tests at the cap. A test the runner
says takes longer than the cap holds is not searched. A revert returns to the
base revision, one search a state. The model is asked for one JSON object, with
a timeout a call, and is told which edits were already tried.
dev flow fix reads the failing output against the tree (locate: the gateway's
learned ranker, features held to its own by a test), puts the functions tgrep
finds spelling the failure's messages into the ranking, and lets Kai choose the
site, the action and the effort in one request, or decides alone when the
ranking is sure. The action search tries generic token transforms at the best
sites against the visible test, eight at once; a candidate that leaves fewer
tests failing is kept as a step. Else a model writes one edit (applied by text,
never a test file), the test runs, Kai reads a failed run in one request, and
recover fingerprints the failure and never replays a strategy on it.
Every action is a ledger line with a stable id, its revision, preconditions,
authorization, source and the states it passed through; credentials are
redacted. Kai's transport is a trait, health is per program.
Cargo.lock is not committed: hanzo-trigram is read from hanzoai/mcp commit
e9e6096, which is not pushed yet.
On api.hanzo.ai, automatic approval review and memory extraction and
consolidation ask for enso-auto, not OpenAI's ids. Off OpenAI, the reviewer
counts a model as served only when the catalog lists it: the bundled OpenAI
entries ride along unlisted for lookups, so codex-auto-review looked served on
every provider and a LAN engine was reviewed by a model it does not have. Now
it falls back to the model the run is on.
Co-authored-by: Hanzo Dev <[email protected]>
Move both submodules to current main and bring the owned delta with them.
- patches: the session title is one literal in codex_title now, so it is
anchored there and the status-card edit, which that title replaced, goes;
get_tooltip takes the keymap; the cyber-access flag names a provider in
its help; mcp_login joins the modules the library publishes.
- Cargo.toml: workspace dependencies, profiles and patches track upstream's,
as they did at the last pin, and Cargo.lock follows.
- tests: the pty spawn takes ChildFds; the feature round trip asks for an
experimental feature instead of naming one upstream has since deprecated.
Claude-Session: https://claude.ai/code/session_01SVaQNFaAjhDxthpxasGah5
The Hanzo provider asks `dev token` for its credential every ten minutes
instead of reading HANZO_USER_KEY once at startup, so a session outlives the
hour a sign-in token lives. A profile still on the old startup-only provider is
moved to it; one the user changed is left alone. `dev token` prefers an API
key, then a fresh token from the Hanzo CLI, to a sign-in token inherited from
whatever launched the agent.
The chat models api.hanzo.ai serves carry their real window and inputs, so
enso-auto and the rest no longer run on fallback metadata.
A justification without sandbox_permissions runs at the default permissions
instead of failing the shell call. Featured plugins are asked for only with a
ChatGPT sign-in, which is the only caller that endpoint answers. The profile
links to the shared credential only when it exists, and a sign-in links first
so it writes the shared one.
Co-authored-by: Hanzo Dev <[email protected]>
v0.6.107 published its GitHub release and all five platform packages,
then stopped at `cd codex-cli`: the launcher moved to npm/ on
2026-09-07 and the release never followed it. Its dependencies are pnpm
catalog entries, which npm would publish as the literal `catalog:` that
no installer resolves, so each becomes the version pnpm-workspace.yaml
gives it. npm refuses a version twice, so every publish first asks
whether that version is already there.
Claude-Session: https://claude.ai/code/session_018Gt5TvrE2rxXuZikWSauv3