`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
The workspace says 0.7.0-dev.1 while the release computes the next patch
above what is published, so the 0.6.107 build answered dev 0.7.0-dev.1
and publish refused it. The build job now replaces the workspace
version in every manifest that pins it, in the upstream edit that gives
upstream's crates the same version, and in Cargo.lock, so --locked
holds; built that way on ra, dev --version and dev doctor both say
0.6.107.
Claude-Session: https://claude.ai/code/session_018Gt5TvrE2rxXuZikWSauv3
The platform starts one runner per job when the job is queued. With
max-parallel 1, linux-amd64 built in 22 minutes and the four targets
queued behind it never got a runner, so the release sat with one
platform's assets.
Claude-Session: https://claude.ai/code/session_018Gt5TvrE2rxXuZikWSauv3
Since 2026-09-08 release.yml sat in .hanzo/workflows, which GitHub does
not read, and the forge runs nothing for this mirrored repository: no
push to main released anything, and a draft v0.6.107 holds no assets.
It moves to .github/workflows.
The runner there is a sandbox with no root, so no step installs a
package: the build and publish jobs check for what they need (cc, make
and perl included, for the vendored OpenSSL) and name what is missing, and the Windows build takes clang-cl, lld-link and
llvm-lib from a pinned LLVM 21.1.2 release instead of apt. The five
targets build one at a time, since the hosts serve other work. The
forge mirrors this repository, tags included, so the step that pushed
the release to it, which could only fail with a GitHub token, goes.
Claude-Session: https://claude.ai/code/session_018Gt5TvrE2rxXuZikWSauv3
hanzo-kai linked hanzoai/decision's control and program crates by git.
That repository is private: the public build, CI, and every cargo install
of dev failed to fetch it. Kai is now a client of POST /v1/decisions at
api.hanzo.ai, signed with the Hanzo credential Dev already sends; nothing
of hanzoai/decision is linked, .cargo/config.toml goes, and Cargo.lock
loses 89 packages and every private source.
The programs Dev asks (tools.select, router.model, reasoning.budget,
context.select, agent.command-risk, agent.progress, agent.complete, and
the fix flow's fix.pick and fix.next) ship in crates/hanzo-kai/programs
as typed questions with their thresholds, verdict rules and calibration
pins. The gate that reads the answers is Dev's own: a noul holds at its
threshold, a choice or score is accepted at its certainty, a verdict
rule joins the policy on allow < ask < deny only when enforced, and an
answer under another calibration runs in shadow.
When Kai does not answer (refused, timed out, 401, 404, 5xx, or no
state of the decision answered) the decision fails at once and Kai is
down for 60 s: no request is made in that window, the loop does exactly
what it does without Kai, one line goes to the log and no trace line is
written. Only a decision asked after the failure brings Kai back. A
decision's states are asked in parallel; tier and budget together. The
tool shortlist is decided again when the tools on offer change, since an
MCP server that finishes starting mid-turn adds its tools.
dev flow is now dev flow fix, a fixed pipeline rather than a Decision
Program run by the private executor: retrieval, Kai's pick, Zen's diff,
the tests, Kai's next. --control rule, or Kai not answering, leaves the
tests and the budget to decide, and the report says so once. An attempt
whose patch no longer reverses ends the flow instead of retrying over it.
Tests serve the Decisions API and chat completions from wiremock: Kai
on (tools shortlisted, tier and effort hinted, verdict tightened, one
trace line per decision with its distributions), Kai answering 404,
Kai unreachable, Kai answering with a page that is not the API, tools
arriving mid-turn, and an answer under another calibration.
Claude-Session: https://claude.ai/code/session_018Gt5TvrE2rxXuZikWSauv3
hanzo-loop is the contract the loop applies: a tool shortlist per step, a
command verdict joined with the policy on allow < ask < deny, and routing
hints on the turn metadata. hanzo-kai links hanzoai/decision's control and
program at ec8207d: one controller per thread answers those three through
seven anchored upstream edits, and extension contributors feed it context,
progress and completion. kai.toml turns it on, every operation in shadow by
default. Each decision is one trace line in the shape Enso's control writes.
dev flow runs a Decision Program over the repository. The shipped fix flow
retrieves candidate files, Kai picks one, Zen writes a diff, the tests run,
and Kai says done, retry or escalate within what the tests and the budget
permit. go/dev.wasm is rebuilt because Cargo.toml, Cargo.lock and the
Makefile are among its recorded inputs.
Claude-Session: https://claude.ai/code/session_018Gt5TvrE2rxXuZikWSauv3
The core has taken the event before Step decodes its answer. Step answered a
decode that failed with ErrMalformed, which says nothing changed, and with the
actions it had read so far; the session ran on ahead of its host, and the same
turn stepped again was a redelivery that asked for nothing, so its ask was
lost. Now an answer that is not read ends the session as an ended context
does: ErrHandle, then ErrHandle for every call, and the snapshot from before
the event carries it on. A Step that answers an error answers no actions. A
stand-in core that answers with a member Action lacks, and the real core with
an answer the host refuses, each fail on the old code. The memory test drops
the host refusal it looped on, since one now ends the session.
Nothing noticed if Session.Close stopped closing the instance: the closed
session test now calls the old instance and requires it to fail.
Docs: a null member that is not an Option reads as its zero value, which serde
refuses; a session that trapped answers ErrPoison after its Core closes; and
the 64 MiB cap holds about 14 MiB of conversation and 8 MiB in one event. An
ask traps at 15 MiB of results, a Snapshot at 16, a lone prompt at 9, and a
restored session meets the same wall.
Co-authored-by: Hanzo Dev <[email protected]>