Files
dev/LLM.md
T

4.7 KiB

Hanzo Dev

The dev command: a coding agent for the terminal.

Shape

Hanzo owns the front door; upstream owns the engines.

  • crates/hanzo-dev is the binary. Its main.rs is the entire command surface, and every subcommand hands off to a library. Nothing is generated and no upstream source is compiled through an include!.
  • crates/hanzo-config picks the provider and the product home. crates/hanzo-tui holds the strings and colors that make the interface ours.
  • crates/hanzo-upstream is a detached workspace, because the root workspace cannot resolve until it has run. make drives it; it is never imported.

The loop the cloud drives

The reasoning half of dev as a wasm module, with its Go host and the wasm2go build, lives in hanzo-inc/dev. Nothing here depends on it.

Upstream

upstream/codex and upstream/code are submodules. The gitlink is the pin — no lockfile of hashes sits beside it. Crates are consumed straight from the checkout by ordinary path dependency.

patches/upstream.json carries the whole Hanzo delta: anchored substitutions that make prepare applies to the checkout in place. git -C upstream/codex status shows them, and that is the honest picture — the checkout is a build input we own, not a pristine mirror. make reset returns it.

The product's name is a rule, not edits. patches/brand.json says where make prepare turns the word upstream calls itself by into ours, in the string literals of non-test code, and what it leaves alone: a file name, a package, a wire value. A rewording upstream cannot break it; an anchored edit can.

Every edit carries an exact match count. When upstream moves the ground under one, preparation fails and names the file rather than branding the wrong line. That is the signal to re-anchor, and it is why the delta is anchored strings rather than a diff.

Two of the edits are not branding: they publish mcp_cmd, plugin_cmd and doctor from upstream's library instead of leaving them in its binary. Those belong upstream as a pull request; landing them there shrinks this file.

Never edit upstream by hand

Changes go in a hanzo-* crate, or in patches/upstream.json when upstream hard-codes something that must be ours. A hand edit inside upstream/ is lost at the next make bump.

The Code fork

upstream/code is reference, not a build input. Its crates depend on its own fork of codex-core, so importing them would link two cores into one binary. Its additions worth having — Auto Drive, the browser bridge — get rebuilt as hanzo-* crates against codex-core. migration/code-v1.patch records what v1 carried, including the defects it was already carrying; see migration/STATUS.md before porting anything from it.

Working here

make build          the dev binary
make test           the Hanzo suite
make test-upstream  the upstream suite against the pinned checkout
make bump           move the submodules forward
make help           everything

make build is the check that must pass. Fix warnings as well as errors.

House rules

  • Hanzo service APIs use https://api.hanzo.ai/v1/ exclusively.
  • Keep the upstream interaction model and animation; the branding is ours.
  • Keep Linux, macOS, and Windows working.
  • Upstream project names appear only in NOTICE — never in the README, the repository description, the CLI, or the interface.

Runtime & Model Fixes (2026-10-07)

  • Model Metadata (enso-auto): Native ModelInfo entry added to upstream/codex/codex-rs/models-manager/src/model_info.rs with 262k context window, reasoning effort presets, search tool support, and used_fallback_model_metadata: false, eliminating "Unknown model enso-auto... fallback metadata" warning.
  • Sandbox Permissions Inference: In upstream/codex/codex-rs/core/src/tools/handlers/mod.rs, resolve_sandbox_permissions now infers SandboxPermissions::RequireEscalated when justification.is_some() && sandbox_permissions.is_none(), preventing malformed shell call errors under approval_policy = "never" / sandbox_mode = "danger-full-access".
  • ChatGPT Legacy Plugins 401: In upstream/codex/codex-rs/core-plugins/src/remote_legacy.rs and manager.rs, requests to chatgpt.com/backend-api/plugins/featured are skipped unless authenticated against ChatGPT backend (auth.uses_codex_backend()).
  • Auth Symlink Guarantee: hanzo-config::ensure_parent_and_symlink ensures ~/.hanzo/auth.json is initialized with {} if absent before symlinking, preventing dangling ~/.hanzo/dev/auth.json.
  • Token Refresh Command: DEFAULT_CONFIG includes dynamic token refresh configuration [model_providers.hanzo.auth] command = "hanzo auth token", refresh_interval_ms = 600000 to prevent 60-minute JWT expiration mid-session.