A stranger can self-signup and run inference we pay a provider for, at zero
balance. Not for want of auth — every gate on the path checks auth. The binary
shipped THREE paywalls and enforced none:
- routers.Paywall (mounted app-wide) asked only "does the org hold a paid
PLAN?". No credit leg, so turning it on would have 402'd every prepaid
customer. That is why it shipped dark and stayed dark.
- BillingGate (mounted app-wide) gates on price(path) > 0, and DefaultPrice
returns 0 for every path — it never evaluates anything.
- entitlements.RequireProduct had the right answer and was mounted on no
route at all.
The predicate lived in clients/entitlements, a leaf that imports the root — the
wrong side of the dependency, so the edge filters serve.go mounts could never
reach it and grew their own divergent copies instead. Move it to the one package
every gate can import and delete the copies.
BILLABLE IS NOT PRICE. Authorization and pricing were one int64. Every inference
path prices at 0 at the edge — deliberately, since ai and zen self-meter their
token costs — and `cents <= 0` was read as "do not gate", so "we charge nothing
HERE" silently meant "we authorize NOTHING here". The same fusion un-gates every
resource an operator prices at 0 (ResourceMeter.Gate: costCents <= 0 -> nil).
That fusion is why the LLM leak and the non-LLM gap are one bug. Two questions
now: Billable says whether standing is required, DefaultPrice says what the edge
charges. Pricing at zero can no longer un-authorize.
SpendGate replaces routers.Paywall at the same mount: subscription OR prepaid
credit (cloud.Stand), read at the wallet address the DEBIT writes, over the LLM
paths and the non-LLM resource trees alike.
DEFAULT OFF, and that is sequencing, not timidity. There is no reachable
starter-credit path in this binary: grant-starter was deleted from commerce
(last in v1.48.2), its replacement POST /v1/billing/credit is not registered in
the co-resident build, and no ensureStarterCredit runs anywhere. A new signup's
wallet is $0 with no self-service way to fund it, so enforcing today trades a
revenue leak for a total signup outage. Flip it only after a funding path exists.
Also fixes the kill switch, which could not kill. serve.go ORed a boot-time
cfg.PaywallEnforced on top of the cockpit switch, so an env var could arm a gate
the cockpit could not disarm. The flag's own Env fallback did the same. Both
gone — entitlements' TestSwitchesDefaultOff already asserted this and was RED on
main. PAYWALL_ENFORCED is set in no deployment and no CR, so this is inert in
production.
Unknown refuses AS UNKNOWN. Unpaid requires BOTH authorities to have answered
no; anything less is Unknown and takes the posture (paywall_strict, also default
off), never a fabricated delinquency. Reads, the pay path, inbound payment
webhooks, and SuperAdmin masquerade are never gated.
Tests: 16 gate cases, 22 Billable cases, the atto boundary, and the address
property every prior recurrence violated — gate the pool, spend the person's
wallet. Mutation-checked: pool-instead-of-wallet, Unknown-admits, and
gate-the-reads each turn them red.
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