Hanzo AI

Registry

Your container and package registry: push images, pull them back, see what you store.

Also for this capability: API · CLI · MCP · SDKs

Your container and package registry: push images, pull them back, see what you store.

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

Specification

HIP-1144 · Registry — The Artifact Control Plane — Draft · read the specification →

/v1/registry is the management plane over the platform's two running artifact registries — the OCI registry at oci.hanzo.ai and the npm registry at pkg.hanzo.ai: list projects, images, tags and packages, and mint scoped pull tokens. It is implemented in hanzoai/cloud at apps/registry and reimplements neither registry: every op is a typed read of what those services genuinely answer, plus one token mint through the same IAM realm the docker CLI uses (apps/registry/registry.go:8-16).

Motivation

The registries are shared platform deployments with their own wire protocols and one platform credential. A tenant needs to answer "what do I store, and who may pull it" through the unified /v1 plane — with IAM identity, the org boundary, and the document/SDK/MCP projections — without cloud becoming a second registry or a byte relay.

Specification

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

The store, and there is none

This capability owns no store. The registries own all artifact data; the subsystem holds only the parsed token challenge and a short-lived token cache, in memory, pruned by expiry (apps/registry/registry.go:127-142).

Control plane only

The OCI wire — manifests, blobs, push, pull — stays on oci.hanzo.ai and MUST NOT be proxied here: a data path through the API host would double-move every image byte and break the content-addressed client protocol (apps/registry/registry.go:18-23). /v1/registry answers the questions AROUND the wire and hands out the address of the wire itself.

Addresses

Six operations under /v1/registry, all typed ops (apps/registry/registry.go:170-184): GET /status (a live probe of both halves), GET /projects, GET /images, GET /tags, GET /packages, and POST /token — a short-lived, pull-only token for exactly one org-owned image, its scope pinned server-side to repository:<org>/<image>:pull.

Tenancy

The org is the validated principal's (principal.Org), NEVER an In field. The registries are shared, so the boundary is enforced HERE on their own namespace conventions: an org's images are the catalog entries under <org>/… and its packages are <org> and @<org>/…. Filtering happens before any response shape exists — foreign names are dropped, never serialized (apps/registry/registry.go:649-652) — and the npm scope filter runs on the results, so a caller's query cannot widen it. No validated principal is 403 before any upstream byte.

Every repository segment MUST match the OCI distribution path-component grammar before it is folded into an upstream URL or a token scope (apps/registry/registry.go:107-125), so a hostile value can never smuggle path or scope structure into the wire.

Money, events, telemetry

Free, said in those words: plugin/registry/main.go declares cloud.Free. It publishes nothing to the bus, so a customer's webhooks receive nothing from it. It emits nothing beyond the request span every route gets.

Failure posture

The platform catalog credential (REGISTRY_CLIENT_ID/REGISTRY_CLIENT_SECRET, an IAM application's service credential, KMS-synced) rides only as Basic auth to the token realm the registry's own 401 challenge advertises. An upstream that refuses it MUST surface 503 — a deployment fault, never a caller-auth bug — and an unreachable upstream is 503 (apps/registry/registry.go:36-39).

Stage

ga: the registries are developer-tools core of the self-service cloud, and the manifest row (manifest/apps.go:421) declares no stage.

Upstream

The registries this plane manages are forks the platform runs, not code this package embeds: hanzoai/registry is CNCF Distribution (Apache-2.0), S3-backed with Hanzo IAM token auth, and hanzoai/pkg is Verdaccio (MIT) on S3. The app imports neither — it speaks the OCI distribution HTTP API (including its token challenge and RFC 5988 Link paging) and the npm registry search dialect.

Rationale

The alternative is proxying the registries whole, which buys one hostname and costs the content-addressed protocol: docker and npm clients already speak the registries' own wire, with digests verified end to end, and a relay in the middle is a second copy of every byte plus a place for the two to disagree. The narrower design — reads plus a pinned token mint — gives the tenant boundary a single enforcement site without touching the data path. The token being pull-only and single-repository is the same argument at the credential layer: the mint's job is to let a workload pull one image, not to delegate the platform credential.

Security Considerations

The dangerous object is the platform credential, which can read the whole shared catalog. The wrong implementation leaks it in either direction: echoed or logged outright, or laundered through an over-scoped minted token — a token scope built from an unvalidated name (repository:a/b:pull,push smuggled via a crafted "image") is the concrete case the segment grammar closes. Cross-tenant listing is the other exposure: filtering on the response shape instead of before it, or letting the caller's search query bypass the org prefix, turns a shared catalog into everyone's. And the refusal split is load-bearing — an upstream refusing the PLATFORM credential must read 503, because reporting it as the caller's 401 trains callers to retry with more privilege.

Four surfaces

SurfaceReaches this capability asCoverage
RESTregistry at its own prefix6 operations
CLIhanzo registry …6 of 6
SDKRegistryApi in every published client6 methods
MCPtool registry on https://api.hanzo.ai/v1/mcp5 operations, 1 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/registry/tags, operation get_registry_tags:

hanzo registry tags

Answers 200 with object — ok.

Endpoints

EndpointWhat it does
GET /v1/registry/imagesImages lists the org's container repositories, read live from the OCI catalog and filtered server-side to the org's namespace — the page can only…
GET /v1/registry/packagesPackages lists the org's npm packages — &lt;org&gt; and @&lt;org&gt;/… — from the npm registry's search index, optionally narrowed by a query within that…
GET /v1/registry/projectsProjects lists the namespaces the caller can see with what each holds: the org's slug, its repository count on the OCI catalog, and its package count…
GET /v1/registry/statusStatus reports whether the OCI and npm registries are reachable and, when the OCI half is auth-gated, which token realm its challenge advertises — an…
GET /v1/registry/tagsTags lists one org-owned repository's tags, read live from the OCI registry.
POST /v1/registry/tokenToken mints a short-lived, pull-only registry token for exactly one of the org's images, through the same IAM realm the docker CLI authenticates…

All Hanzo APIs · Interactive reference

How is this guide?