Hanzo

Deploy

Package deploy is Hanzo CD: see what each app is running, sync it, and roll back a bad release.

Package deploy is Hanzo CD: see what each app is running, sync it, and roll back a bad release.

Base URLhttps://api.hanzo.ai
Operations20
AuthAuthorization: Bearer $HANZO_API_KEY

Specification

HIP-1122 · Deploy — The GitOps Plane — Draft · read the specification →

/v1/deploy is Hanzo CD: see what each app in the fleet is running, sync it, and roll back a bad release. It is implemented in hanzoai/cloud at apps/deploy, observing the operator-managed fleet — applications, resource tree, per-object health, live diff — and driving reconciliation. Each operator hanzo.ai/v1 App CR is a GitOps Application (apps/deploy/deploy.go:8-11). This HIP states that the cluster is the store, which reads are tenant-scoped, and why the writes are SuperAdmin-only.

Motivation

The operator reconciles declared state into workloads whether or not anyone is watching; what was missing was the watch. Without one plane that projects the fleet — declared version, health, sync, the owned-resource tree — the answer to "what is running" is a kubectl session, which neither the console nor a tenant can be handed. This plane is that projection, at the addresses the CD dashboard that consumes it already speaks (apps/deploy/deploy.go:13-15).

Specification

The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY are to be interpreted as in RFC 2119.

§1 The cluster is the store

deploy owns no store. Its state is the cluster's: App CRs, their owned objects (Deployment, Service, Ingress, ReplicaSet, Pod), and the static-plane site CRDs projected as Application rows so the fleet list covers the whole delivery surface (apps/deploy/deploy.go:76-84). Nothing this plane serves survives the cluster it reads, and nothing needs to.

§2 The addresses

Every route is under /v1/deploy, enumerated as explicit prefixes in the manifest row (manifest/apps.go:175). The fleet reads — applications, detail, resource tree, revisions, clusters, projects, settings, gitops, version — are typed. The raw routes are raw because their answers cannot be values: stream/applications and the streamed resource tree are event streams; login, callback and logout are the console's OIDC redirect dance against IAM (apps/deploy/login.go:128-140); sync, rollback and reconcile are imperatives answering acknowledgement, not a resource; account/can-i/{...} is a wildcard permission probe the dashboard issues.

§3 Tenancy — two scopes, one predicate

Scope is derived from the validated identity in one place (resolveScope, apps/deploy/scope.go:66-84): a SuperAdmin — decided by the c.IsAdmin() predicate alone, which already implies a validated principal — sees and mutates the whole fleet; a validated org member sees only apps carrying its own hanzo.ai/org label, read-only. The writes (sync, rollback, reconcile) MUST remain SuperAdmin-only: they change what runs. Secret objects are never surfaced — no tree node, no manifest — so the projection cannot leak materialized env (apps/deploy/deploy.go:36-38). Console sign-in resolves SuperAdmins through the admin-console IAM application, whose organization is the reserved admin org (apps/deploy/login.go:101-106), and validates tokens with the same validator the identity boundary uses.

§4 Money, events, telemetry

deploy is free, in those words (plugin/deploy/main.go:21, cloud.Free; not in spend.go:275). It publishes no events on the bus — the stream routes are per-request server-sent events, not bus topics — and it emits nothing to observability beyond the request span every route gets.

§5 Stage

deploy is ga: it is the platform core's delivery lens, part of the self-service agentic OS rather than a vertical application.

§6 Upstream

deploy derives from no forked code. Two third-party facts stand: it reads the cluster through k8s.io/client-go (Apache-2.0), and it serves the CD dashboard's own address shapes so that console consumes it unchanged (apps/deploy/deploy.go:13-15) — a wire dialect implemented, not code inherited.

Rationale

The alternative to reading the cluster is keeping a deployment database and reconciling it against reality — a second copy of state whose one failure mode, drift, is exactly what a CD plane exists to expose. Reading the CRs directly means the plane can be wrong only by being stale, never by disagreeing.

Security Considerations

The wrong implementation is a cluster console handed to tenants. Three boundaries hold it: writes require the SuperAdmin predicate, org reads are filtered by the org label resolved from the validated principal (never a header), and Secrets are excluded from the tree at the GVR list, so no query shape can reach them. The OIDC flow fails closed — a missing verifier or public URL disables sign-in rather than weakening it (apps/deploy/login.go:119-121).

Four surfaces

SurfaceReaches this capability asCoverage
RESTdeploy at its own prefix20 operations
CLIhanzo deploy …20 of 20
SDKDeployApi in every published client18 of 20 — the clients are generated at their own release
MCPtool deploy on https://api.hanzo.ai/v1/mcp21 operations, 5 under the document's own id — ask describe for the rest

Quickstart

export HANZO_API_KEY=sk-...   # console.hanzo.ai → API keys

Then the first call — a read that needs nothing but the key. GET /v1/deploy/login, operation get_deploy_login:

hanzo deploy login

Endpoints

EndpointWhat it does
GET /v1/deploy/applications/{name}/resource-treeReturns one application's argocd ApplicationTree: the objects the operator reconciled from its App CR, reached by ownerRef — the Deployment and,…
GET /v1/deploy/applications/{name}/revisions/{revision}/metadataReturns the argocd RevisionMetadata for one revision of one application — what the detail view shows beside a revision.
POST /v1/deploy/applications/{name}/rollbackThe console's rollback control — today it requests a reconcile, nothing more
POST /v1/deploy/applications/{name}/syncAsk the operator to reconcile one application now
GET /v1/deploy/applications/{name}/syncwindowsReturns one application's argocd ApplicationSyncWindowState — the answer to "is anything blocking a sync of this application right now?".
GET /v1/deploy/applications/{name}Returns ONE projected argocd Application by name, with status.resources filled in from its reconciled resource tree — which is what makes it the…
GET /v1/deploy/applicationsReturns the fleet as an argocd ApplicationList: one projected Application per operator App CR, carrying the image tag the CR DECLARES, the tag…
GET /v1/deploy/callbackFinish the sign-in round trip and mint the console session
GET /v1/deploy/clustersReturns the argocd ClusterList of the destinations the caller's applications reconcile into: one entry per distinct destination server, carrying the…
GET /v1/deploy/gitopsLists every Hanzo CD Application in the cluster: the git source each one polls, the commit it last APPLIED, how its last sync operation ended, and…
GET /v1/deploy/healthWhether this control plane can actually reach the cluster it deploys to
GET /v1/deploy/loginStart the sign-in round trip for this console
POST /v1/deploy/logoutEnd the console session on this host
GET /v1/deploy/projectsReturns the argocd AppProjectList this console groups and filters applications by.
POST /v1/deploy/reconcileRender the configured git source and apply it to the cluster, once
GET /v1/deploy/session/userinfoAnswers "is this browser signed in, and if not where does it sign in?" — the dashboard SPA's bootstrap question, and the only route on this plane…
GET /v1/deploy/settingsReturns the argocd AuthSettings object the dashboard SPA awaits before its first render.
GET /v1/deploy/stream/applications/{name}/resource-treeLive resource tree for one application, as Server-Sent Events
GET /v1/deploy/stream/applicationsLive application fleet updates as Server-Sent Events
GET /v1/deploy/versionReturns the argocd VersionMessage the dashboard SPA reads at bootstrap.

All Hanzo APIs · Interactive reference

How is this guide?

On this page