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>
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.
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/v1API — 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 managementgateway— HTTP routing + policyo11y— metrics / traces / logsvfs— virtual filesystem / object-store abstractionmq— message queuedns,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) withCache-Control: no-cache; fingerprinted assets underassets//_next/are servedimmutablefor a year, with brotli/gzip precompressed negotiation when the build emits.br/.gzsiblings.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
/v1on 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 language — Python (flagship) · TypeScript · Go · Rust · C++ · Swift · Kotlin · umbrella