Skip to content
Naz-TacPublic
forked from hanzoai/cloud

About

Hanzo Cloud — OSS core. One Go binary. Dual-licensed Apache-2.0 OR MIT.

Resources

Stars

0 stars

Watchers

0 watching

Forks

 
 

Latest commit

 

History

65 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Hanzo Cloud

The open-source Hanzo Cloud — one Go binary that runs a complete local cloud: a document store, a key/value store, SQL, a task queue, functions, secrets, object storage, DNS, code search, a gateway edge, feature flags, audit, and a plugin runtime. Every subsystem mounts from one composition root (apps.Wire()).

No Kubernetes. No cluster. No network. No Rust toolchain. A data directory is the whole dependency.

Run it

make dev

That builds the binary, mints a local encryption key the first time, and serves http://127.0.0.1:8080. Open it — the console is embedded in the binary.

Or without make:

go build ./cmd/cloud
CLOUD_KMS_MASTER_KEY_REF=$(openssl rand -base64 32) ./cloud

go build needs nothing but Go. The feature-flag evaluator has a native Rust implementation, but it sits behind -tags flags_native precisely so that a missing Rust toolchain can never stop the binary from building; without the tag a pure-Go fallback takes its place.

Where it listens

CLOUD_LISTEN is the address (default :8080). PORT is read as a fallback when CLOUD_LISTEN says nothing, so PORT=3000 ./cloud does what you expect. Health and metrics are on a separate ops listener, CLOUD_HEALTH_LISTEN (default :9090), so a load balancer probes a port the public never reaches:

curl localhost:9090/health
curl localhost:8080/v1/openapi.json     # every route this process serves

The encryption key is not optional

Stores open through cek, which encrypts them at rest with SQLCipher. Every build can encrypt — the cgo backend links libsqlcipher, the pure-Go backend uses a pure-Go codec — so a build with no key refuses to open the data plane rather than silently writing plaintext. That refusal is the point, and it is the same code path in development and production.

make dev therefore mints a real key into .dev/master.key (gitignored, mode 0600) instead of exempting itself. If you want plaintext files to poke at, CLOUD_DEV_UNENCRYPTED=1 opts out of only the no-key case, loudly, every boot. A malformed key still fails. Never set it where real data lives.

The local apps

Three apps run entirely on the embedded store. They are real implementations, not proxies to a cluster — the same addresses the hosted product serves, backed by local SQLite.

/v1/base collections of JSON documents — the local store, and so also the local key/value and the local SQL
/v1/tasks durable queue with lease/ack
/v1/functions function registry and runner (staged — see below)
/v1/bot the protocol a control UI speaks, and under it the bot runs that are going

There is deliberately no /v1/kv and no /v1/sql. Base is already both: a document under a collection is the key/value store, and it is SQLite underneath. Two more doors onto one room would be two more names to keep in agreement.

/v1/kms is here too, serving from an embedded luxfi/kms — secrets belong in KMS locally exactly as they do in production, never in an env file.

A bot is a loop, and one instance of that loop is a run. /v1/bot/runs is where your runs are, wherever they happen to be: start one where you have a machine for it and that machine says so (POST /v1/bot/runs with where: local), and it is listed, reachable, and stoppable from the same place as a run in a sandbox. Nothing in this edition places a sandbox, so asking it to start a run in the cloud answers 501 and says what is absent rather than minting a run nobody is carrying out; a deployment that does have an executor hands it to the registry (cloud.Deps.Runs) and its runs join the same list.

A run can park. Suspending one hands back whatever it needs to come back as itself — a checkpoint reference, opaque here — and the gateway holds that token without reading it, so the same run can resume on the machine it left or on another. That is the difference between a registry and a liveness ping, and it is why a run can move between a laptop and the cloud. Stopping is a separate door and there is only one of it: the heartbeat refuses the status and names /stop, and forgetting a run ends it through the same halt on its way to disposing of everything it held.

/v1/bot itself is the protocol a control UI speaks — a WebSocket on the upgrade, one request frame on the POST. Asking to upgrade is a fact about the request rather than a flag beside it, so the socket needs no name of its own, and /v1/bot/runs is one segment down where it cannot collide with the other addresses published under /v1/bot.

The protocol answers a subset and says so: hello-ok carries features.methods, and a UI hides any surface whose method is absent. Advertising exactly what works is therefore the growth path rather than a compromise — a method that is merely stubbed should not be listed at all, because a hidden palette reads as a small server and an empty one reads as a broken one.

Every operation is a typed op, which is why they need no separate integration work: one declaration projects into the OpenAPI document, the MCP tool surface, the CLI and the generated SDKs at once. An untyped route gets none of those, which is the whole reason not to write one.

curl -X POST localhost:8080/v1/base/collections/notes -d '{"title":"hello"}'
curl localhost:8080/v1/base/collections/notes

MCP

/mcp speaks JSON-RPC 2.0 and exposes every typed op as a tool. It is built from the same registry as the REST routes, so a tool cannot drift from the endpoint it calls.

curl -X POST localhost:8080/mcp \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

Namespaces

A request carrying a validated identity operates in that identity's org. A request without one operates in the local namespace, keyed by the empty string — a key no real org can ever equal, so the two can never collide. That is what lets the edition be useful with no identity provider running.

It also means an unauthenticated caller who can reach the port can read and write the local namespace. make dev binds loopback for exactly that reason. Put Hanzo IAM in front of it before it listens anywhere else.

Functions is staged

/v1/functions executes code — it writes a function body to a temp file and runs it with node, python3 or bash. It is linked into every build but mounts only when named, so it can never appear on a surface nobody asked for it on:

CLOUD_ENABLE_STAGED=functions ./cloud     # make dev does this for you

iam and ingress are staged the same way, for their own reasons.

Plugins

Plugins mount from a manifest at CLOUD_PLUGINS and load lazily — the routes exist from boot, but a plugin is built on the first request to its prefix, so a manifest of twenty services costs nothing until they are used. /v1/plugins reports which ones have actually loaded.

Configuration

flag env default meaning
-data-dir CLOUD_DATA_DIR /var/lib/cloud data root
-listen CLOUD_LISTEN / PORT :8080 HTTP listener
-enable CLOUD_ENABLE (empty = all) subsystem allowlist
— CLOUD_ENABLE_STAGED — additionally enable staged subsystems
— CLOUD_KMS_MASTER_KEY_REF — base64 of 32 bytes
-brand CLOUD_BRAND hanzo white-label brand
-domain CLOUD_DOMAIN api.hanzo.ai primary domain
-iam-issuer CLOUD_IAM_ISSUER — JWKS issuer

Where a plane the private build injects is absent, the subsystem mounts fail-closed and says so rather than pretending to work:

s3 subsystem mounted fail-closed: S3_ADMIN_ACCESS_KEY not set (all ops 503 until provisioned)

Develop

make build          # go build, no Rust needed
make test           # go test ./...
make native         # optional: cargo build the Rust flag evaluator
make build TAGS=flags_native
make hooks          # install the pre-push guard — do this once

make hooks points git at .githooks, which refuses any push to origin carrying commits or imports from the private enterprise edition. This repository and that one have unrelated history and must never merge; the hook is what makes a mistyped push a non-event instead of a licence incident.

Licence

Apache-2.0. See LICENSE.

About

Hanzo Cloud — OSS core. One Go binary. Dual-licensed Apache-2.0 OR MIT.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages