Search results and link previews for hanzo.sh read 'CLI, MCP, Agents, Dev tools —
in Python, Rust, or JavaScript', which is the model this change set removed: there
is one implementation of each tool and one way to install it. The description now
says what the command does.
Dropped the the scaffold generator's CDN script tag left over from the scaffold. It is a
third-party module on the page whose whole job is to hand people a shell command,
the CSP already blocked it from loading, and nothing here uses it — so it was
pure supply-chain surface on the most security-sensitive page we serve.
With this, 'python' no longer appears anywhere in the bytes hanzo.sh returns.
Co-authored-by: Hanzo Dev <[email protected]>
The previous commit's README claimed the workflow publishes on every push to
main. It does not, on this repo: four consecutive pushes created zero runs while
pushed_at advanced each time, and workflow_dispatch on the same file works every
time. Cause not established — Actions enabled, workflow active, file on main
with branches: [main], no rulesets, public repo, and the canonical remote instead
of the redirect made no difference.
`on: push` stays, because it is correct and costs nothing the day this clears.
What changes is the claim: dispatch is the path that works, a merge is not a
deploy until then, and the check is one curl. Shipping a doc that says deploys
are automatic when they are not is how the next person merges a fix and walks
away — which is the failure this whole change set exists to end.
Evidence and the ruled-out causes are in LLM.md so nobody re-derives them.
Co-authored-by: Hanzo Dev <[email protected]>
Its comment told the next person to run `pnpm build && npx wrangler@3 deploy`,
which is exactly how the live host ended up months behind main. Deploying is CI
now, and CI is the thing that checks the live bytes afterwards. The local command
is still there for a break-glass, with the consequence stated.
Co-authored-by: Hanzo Dev <[email protected]>
It documented a generated starter — an /improve project URL, 'Share -> Publish'
to deploy, and `npm i && npm run dev` for a repo that builds with pnpm and a
frozen lockfile. None of it described hanzo.sh, and the deploy section pointed
somewhere that has never deployed this host.
It now says what the one command installs, that the served file is a polyglot,
that downloading belongs to hanzoai/cli/install.sh and should stay there, and how
to exercise an installer change under both published shells before deploying.
Co-authored-by: Hanzo Dev <[email protected]>
The polyglot is one file that is both the installer and the landing page. The
shell half stopped installing uv; the HTML half still told everyone it does —
"Requires bash. Installs uv if missing.", a four-up grid offering `pip install
hanzo`, `uvx hanzo`, `cargo install hanzo-dev` and `npm i -g @hanzoai/cli`, and
an "Installation Bundles" section selecting python/rust/full. A fix that only
lands in the bytes a machine executes, and not in the bytes a person reads, has
fixed half the problem and left the documentation to contradict the product.
The page now says what the installer does. One command; the alternatives grid is
gone, because offering four package managers for a program with exactly one
implementation is the language-choice model this change exists to remove.
The per-language package grid (Python / Rust / JavaScript, listing hanzo-agents,
hanzo-dev, @hanzoai/mcp and others) is replaced by what is actually installed:
`hanzo` and `hanzo-mcp`, each with its second name and a link to the repo that
builds it. Below it, in the open, the four tools that are NOT installed and why —
the same list the installer prints, so the page and the terminal agree.
Corrected alongside: "After install" advertised `hanzo dev`, which needs the dev
binary that is not public, so the first suggested command would have failed; it
now shows `hanzo code`. The subtitle promised agents and SDKs that this installer
does not install.
Lint was already failing on 5 pre-existing errors in src/components/ui and
tailwind.config.ts; unchanged by this, and not fixed here.
Co-authored-by: Hanzo Dev <[email protected]>
hanzo.sh is a Cloudflare assets Worker that was published by hand. That is the
reason the installer fix in e300d78 never reached anyone: main was correct for
weeks while `curl hanzo.sh | bash` kept handing out a copy that predated it. The
repo and the bytes users get were two different states, and nothing in CI had an
opinion about the difference.
So the deploy runs on every push to main, and — the part that matters — it does
not pass because wrangler exited 0. It re-fetches https://hanzo.sh and compares
its md5 to the file just built, retrying while the edge revalidates, and fails
the job if they differ. A green deploy over a stale site is the failure being
fixed here; a deploy step that cannot detect it would reproduce it.
It also re-asserts the polyglot against the LIVE response, not just the artifact:
parses under dash, and carries no astral.sh or `uv tool install`. Cloudflare
serves this host with cf-cache-status: HIT, so the purge is attempted first, but
best-effort — the token may not carry Cache Purge, and the live-bytes check is
what actually decides.
Runs on GitHub's runner because this org registers no self-hosted runner and the
only copy of the Cloudflare credential is a GitHub org secret. It builds no
container image; the image path (Dockerfile -> hanzoai/static -> universe CR) is
a separate unfinished migration, documented in LLM.md.
Co-authored-by: Hanzo Dev <[email protected]>
`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]>
`curl hanzo.sh | sh` resolved the name `hanzo` from PyPI. The project published
there is a different program that happens to share the name, so this installed
the wrong `hanzo` — into ~/.local/bin, which outranks /usr/local/bin on a normal
PATH, so it also won against anything correct already on the box.
Install the real CLI instead, and do not re-implement how: hanzoai/cli ships the
installer that knows its own per-platform asset naming, verifies the sha256
before unpacking, and places BOTH names — `hanzo` and the `hanzo-node` delegate
cloud's control binary execs — from that one verified build. This calls it. One
download path, one asset rule, one place to change when either moves.
Fetch that installer from the API rather than raw.githubusercontent, which is
CDN-cached and handed back a copy several minutes old during testing: a stale
script is the same class of bug this change exists to remove, so it is not worth
risking for a shorter URL. Raw stays as a fallback if the API is unreachable.
Then verify rather than assume — if the delegate name is not there afterwards
the install FAILS loudly, because a missing one silently falls through to
whatever older `hanzo-node` the box already had, which is the invisible failure
in the first place.
The quick-start also advertised two commands that no longer exist.
Co-authored-by: Hanzo Dev <[email protected]>
Superseded: the Hanzo GitHub App pushes a webhook, so the forge tracks GitHub
without a per-repo workflow. This file called git.hanzo.ai/api/v1/.../mirror-sync
— a Gitea API for a system we no longer drive — and would sit inert in every repo.
One mechanism, in one place, instead of ~350 copies of a cron.
git.hanzo.ai mirrors this repo by PULL on a ~10-minute interval, and arcd runs
CI/CD there — so every push waited out that interval before anything built.
This asks Gitea to pull HEAD immediately.
Latency only: the repo already mirrors via the App webhook, so a missing
HANZO_GIT_TOKEN or a failed curl is non-fatal and never fails the push.
Idempotent (mirror-sync just pulls HEAD) and concurrency-coalesced.
Load Geist Sans/Mono before @tailwind (valid @import ordering) and map Tailwind
fontFamily.sans -> Geist, mono -> Geist Mono, with a base rule forcing html/code
onto them. Was falling back to the Tailwind system stack (no Geist declared).
Revise the content in the Features section to reflect the focus on Hanzo Analytics, Hanzo Base, and integration with the AI Code Editor and App Builder (Hanzo Code and Hanzo App). Highlight the collaboration with the Hanzo Bot AI Team (Hanzo Dev) and emphasize the open-source nature of the project, making it easy to fork and innovate. Maintain the existing layout while updating the messaging.
Include the full source code of the Hanzo installation script with syntax highlighting and inline comments for better understanding. The script checks for prerequisites, installs Docker, initializes Docker Swarm, creates a network, and sets up the Hanzo platform.
Updated color schemes across different sections of the application for a more uniform appearance. Adjusted variables and styles to maintain a cohesive visual design throughout the interface.
Implement a minimalist, intuitive website design reflecting the philosophies of Steve Jobs, Jony Ive, and Dieter Rams. Focus on simplicity, clarity, and user experience while applying a refined color palette. Ensure high-quality aesthetics, function over form, and attention to detail. Incorporate responsive design elements, glassmorphism, and ensure proper padding and margin throughout components for a polished look.