hanzo-dev cab1b716c5 clients: seven apps stop linking the ai module for a table they can create
cmd/{analytics,ask,evals,leaderboard,link,rollingcap,usage} each linked
github.com/hanzoai/ai/object, and it cost them 1310-1314 packages against a
671-package core floor. All seven are now 672-677, with ZERO ai packages.

The 638 packages were buying a guaranteed error. aiobject.EnsureCloudUsageTable
execs through object.DatastoreExec, whose connection is opened only by
object.InitDatastore, which runs only inside aimod.Mount — and none of these
seven link the ai module, so the call ALWAYS returned "datastore: not connected"
and every one of the nine call sites silently took its failure branch. The
symptom was an honest-empty dashboard against a warehouse that was up. The next
line at each site already queried clients/datastore, whose connection IS live in
exactly these binaries.

So the DDL moves there — clients/datastore/cloudusage.go, verbatim, guarded by
Ready() and latching only on success, following clients/sbom's ensureTable. It is
deliberately a SECOND copy: ai keeps its own for the write path. A func var the
host injects is the obvious alternative and it is a seam that can never be wired,
because the whole point of these binaries is that they do not link ai. Two copies
of idempotent DDL against one table converge; a nil hook does not.

Two call sites were not the table at all:

  clients/answer reached aiobject.Crawl for page reads. clients/websearch already
  has a native Crawl4AI client against the same service, and answer already
  imports websearch — so Crawl is now exported there and crawl() became its len==1
  case. One dial path, one auth path, one decode path, and a duplicate client
  gone. Net new packages: zero.

  clients/rollingcap read aiobject.TierReader(), and THAT WAS A LIVE BUG: the
  rolling AI-spend cap has been dead in every deployment. aiobject's tier reader
  is a COPY clients/ai installs at ai.Mount; cloud's is the source, set by
  wireTierReader in BuildDeps before MountAll ever runs. cmd/rollingcap never
  links clients/ai, and in the unified binary apps.Wire() mounts rollingcap
  BEFORE ai — so the copy was nil either way and Mount took its no-op early-out
  on every boot. It reads cloud.TierReader() now and the cap is live.

  Its other half needed a real seam, so cloud.RollingCapReader joins the four in
  ai.go. SetRollingCapReader is the one EXPORTED setter there and the deviation is
  forced: the other four are written by build.go/durable.go inside package cloud,
  but this producer is clients/rollingcap, which sits above the edge. clients/ai
  installs a TRAMPOLINE rather than a snapshot — it resolves the reader per call
  — so mount order cannot silence the cap a second time.

Not done here: clients/admin/finance has the same import and is mid-edit by
another change. It is also the one app that would not reach the floor (2184 ->
1612 measured), because it independently pulls part of ai/object's closure.

Measured, CGO_ENABLED=0 go list -deps ./cmd/<app>:

  analytics    1311 -> 674     leaderboard  1311 -> 673
  ask          1311 -> 675     link         1314 -> 676
  evals        1311 -> 673     rollingcap   1310 -> 672
  usage        1314 -> 677     ai packages    25 -> 0  (all seven)

Tests: cloud, apps, clients/{rollingcap,usage,analytics,answer,websearch,
leaderboard} all ok. vet clean on the touched set plus ./ and clients/ai.

Co-authored-by: Hanzo Dev <dev@hanzo.ai>
2026-07-27 20:00:01 -07:00

Hanzo Cloud

Hanzo Cloud

The Open AI Cloud as one Go binary. Identity, secrets, data, AI, gateway, observability, and the console — every Hanzo-native subsystem mounted into a single multi-org process. Per HIP-0106.

Status License

The same artifact serves api.hanzo.ai, api.lux.cloud, api.zoo.cloud, api.osage.cloud, and every white-label reseller. Brand, enabled subsystems, and org scope are deployment configuration — one binary, one origin, no sidecars.

Quick start

# Run the unified binary (pin a released version)
docker run -p 8080:8080 ghcr.io/hanzoai/cloud:v1.801.206

# Or install the CLI + server
go install github.com/hanzoai/cloud/cmd/hanzo@latest
brew install hanzoai/tap/hanzo

