Files
Hanzo Dev 56a87c061a install: download the binary, verify it, done — no toolchain in between
`curl hanzo.sh | bash` installed uv from astral.sh and then `uv tool install`ed
hanzo, hanzo-mcp, hanzo-agents and hanzo-node. Every one of those is a native
Rust binary that we already publish, cross-compiled for five targets with a
sha256 beside each asset. So the installer was fetching a Python toolchain in
order to deliver programs that are not Python, and resolving `hanzo` from PyPI —
a different program that happens to share the name.

It now downloads one prebuilt binary per tool, verifies its sha256, and puts it
on PATH. That is the whole design, and it is smaller than what it replaces:
-349 lines net, and public/install.sh drops from 669 lines to 314.

The machinery for the right thing was already in the file and unreachable:
install_release() was defined and had ZERO call sites, while every bundle routed
through install_tool() to uv. Wiring it up was the tempting minimal fix and it is
the wrong one — install_release() verified nothing, so it would have traded a
wrong binary for an unverified one. It is deleted. Downloading lives in
hanzoai/cli/install.sh, which already verifies, and which this drives once per
tool via HANZO_INSTALL_{REPO,BIN,ALIAS}. One implementation, two callers.

What ships, verified by installing each from a clean PATH and empty HOME:
  hanzo      hanzoai/cli  v1.9.18       + hanzo-node, one build, symlinked
  mcp        hanzoai/mcp  rust-v1.1.15  + hanzo-mcp, one build, symlinked

What does not, and is now NAMED in the output instead of quietly swapped for
something else: dev and node (private repos — anonymous fetch is a 404 — and no
per-asset checksums), desktop (private, and linux-amd64 only), bot (not a native
binary). `dev` is the costly one: it is what `hanzo code` runs by default, so a
public install yields a CLI that cannot run its own headline command's default
backend. Better said at install time than discovered at first use.

POSIX sh now, which fixes a second, independent break. The page published
`| bash` and llms.txt published `| sh` while the script was bash-only, so the
`sh` half died on Debian at `set: Illegal option -o pipefail` before downloading
anything — and every agent reading llms.txt copies the `sh` form. Rather than
pick a winner and leave the other broken, both work; the polyglot already
declares #!/bin/sh, so this makes that shebang honest. The Dockerfile now asserts
under dash as well as bash, because a bash-only assert is precisely what let this
ship.

Also corrected: the installer told users to run `hanzo login`, which is not a
command — it is `hanzo auth login`, and `hanzo login` is swallowed as an AI task.
llms.txt advertised `hanzo deploy` and `hanzo node start --chain ethereum`;
neither exists. Its examples are now commands present in the shipped binary.

The bundle vocabulary is gone: naming nothing installs everything installable,
naming a tool installs that tool. /python and /rust selected a language for
programs that have exactly one implementation each, and both were already broken
(they piped a 404 into bash). /agents is `hanzo agent` in the CLI. The remaining
shims are routing only, so the installer stays the single place that knows what
exists. scripts/polyglot.sh, an unwired duplicate of the .js builder, is deleted.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-01 11:29:07 -07:00

8 lines
254 B
Bash

#!/bin/sh
# Hanzo dev.
# curl -fsSL hanzo.sh/dev | sh
#
# Routing only. The installer is the one place that knows which tools ship as a
# native binary and what to say about the ones that do not.
exec sh -c "$(curl -fsSL https://hanzo.sh)" -- dev "$@"