Files

3.8 KiB

Hanzo CDN Assets

Static assets served via Cloudflare Workers + R2 at cdn.hanzo.ai.

Structure

hanzo/
├── brand/        Hanzo logo variants (SVG, PNG, favicon, apple, dock icons)
├── buttons/      OAuth provider login button SVGs
├── flag-icons/   271 ISO 3166-1 country flag SVGs
├── fonts/        Inter + Roboto Mono web fonts (woff2)
├── iam/models/   Face recognition models
├── img/          Social provider, payment, captcha, app logos
├── market/       Backend-less Market: agents/tools/plugins catalog (JSON)
├── partners/     Partner/ecosystem logos (AWS, NVIDIA, Techstars, etc.)
├── press/        Press kit assets
└── providers/    AI model provider icons (OpenAI, Anthropic, Mistral, etc.)

Market (no backend required)

The Hanzo / Lux / Zoo desktop apps read their catalog as static JSON from here, so the Market works with no backend. Every read is a file. Each app bundles a trimmed copy of the same documents and falls back to it when the CDN is unreachable, so the Market also works with no network.

URL Contents
cdn.hanzo.ai/market/index.json manifest: schema, version, counts, file map
cdn.hanzo.ai/market/agents.json agents catalog ({products,total,page,limit,totalPages})
cdn.hanzo.ai/market/tools.json tools catalog, same shape
cdn.hanzo.ai/market/categories.json categories
cdn.hanzo.ai/market/featured.json featured collections
cdn.hanzo.ai/market/plugins.json plugin/integration registry (composio)
cdn.hanzo.ai/market/tools/{id}.json per-tool detail

Versioning. index.json carries a schema (bumped only on a breaking shape change; a client that does not recognise it keeps using its bundle) and a version that is a content digest over every served document. The version changes if and only if what the CDN serves changes, which is what makes a deploy verifiable — deploy.sh refuses to succeed unless the edge reports the version the repo just built.

CORS: the Worker sends Access-Control-Allow-Origin: * so app webviews can fetch directly.

Regenerating

scripts/market.py is the only thing that writes catalog files — the CDN documents, the apps' offline bundles and the CI gate all come from it, so they cannot disagree about the schema or the digest.

scripts/market.py gen --from ../store \
  --bundle ../desktop/apps/hanzo-desktop/src/lib/market-catalog.json \
  --bundle ../../zoo/app/apps/lux-desktop/src/lib/market-catalog.json \
  --bundle ../../zoo/app/apps/zoo-desktop/src/lib/market-catalog.json

scripts/market.py check    # CI gate: valid JSON, manifest matches, digest matches

--from is a checkout of the curated flatfile catalog (hanzoai/store): one JSON per item under data/agents/ and data/tools/. That repo stays the editorial source — a CMS or commerce backend publishes into this layout rather than being queried at read time, which is what keeps reads backend-less.

Deployment

CI (hanzo.yml → hanzoai/ci) gates the catalog on every push. Publishing is this repo's deploy.sh: upload to R2, purge the Cloudflare edge for exactly the URLs written, then verify the live manifest matches the repo.

export CLOUDFLARE_API_TOKEN=...           # R2 write + Cache Purge on the zone
export CLOUDFLARE_ZONE_ID=...             # enables purge-on-deploy
./deploy.sh                               # market catalog (default)
SUBTREE=hanzo ./deploy.sh                 # the whole asset tree

Domains

  • cdn.hanzo.ai → pub/hanzo/*
  • cdn.lux.network → pub/lux/*
  • cdn.zoo.ngo → pub/zoo/*
  • cdn.pars.network → pub/pars/*

Licensed under MIT OR Apache-2.0, per HIP-0137.