Open http://localhost:8080 for the embedded console; the API is served under /v1 on the same origin.

What this is

hanzoai/cloud is one Go binary that mounts every Hanzo subsystem (iam, kms, base, gateway, ai, commerce, vfs, mq, dns, amqp, mcp, o11y, tasks, …) into a single multi-org process. The same artifact serves api.hanzo.ai, api.osage.cloud, api.lux.cloud, api.zoo.cloud, and every white-label reseller. Brand, enabled subsystems, and org scope are deployment configuration.

hanzo — cloud control CLI

The same binary is also a gcloud/doctl-class CLI. The first token selects the mode:

  • hanzo <subsystem>server mode: serve a subsystem (hanzo iam, hanzo cloud, …).
  • hanzo <verb>client mode: control the live estate. A thin client over Hanzo IAM (hanzo.id), the platform control plane (platform.hanzo.ai/v1), and the cloud /v1 API — it invents no parallel API.
hanzo login                       # IAM password grant against hanzo.id → token in ~/.hanzo (0600)
hanzo whoami                      # identity from the stored token (--verify hits IAM userinfo)
hanzo apps list                   # platform apps board: declared/running/latest tag + drift + health
hanzo apps get <org>/<app>/<env>  # one app row
hanzo deploy <container> --project <p> --env <e>   # rolling, zero-downtime redeploy
hanzo clusters list|get|create|select|target       # dedicated DOKS cluster lifecycle
hanzo build <repo> --sha <sha> --image <img>       # platform-native (arcd/Kaniko) build, no GitHub builders
hanzo k8s target                  # the org's resolved deploy target (kubeconfig never returned)
hanzo config set <k> <v>          # ~/.hanzo/config preferences

Global flags: --org, -o/--output table|json, --platform-url, --iam-issuer, --platform-token. Tokens resolve from flag → env → ~/.hanzo (never hardcoded): the IAM user token is the identity; the platform control plane is service-token authed (it cannot validate user tokens), so apps/deploy/clusters use --platform-token / HANZO_PLATFORM_TOKEN / PLATFORM_SERVICE_TOKEN, and build uses HANZO_BUILD_TOKEN / PLATFORM_BUILD_CALLBACK_TOKEN.

Install: go install github.com/hanzoai/cloud/cmd/hanzo@latest, or brew install hanzoai/tap/hanzo.

Subsystems mounted

