4354 Commits
Author SHA1 Message Date
zeekay 0f0f83ce3a hanzo-kai: the tree copy makes a symlink on Windows too
`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.
v0.7.0
2026-10-15 09:04:15 -07:00
zeekay a8af775a94 crates: the four libraries are not published
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`.
2026-10-15 08:04:11 -07:00
zeekay 7ee3d3d35c bazel goes: the root's copies of upstream's Bazel build
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.
2026-10-15 07:43:53 -07:00
zeekay 0e628dc574 0.7.0
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.
2026-10-15 07:37:45 -07:00
zeekay 8cd3a7d268 upstream: hanzoai/codex at 3ee47c105, the delta as commits; the build-time edits go
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.
2026-10-15 07:16:51 -07:00
zeekay c0fabbb775 upstream/code goes: just-every/code is reference, never a build input
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.
2026-10-15 07:16:24 -07:00
zeekay ee4089c28a release: the version is assigned by hand, never minted by the pipeline
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.
2026-10-15 06:06:49 -07:00
hanzo-dev 6397df24cf kai: an answer that does not read or apply is said again once; an escalated attempt with no edit goes to the generator once
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.
2026-10-14 20:20:21 -07:00
hanzo-dev e6a813c380 kai: edit::parse says which miss it is; spelling and near
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.
2026-10-14 20:19:57 -07:00
hanzo-dev 3bbcdba60b kai: keep every model call with its finish reason and usage, ask for an edit as a strict JSON schema
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.
2026-10-14 20:19:31 -07:00
zeekay 148ab1636d chore: update Cargo.lock 2026-10-14 18:47:25 -07:00
zeekay 799e637d9a fix(kai): resolve escalation model reasoning overflow and markdown edit parsing 2026-10-14 18:42:07 -07:00
zeekay 7926da8a56 feat(kai): implement local Kai acceleration v2 with circuit breaker, zero-inference fast path, and recall-preserving prefilter 2026-10-14 18:32:14 -07:00
zeekay edc6fa59e9 fix flow: Kai's turn decision acts, an escalation model, a wider test before done, kept model calls
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.
2026-10-14 17:20:36 -07:00
zeekay 2b05bae4d0 fix flow: progress that is real, a process group that dies, a search that fits its cap
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.
2026-10-14 15:49:51 -07:00
zeekay 501a220471 fix flow: Kai as controller of a ledgered loop, a search of candidate edits, tgrep evidence, recover
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.
2026-10-14 14:54:05 -07:00
zeekay 8a296d976c WIP: dev-fast, stopped by the usage limit mid-work; not built or tested 2026-10-14 13:16:59 -07:00
zeekayandHanzo Dev 76c70b8db1 chore(release): 0.6.122 [skip ci]
Co-authored-by: Hanzo Dev <[email protected]>
2026-10-11 19:44:16 +00:00
zeekay 903ba0c1de feat(loop): add deterministic context compaction to Controller and Kai thread v0.6.122 2026-10-11 10:19:36 -07:00
zeekayandHanzo Dev 5d8652d06d fix(dev): review and memory run on models the provider serves
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]>
2026-10-09 17:06:36 -07:00
zeekayandHanzo Dev f70ffd1e80 chore(release): 0.6.119 [skip ci]
Co-authored-by: Hanzo Dev <[email protected]>
2026-10-09 23:17:34 +00:00
zeekay e99689fa1a tui: monochrome, and one line under the input v0.6.120 2026-10-09 15:01:34 -07:00
zeekay 8635dbbe4b fix(dev): a run takes the HANZO_API_KEY its host hands it, so a cloud sandbox signs in with no CLI v0.6.119 2026-10-09 06:17:45 -07:00
zeekay 84a1d72fa6 fix(release): the version reaches the binary crate alone, so a release reuses every crate beneath it 2026-10-09 05:41:34 -07:00
zeekay 2fa7f5e3c4 fix(release): carry compiled crates between runs through sccache and the org's store 2026-10-09 05:41:34 -07:00
zeekayandHanzo Dev b32b3122d2 chore(release): 0.6.118 [skip ci]
Co-authored-by: Hanzo Dev <[email protected]>
2026-10-09 12:28:08 +00:00
zeekay 16540ee6cf fix(release): two compile jobs per build, so five builds fit one shared node's memory
Claude-Session: https://claude.ai/code/session_01LCxkTkYTJrFqZ27vDSsn6Y
v0.6.118
2026-10-08 20:14:12 -07:00
zeekay f70e6dbff8 fix(release): build without LTO, whose link ran a shared runner node out of memory
Claude-Session: https://claude.ai/code/session_01LCxkTkYTJrFqZ27vDSsn6Y
2026-10-08 18:25:27 -07:00
zeekay b4ea5a9324 fix(dev): a bare dev starts in-process, reads only .hanzo, and defaults to Hanzo
Claude-Session: https://claude.ai/code/session_01LCxkTkYTJrFqZ27vDSsn6Y
2026-10-08 11:36:40 -07:00
zeekayandHanzo Dev 8a57b6b5b9 chore(release): 0.6.115 [skip ci]
Co-authored-by: Hanzo Dev <[email protected]>
2026-10-08 08:23:40 +00:00
zeekay 4a20f8e6f9 fix(release): the build limit sits at the ceiling, a crowded cluster is slow, not failed v0.6.115 2026-10-07 20:51:33 -07:00
zeekay 3b5336bcb2 fix(dev): never check another product's releases for an update 2026-10-07 17:05:03 -07:00
zeekay 2dde1d95ad feat(dev): the picker lists Hanzo models, the name is a rule in brand.json, one default 2026-10-07 16:24:18 -07:00
zeekay 63a0bb114d feat(dev): Enso by default, /login /auth /model <name>, Dev in every string, codex 11da6b9 2026-10-07 16:04:54 -07:00
zeekay 2cdddb0b00 refactor: the wasm loop, its Go host and wasm2go move to hanzo-inc/dev
Claude-Session: https://claude.ai/code/session_01SVaQNFaAjhDxthpxasGah5
2026-10-07 13:49:35 -07:00
zeekay 381ba15a05 fix(cli): exec labels the model's reply dev, not the engine
Claude-Session: https://claude.ai/code/session_01SVaQNFaAjhDxthpxasGah5
2026-10-07 13:39:53 -07:00
zeekay 3e1815afbe fix(ci): lock models-manager's hanzo-config edge, rebuild dev.wasm to match, build by default
Claude-Session: https://claude.ai/code/session_01SVaQNFaAjhDxthpxasGah5
2026-10-07 13:21:38 -07:00
zeekay 82cf6d3b4c chore: lockfile update for codex-exec 2026-10-07 11:41:47 -07:00
zeekay b1b267bb92 fix: adapt hanzo-kai, upstream patches, and token auth to codex 0e15206 2026-10-07 11:34:40 -07:00
zeekay e98ed461ae chore: sync upstream to codex 0e15206 and code 41f66ca
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
2026-10-07 11:33:56 -07:00
zeekayandHanzo Dev 2a4577776b The model manager reads the Hanzo catalog, recorded in the lock
Co-authored-by: Hanzo Dev <[email protected]>
2026-10-07 10:49:22 -07:00
zeekayandHanzo Dev 403b906d17 A Hanzo sign-in refreshes itself, Hanzo models are known, and no stray call or link is left
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]>
2026-10-07 10:15:19 -07:00
zeekayandHanzo Dev 191966e9e0 chore(release): 0.6.108 [skip ci]
Co-authored-by: Hanzo Dev <[email protected]>
2026-09-27 14:07:44 +00:00
zeekay d8da5353ab The npm launcher publishes from npm/, its catalog entries resolved, and a rerun skips what npm already holds.
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
v0.6.108
2026-09-27 06:25:35 -07:00
zeekay 137beb1075 The release stamps the version it computed over the one the tree names.
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
v0.6.107
2026-09-27 05:41:04 -07:00
zeekay 8ca9769d48 Release targets build together, since a job held back by max-parallel outlives its runner.
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
2026-09-27 04:46:11 -07:00
zeekay 9ebef1cc94 The release runs on GitHub again, one target at a time and without root.
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
2026-09-27 03:57:32 -07:00
zeekay a7126cbd19 Kai reaches Dev over the Decisions API, so Dev builds and installs from public sources alone.
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
2026-09-27 03:57:24 -07:00
zeekay ff64e7d729 Kai decides in the dev loop, and dev flow runs Decision Programs whose steps are tools, Kai or Zen.
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
2026-09-26 12:59:11 -07:00
zeekayandHanzo Dev 18d32febe4 fix(go): an answer the host cannot read ends the session
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]>
2026-09-19 09:15:48 -07:00