Files

hanzo-app — 74 products, published by Hanzo, built by named agents

74 live products at <slug>.hanzo.app, indexed at https://examples.hanzo.app.

They used to be called ex-admin, ex-kanban, ex-shop — which is not a name, it is a filing code, and it told a visitor that what they were looking at was a sample rather than a thing. Every one of them now has a product identity: a name, a mark, a hue, a tagline in its own voice, and a byline.

The byline

Lanes — published by Hanzo AI, built by Atlas, an AI agent working on internal tools.

Three claims, all true, none inflated:

Published by Hanzo AI. Machine-readable in three places that cannot be removed without removing the product: <meta name="hanzo:official">, JSON-LD naming Hanzo AI as publisher, and /.well-known/hanzo-example.json. The official flag on the project record is not set from here and cannot be — api.hanzo.ai gates it on a SuperAdmin principal. It is declared platform-side in cloud/clients/projects/firstparty.json off the same slugs, and build.py --verify-official asserts the two halves agree.

Built by a named agent. Ten agents (agents.json), each with a discipline and a body of work, each with a generated avatar. They are described as what they are — AI agents — and never dressed as people. No biography, no employer, no photograph, no testimonial. HIP-903, The Agentic Company: an agent that genuinely built the thing needs none of that, and inventing it would turn a true story into a false one.

Forked from a template. Every product's project was created by POST /v1/projects/fork from a gallery template, so projects.forked_from is a fact the platform recorded at fork time rather than a claim this repo makes about itself. 74/74 carry that edge across 28 distinct parent templates.

Two kinds of product

Derived (6). derive.py checks out the parent template, applies the agent's edit to its source, runs the template's own build, and publishes that output. The git diff it prints is the point: it is simultaneously the proof the product is a derivative and the proof a template is agent-editable.

lanes      ← kanban-board          4 files changed, 27 insertions(+), 19 deletions(-)
longform   ← blog-platform         5 files changed, 44 insertions(+), 36 deletions(-)
bazaar     ← ecommerce-storefront  5 files changed, 30 insertions(+), 22 deletions(-)
marginalia ← markdown-editor       6 files changed, 25 insertions(+), 17 deletions(-)
cadence    ← analytics-dashboard   6 files changed, 31 insertions(+), 23 deletions(-)
reel       ← video-streaming       6 files changed, 49 insertions(+), 41 deletions(-)

The edit has two halves. Brand is generic — metadata becomes the product's, the design system's --primary/--ring become its hue, hard-coded accent utilities (bg-amber-600 on a CTA) are pointed at the token instead, and the byline is rendered by the template rather than stapled onto its output, because a Next.js app owns <body> after hydration and drops anything it did not render. Content is per-product replace pairs in products.json.

Doing this found real defects the pre-built demos were hiding: four templates did not compile at all (Module not found: '@/components/ui/…' — the dependency was declared and the wrapper was never committed), and several 404'd on an /api/placeholder/… route that does not exist on a static host. Both are fixed: the wrappers upstream in hanzo-templates/*, the placeholders in the agent's edit.

Kit-built (68). The product's app is one file, apps/<slug>.html, on the shared kit. Their fork edge is recorded and honest, but their bytes come from the kit, not from the parent's source. That gap is stated here rather than papered over.

Shape

products.json  the ONE roster: slug, name, tagline, hue, mark, agent,
               parent template, and (for the 6) the agent's edit
agents.json    the ten agents: name, discipline, profile, hue
kit/hz.css     one stylesheet: tokens + the primitives every archetype uses
kit/hz.js      one runtime: DOM helpers, a persisted store, deterministic
               demo data, chart marks, a data grid, a router, and the ONE
               backend call — @hanzo/base
apps/<slug>.html   one file per product: `<!--hz {...}-->` + body + <script>
build.py       fork → compose → syntax-gate → POST /v1/sites/deploy
derive.py      reset → agent edit → template's own build → artifact deploy
verify.py      the quality gate: a real browser must render it
gallery.py     derives apps/examples.html from products.json + verify.json

One slug names all three: the source file, the project, and the host.

The three invariants

One deploy path. Every product — including the gallery — is published through api.hanzo.ai: POST /v1/sites/deploy for a file manifest, POST /v1/projects/<slug>/deploy for a built artifact (the binary-safe lane, which is what a woff2 needs). There is no third path and no path that is not the API.

One backend. Every product that stores anything calls POST /v1/base/collections/submissions/records on its own origin — @hanzo/base through host-as-project-ref (HIP-0014), so an anonymous page persists a real record with no credential in the page and no bespoke backend.

One runtime. a.hanzo.ai/analytics.js and a.hanzo.ai/chat.js, injected by the shell, never vendored, so the runtime is updated in one place instead of 74.

Gates

build.py refuses to publish a page whose script does not parse (node --check).

derive.py treats a non-zero build exit as fatal even when out/ exists — out/ is gitignored, so it survives git clean from the previous run, and trusting its presence is exactly how a failed build ships yesterday's bytes under today's brand. That is not hypothetical; it happened here, and this is the fix.

verify.py drives headless Chromium against the live URL and requires HTTP 200, no page or console error, ≥25 elements, ≥120 characters of visible text, a visible Hanzo-product badge, and — for canvas products — measured pixel variance, because a canvas that renders a flat fill is a blank 200 with extra steps.

Nothing here fabricates proof about Hanzo or its agents: no invented adoption numbers, no testimonials, no human credentials behind an agent. The contents of a demo are openly synthetic — placeholder names on generated avatars, .invalid addresses, seeded metrics, a storefront's ratings — and every page says so in its footer and in its manifest ("syntheticData": true).