Each subsystem exposes func Mount(app *zip.App, deps cloud.Deps) error and wires its own /v1/<name>/* routes onto the shared app.

  • iam — identity & access (users, orgs, roles, OIDC/JWKS per HIP-0026)
  • base — per-org SQLite + in-process extension runtimes (HIP-0105)
  • kms — secret custody (sealed secrets, HIP-0027)
  • commerce — checkout, billing, pricing, invoicing (light router; NOT in PCI-DSS scope)
  • ai — AI control plane: inference, RAG, model hub, agents, MCP management
  • gateway — HTTP routing + policy
  • o11y — metrics / traces / logs
  • vfs — virtual filesystem / object-store abstraction
  • mq — message queue
  • dns, amqp, mcp, auto, tasks, … — full list per HIP-0106

Deployment modes

Same binary; different startup configuration:

cloud --enable=iam,base,kms,commerce,ai,gateway,o11y --brand=hanzo  --domain=hanzo.ai
cloud --enable=iam,base,kms,commerce,ai,gateway,o11y --brand=osage  --domain=osage.cloud
cloud --enable=iam,base,kms,commerce,ai,gateway,o11y --brand=lux    --domain=lux.cloud
cloud --enable=iam,base,kms,commerce,ai,gateway,o11y --brand=zoo    --domain=zoo.cloud

Architecture

                 api.{org}.{brand}
                          |
                   hanzoai/cloud (one Go binary)
                          |
   +----------+----------+----------+----------+----------+
   |    iam   |   base   |   kms    |    ai    | gateway  | ...
   |  Mount() |  Mount() |  Mount() |  Mount() |  Mount() |
   +----------+----------+----------+----------+----------+
   per-org SQLite (HIP-0302)   |   Hanzo IAM JWKS (HIP-0026)
   replicate -> S3 (HIP-0107)  |   ZAP inter-subsystem RPC

Every subsystem mounts through the same Mount(app, deps) seam. Cross-subsystem calls ride a narrow in-process interface; no subsystem reaches into another's store.

White-label fork pattern

Customers fork hanzoai/cloud to launch their own ecosystem in one binary. Brand detection, enabled subsystems, and ZAP endpoints (payments / vault backends) are all deployment configuration.

Web framework

hanzoai/zip — Sinatra-style Go web framework built on Fiber v3. The ONE Go web framework. No .Fast escape hatch.

Console UI — embedded in the ONE binary

The same hanzoai/cloud binary serves the console (@hanzo/gui) UI at the web root AND the /v1 API from one process — one artifact, one origin, no separate console Service. The UI is compiled in via //go:embed (see webui.go).

Pipeline (in the Dockerfile, before go build):

console stage  →  build console static bundle  →  /out
      COPY --from=console /out/ → src/webui/dist/     (overlays the fallback shell)
build stage    →  go build   →  //go:embed all:webui/dist bakes it into /cloud

Serving (webui.go, registered LAST in Serve so it never shadows the API):

  • GET / and any client-side route (/orgs, /models, …) → the SPA shell (index.html) with Cache-Control: no-cache; fingerprinted assets under assets//_next/ are served immutable for a year, with brotli/gzip precompressed negotiation when the build emits .br/.gz siblings.
  • GET /v1/* (and /zap, /healthz, …) → the API. Real subsystem routes are registered before the console catch-all, so they always win; an unmatched path under an API prefix returns a real 404 (JSON namespace), never HTML.
  • Same-origin: the embedded console calls /v1 on its own host, so the session cookie is first-party — no second origin, no CORS.

webui/dist/index.html is a committed fallback shell (a real same-origin /v1 bootstrap) so go build always compiles and the binary always serves a UI even without the Node toolchain. The image build overwrites webui/dist with the real console bundle. See webui_test.go for the boot-and-assert tests (/ → shell, deep link → shell 200, /v1/* → API, unmatched /v1 → 404).

The hanzoai/console build:embed script (scripts/build-embed.mjs) stashes its Next server route handlers (BFF proxies that collapse to the cloud /v1/* the SPA calls same-origin), wraps the client catch-all pages for output: 'export', neutralizes the root layout's request-time headers() read, and emits a real static export at out/ (a ~360 KB index.html + _next/ chunks). The image build (and make webui) run it and overlay webui/dist, so //go:embed bakes the FULL @hanzo/gui console into the ONE binary. The Dockerfile console stage FAILS HARD if that bundle is missing or degenerate — the placeholder shell can never silently ship to prod (escape hatch: --build-arg ALLOW_PLACEHOLDER=1 for a pure-Go dev image).

Specs

Implements:

  • HIP-0014 Application Deployment
  • HIP-0026 IAM
  • HIP-0027 KMS
  • HIP-0037 AI Cloud Platform
  • HIP-0105 In-Process Extension Runtime
  • HIP-0106 Unified Cloud Binary
  • HIP-0129 Open Cloud Planes
  • HIP-0302 Encrypted SQLite + ZapDB Durability

Status

In production. The unified binary serves api.hanzo.ai and the white-label cloud surfaces today, with per-org SQLite (HIP-0302) and the embedded console. Subsystems continue to land per HIP-0106's migration phases; apps/apps.go:Wire() is the one ordered list of everything mounted. For repo-level engineering doctrine (module graph, route-table projections, cross-subsystem seams), see LLM.md.

Hanzo — the Open AI Cloud

Open source · every language · on-chain settlement. hanzo.ai · docs.hanzo.ai

SDKs in every languagePython (flagship) · TypeScript · Go · Rust · C++ · Swift · Kotlin · umbrella

S
Description
No description provided
Readme Apache-2.0
400 MiB
2026-07-16 06:27:48 +00:00
Languages
Go 98.7%
Python 0.4%
Makefile 0.4%
JavaScript 0.2%
Shell 0.1%
Other 0.1%