The theme is codeTheme from @hanzo/ui/core: Dracula on dark, GitHub
Light on light, the one every Hanzo surface draws. lib/shiki.ts and each
app's source.config.ts import it rather than naming a theme, so vesper
and github-dark are gone. @hanzo/ui moves to 8.27.83, the first release
that carries it.
A block's code area paints the theme's own ground and ink from the pre
shiki wrote, #282a36 in the dark, rather than the site's panel.
The docs home drew its hero and its eight domain snippets as plain text,
and so did the models page's fallback request. The hero highlights its
three doors in a server part (components/hero.tsx); the snippets and the
fallback are Example props in the MDX. No highlighter reaches the
browser.
Every conversion CTA reads "Try Hanzo" and goes to sign-in; payment comes
after it. The landing's close now does that in place of "Choose plan".
It no longer fires plan_clicked: it is not a plan choice, and the page view
and the $click that <Hanzo> autocaptures already record it. That leaves the
EVENTS re-export in @hanzo/docs-analytics with no caller, so it goes too.
The landing's "Sign up free" opened hanzo.id/signup, and "Sign in" opened
/login, whose authorize step sent the reader to hanzo.id too. No surface
sends a visitor there. Sign-in is hanzo.ai/login now (the /login address is
a redirect rule), sign-out clears the session in this browser instead of
carrying the reader to the issuer's end-session page, and the conversion
CTA reads "Choose plan" and opens hanzo.ai/pricing.
The click fires plan_clicked {source: 'docs'} on the client that counts the
page views, named from the @hanzo/events catalog that @hanzo/docs-analytics
now re-exports.
The ingest key comes from @hanzo/event's keyring, resolved from the page's
host, rather than a KMS value inlined at build. docs.hanzo.ai resolves the
hanzo org's key, the one the rest of the funnel reports under, and a sibling
docs site on a host no brand claims reports nothing rather than filing its
visitors under hanzo. The deploy resolves the same key, asks /v1/event
whether it names a project, and greps the export for it.
The Zen page called zen6 a 27B dense model and led with no reason to
pick Zen; the models index listed Zen 7 as "upcoming" and HIP-0904 as
"dense, coder and ternary checkpoints"; examples called zen5 and one
called zen5-coder-32b-instruct, which the gateway does not serve.
Zen is now told as the gateway serves it: Zen 7 in research preview
with Request access, Zen 6 the new Zen architecture (zen6,
zen6-coder), Zen 5.8 the one before, Zen 5 earlier. It leads with its
two jobs, agentic coding on your own machine and marketing work, and
names Zoo Labs Foundation, a 501(c)(3) non-profit, as its maker.
Examples call zen6.
Upstream base models appear only in the Architecture value and the
License & attribution section, both data-upstream. check-zen reads
every Zen page in pre-build and fails the build on a name from
zen.upstream anywhere else.
Nothing apps/docs renders names a utility class, a Radix primitive or a
base-ui part any more, so the build stops carrying them. global.css is
plain CSS: the faces, the ground, the color-scheme the code tokens read
through light-dark(), and the shell footer. postcss.config.mjs goes
with the Tailwind plugin, and the app drops tailwindcss and its postcss
plugin and animate plugin, tailwind-merge, class-variance-authority,
every @radix-ui package, @hanzo/docs-base-ui, @hanzo/docs-ui and
lucide-react.
The MDX pipeline drops twoslash, the auto type table and ts2js, which
existed to emit base-ui and Radix parts and which no page uses, and the
graph view's d3 and force-graph go with the graph. base-ui's shiki
stylesheet no longer answers .t_dark; the docs were its only reason to.
The framework packages stay: each still has consumers among the other
apps and examples.
Claude-Session: https://claude.ai/code/session_01HuMDfgFssPUptYUzgZ6Cp8
What was left of Tailwind and base-ui in apps/docs was the pages around
the docs: the front page, the hero and product sections on /docs, the
catalogs, search, feedback, the 404, the blog and the sign-in screens.
Each is a gui part on the theme now, and the app source carries no
utility class, no Radix and no base-ui import.
The front page follows the reader's theme instead of forcing a dark
subtree, and its API Reference card pointed at /reference, which is not
a route; it goes to /docs/openapi. Search is one gui dialog opened
from the rail or with Cmd-K, over the same static index, with the jump
and the ask-an-agent rows it had. The feedback control sends a
docs.feedback event on the one telemetry stream; it used to hand the
reader's answer to a stub that logged it to their own console.
The blog sits in the docs shell on the same page frame, and a post no
longer prints its title twice. The registry build, the fork's preview
components, the unused AI-search dialogs, the API page and the tree's
icon plugin go: nothing rendered them, and the icons were an SVG tree
serialised into every page.
Claude-Session: https://claude.ai/code/session_01HuMDfgFssPUptYUzgZ6Cp8
A page body was Tailwind's typography plugin reaching into compiled MDX
by selector, around base-ui's Callout, Cards, Tabs, Steps and code
blocks. Every markdown element and every part the content names is a
gui element now, chosen by tag through components/mdx.tsx. Blocks are
spaced by the body's gap rather than their own margins, so a list in a
callout or a table in a tab keeps its own rhythm, and tables keep the
browser's table layout so columns line up.
Code tokens carry color: light-dark(...) straight from shiki, so the
theme class picks the palette through color-scheme and no stylesheet
has to know which theme is on. remark-steps' marked divs become the
Steps parts, and a link to another page carries that page's title and
description instead of mounting a hover card per link.
Content no longer imports the framework's parts: the generators stop
writing the imports and the second "# title", 49 authored pages drop
theirs, and ported and studio pages reach the same parts through the
aliases they already used.
RELEASE.md says how a publish actually fires today: the forge mirror
does not pull on its own and a push queues no run, so sync and dispatch.
Claude-Session: https://claude.ai/code/session_01HuMDfgFssPUptYUzgZ6Cp8
The rail, the tree, the bar, the outline and the page header were
Fumadocs' base-ui layout: Tailwind utilities over a CSS grid, with the
width decisions made twice, once in classes and once in a JS media
query. They are gui stacks on theme tokens now, with every breakpoint a
media prop, so a phone hydrates the markup the export wrote. Atomic
rules ship as hoisted <style> tags and <html> carries t_dark, so a page
is styled before any script runs.
The theme has one authority, the t_dark/t_light class that gui's
NextThemeProvider writes before paint; <Hanzo> follows it and the
Tailwind dark variant answers it. The corner dock that covered content
on phones is gone; theme and help sit at the foot of the rail.
A body's leading "# heading" is dropped at compile time, since the
header already prints the frontmatter title: /docs/sdks and
/docs/openapi said their names twice. The /docs hero stops printing a
second title.
The rail narrows by tree path, so an operation page opens the reference
it belongs to, and the drawer carries the top nav a phone had no way to
reach.
LLM.md carries the four-phase plan and the inventory it is measured by.
Claude-Session: https://claude.ai/code/session_01HuMDfgFssPUptYUzgZ6Cp8
RELEASE.md described six ways to build an image and the pin that made one live,
and none of that decides what docs.hanzo.ai serves: the host is a route onto
s3://hanzo-sites/hanzo/docs and the publish is the deploy. It is one lane now,
so the runbook is one page: what fires it, what the job proves before it
publishes, how to check the live site, and which parts of the image lane are
still here and cold.
Co-authored-by: Hanzo Dev <[email protected]>
content/docs/projects/ was gitignored and held thousands of tracked
files at the same time, and every build re-mirrored it from hundreds of
upstream checkouts. Only the shipping image opted out, so the image
compiled the committed snapshot while a person's build compiled a fresh
mirror — one local build deleted 521 committed files and modified 444
more. One mirrored upstream imports a partial mid-page, which no alias
resolves, and the build failed with 54 unresolved specifiers after
silently skipping 119 further pages. The site had not built in a while.
The snapshot is the source: the ignore line is gone, the mirror leaves
the build and becomes a refresh run on purpose and read as a diff, and
the env knobs that let one command mean two different sites are
deleted. The section is named in the export gate, so losing it fails
rather than shipping a hole.
The generator's YAML escape emitted a backslash before a colon, which is
not an escape — the parser rejected the whole frontmatter block and
those pages shipped with no title, icon or description.
(cherry picked from commit dad3e566d0478258204ed9aad153f18b8e11445e)
Co-authored-by: Hanzo Dev <[email protected]>
Re-pinned to cloud@573d2d6ed. `standing` arrives at /v1/standing, so the
document carries 116 products and the tree carries 123 capability pages: cloud's
122 GA rows plus `openapi`, which the host serves itself and no plugin row
names. `catalogsync` and `rollingcap` were already gone, and the taxonomy's
Commerce note already said why.
A folder's own index.mdx is ALREADY its landing page — the tree builder resolves
it before it reads `pages`. Naming `index` there demotes the page from BEING the
folder to being a child OF it, under the folder's own name: 191 folders named
it, 188 of them under the same title, so that many rows said it twice. Gone from
four generators and nine authored sections.
The same rule one level down. The MCP door publishes one action-routed tool per
capability, so 80 of 81 products were a directory holding a single same-named
tool beside an index whose whole body was a one-row table pointing at it. One
tool is one page now, at the product's own address: 204 pages to 124. Its titles
come from `Product.title` like every other surface's, so `Cloud MCP` and `CLI`
spell a capability the same way.
A folder draws a chevron whether or not it holds anything, so 219 leaves offered
to open something and opened nothing. They say `collapsible: false`.
Counts are not written twice. Prose claimed 67 capabilities across eight
movements — two stale numbers and a third word for `domains`; it links to the
reference, which counts them. And the landing paints a literal white-on-neutral
palette while `.light` is stored globally, so choosing light on /docs and
clicking the wordmark gave a white headline on a white page: `dark` is scoped to
that page rather than left to a hidden switch.
docs.hanzo.ai documented three key types. Cloud mints two.
cloud.APIKeyPrefixes is pk- and sk-; hk- and hz- have never existed and
an unrecognized spelling is refused at the door, so a reader's first call
failed asking for a credential nobody can issue. 149 files carried one.
sk- was the subtler half: present, and described as an org-level provider
credential when it resolves to the USER. A find-and-replace would have
left that confidently wrong, so the pages that made a further claim -- a
scope, a third family, a list of recognized prefixes -- were rewritten
rather than swapped.
Derived, not restated. openapi-doc gains Document.keys, read out of the
/v1/keys prose the Go handler writes and zipdoc lifts into the document.
gen-key-types renders that as an MDX fragment api-keys.mdx includes, so
the table nobody may type is not typed. secretKey(doc) replaces the
literal three generators each kept -- which is how three GENERATED pages
also came to teach hk-.
check-keys then holds every page to it, both directions: a prefix the
document does not carry fails the build, and a class api-keys.mdx does
not teach fails it too. Renaming pk- in cloud now stops the build in six
places instead of publishing a stale page.
Also measured against the live API and cluster, and corrected: /v1/keys
does mint keys over HTTP (403 unauthenticated, not absent); Tasks is
/v1/tasks on the one host, not gRPC elsewhere; the KMS example path
404s; and four KMSSecret manifests could not apply -- two named groups
with no controller, and their spec was External Secrets' shape, not the
CRD's five fields.
Sidebar sits flush left. The docs grid was five columns centring a band,
with the sidebar area spanning the leading gutter, so the nav began
176.5px in at 1920 and 496.5px in at 2560 -- inside its own bordered
card. Three columns now: rails pinned, page between them. Measured at
/docs/api-keys before -> after: 1920 176.5/232/1052/268/176.5 ->
232/1405/268, 2560 496.5/232/1052/268/496.5 -> 232/2045/268, nav at x=0.
Phone 390 and tablet 820 unchanged (0/375/0 and 232/573/0, drawer opens,
no page overflow); desktop collapse and restore verified.
The Latency column wrote bare "<50ms", "<200ms", "<2s". MDX reads "<5" as the
start of a JSX tag and fails with "Unexpected character 5 before name", and the
loader's response is to skip the whole page: /docs/models/zen5 returned HTTP 200
with the chrome and none of the content. Nothing caught it, because zen-docs
passes types:check either way — tsc does not compile MDX. Verified by rendering:
128KB and no body before, 208KB with every section after. The values are fenced
in backticks, which is also how a latency belongs in a table.
LLM.md gets the measurements rather than a separate report file: tailwind is
LIVE here (21 postcss pipelines, 60 CSS entrypoints, and the published
radix-ui/base-ui tarballs ship "@import tailwindcss"), 39,433 class tokens over
537 source files, and the reason it cannot be patched away is that the UI layer
is two parallel Fumadocs forks that every app consumes. Also recorded: the
radix->@hanzo/gui primitive map with the two that genuinely do not exist
(navigation-menu, scroll-area), that @zenlm/ui ships tailwind classes with no
CSS in its tarball, and that types:check fails 50/72 and vitest 13/216 at rest
so changes are judged on the delta.
packages/shadcn (@hanzo/docs-shadcn) existed to emit
"npx shadcn@latest add <component>" snippets into rendered docs, and
examples/next-shadcn existed to demo it. A docs page that emits an install
command for a DOM-only component library puts that library in the reader's
app, which is the same defect as depending on it here. Nothing else in the
workspace imported either one, so both are deleted rather than repointed.
The commerce recipes and storefront pages taught the same thing more quietly:
every code block a reader copies was styled with tailwind utility classes.
Tailwind classes and raw <div>/<button>/<select> are DOM-only, so a storefront
built from these pages could never run on iOS or Android. They now use
@hanzo/gui components with style props — XStack/YStack instead of flex and
grid classes, Card/Button/Input/Select/Form instead of bare elements, theme
tokens ($color2, $borderColor, $red10) instead of gray-500 and red-500. The
product grid becomes a wrapping XStack because Tamagui targets flexbox on
native, where CSS grid does not exist.
zen5.mdx hand-rolled a highlighted box out of tailwind on fumadocs CSS vars;
it uses the framework's own <Callout>, which is what that box already was.
Authored-docs tailwind goes 17 files / 467 class tokens -> 0. What the counter
still reports is not tailwind: Bootstrap classes in a Thymeleaf template in the
Java/Spring IAM guide, custom CSS class names paired with <style> blocks in the
IAM login-customization guide, one CHANGELOG entry, and content/docs/projects/**,
which is gitignored and regenerated by sync-project-docs.ts from upstream repos.
Six of the seven readers of the API description still opened
`openapi-specs/hanzo.yaml`. That file is gone — the reference moved to
hanzoai/cloud's `openapi.yaml` and one caller was edited — so the flow pages, the
MCP reference, the interactive loader, both test suites and the build's own guard
all threw ENOENT. Thirteen tests ran where forty-five exist. The path is now a
value in `openapi-doc.ts`, which already called itself the only reader; no script
names the file, so there is no seventh caller to miss next time.
With the guard running again it found what it had been unable to see: seventy-four
routes in authored prose that the API does not serve. `/v1/paas/apps`,
`/v1/visor/machines`, `/v1/mpc/sign`, `/v1/db/query`, `/v1/o11y/scores`,
`/v1/commerce/orders` — each printed as a curl a reader would run and get a 404
from, each sitting on a page that also carried the generated callout pointing at
the real reference. The guard failed only on generated pages, which cannot be
wrong, and merely printed the half that could; it now fails on any of them, and
it governs what it can prove: a route written against `api.hanzo.ai`. A bare
`/v1/iam/acs` in a SAML guide is a path on somebody else's host and holding it to
this description was a category error, not strictness.
Its matching was wrong three ways besides. `{wildcard1}` matched one segment
where it means the rest of the path, so every correct deep path under
`/v1/kms/secrets` read as unknown. A three-segment prefix allowance waved through
anything under a real product. And the document serves the forge at
`/{org}/{repo}`, whose first segment is a parameter, so that one template alone
accepted every route on the site — including the invented ones.
The pages that were an API reference are deleted rather than corrected, because
correcting them recreates the defect: commerce's orders, customers, inventory,
promotions and storefront pages, mpc's, and the seven Bootnode stubs whose own
"full reference" link points at docs.bootno.de. Hand-maintained counts go the
same way — 187 endpoints, 51 namespaces, 147 endpoints, 69 services — kept by
hand beside a reference that computes its own.
`flows.yaml` and `sdks.yaml` stop being fetched from hanzoai/openapi. flows.yaml
names operationIds, and the pinned copy carried the projection's id scheme
(`get_v1_kv_name` where cloud emits `get_v1_kv_by_name`), so three of eleven ids
resolved to nothing and the flow pages could not build at all. A file whose
contents must agree with the document does not get a second upstream.
Two smaller things the same shape. A sibling cloud checkout was installed
unchecked, so a colleague's older tree silently rebuilt the whole reference while
`.spec-lock` still claimed the pinned release; it is digest-checked now like every
other source. And a tool resolving to an operation with no product wrote its page
to the section root — in no folder, linked from no index, invisible to every count
that walks the folders.
The git-runners poll hanzoai/docs off git.hanzo.ai and built it at
2026-08-04T04:35Z (task 31188). The note named hanzo-docs/docs, a different
repo, and reading it as "docs cannot build" sends you hunting for a lane that
already works.
The path in the IA note pointed at app/(home)/page.tsx, which no longer
exists — / lives in its own route group now so /blog and /showcase keep
the marketing chrome.
Co-authored-by: Hanzo Dev <[email protected]>
docs.hanzo.ai could not be republished. This makes every path that could do it
real or explicitly named, and moves the one check that matters somewhere every
path passes through.
The export gate is now in the Dockerfile. This site fails by exporting NOTHING:
the build succeeds, the layer is valid, the push succeeds, the host answers 404,
and no builder notices because from a builder's point of view nothing went wrong.
It used to be gated between build and push in deploy.yml, which only works for
deploy.yml — buildx builds and pushes in a single invocation with no step in
between to hold, and hanzo.yml's `test:` block runs AFTER that push, so neither
could have held it back. scripts/check-export.sh states what a site is, once;
apps/<app>/export.require names the sections that vanish without breaking
anything else. A failed gate means no image exists, so no lane can push past it.
deploy.yml keeps its own call of the same script against the finished image,
which answers the one question the build stage cannot: did the export land in the
IMAGE. Tested against seven exports — healthy, empty, nav-less, under the page
floor, section missing, absent directory, default require-file resolution — under
both dash and busybox ash.
docs/studio/ is the case that motivates the require file. It is a submodule, and
hanzoai/ci checks out without recursing, so on that lane the section silently
disappears while page count and nav both stay green.
.github/workflows/cicd.yml is seven lines importing hanzoai/ci, configured by the
root hanzo.yml. It is workflow_dispatch-only: give this repo two push-triggered
builders for one image and one commit yields two images under two tag schemes,
and the pin names one of them by luck. It names our own runner pool, the same
label the forge lane answers to. It cannot schedule yet, and the reason is not
Actions — Actions is on and the repo is public; every runner we own is registered
to git.hanzo.ai, and GitHub-hosted runners are not something we build on.
RELEASE.md is the runbook: four builders, the credential each needs, and the
exact edit that makes an image live. The finding worth repeating here is that
universe pins a digest beside the tag and the chart renders repo:tag@digest — so
the digest is what gets pulled, and moving the tag alone is a silent no-op.
Verified against the live systems rather than the docs: the pin resolves to the
digest the values file names; no image exists for current main in ANY of the
three tag shapes, so all lanes are cold rather than one quietly working; the
forge repo answers 404 on /actions while another repo on the same forge answers
200; /v1/runner answers 401 with the token configured on the far side, so it is
armed and one credential away.
Co-authored-by: Hanzo Dev <[email protected]>
.github/workflows held 19 files; it holds sync.yml alone now, the canonical
push-refs workflow from universe infra/ci/sync.yml. What it replaced was a
mirror-sync nudge documenting GitHub as upstream and asking the forge to pull.
Thirteen workflows moved into .hanzo/workflows unchanged — byte-identical, so
git records them as pure renames. runs-on is untouched: the forge's runner
answers hanzo-docs-build-linux-amd64. That covers the only checks (lint, test),
the only publisher of the ~30 npm packages (release), the daily pricing commit
(sync-zen-pricing), and the nine sibling static sites, each of which is the
ONLY deploy of its host. Those nine still reach Cloudflare Pages; they move to
images one host at a time, because cf-zones declares only three of the nine and
an App CR with a guessed host is wrong even while inert. LLM.md carries the
list and the steps.
deploy-docs.yml becomes deploy.yml and only builds and pushes. It had patched
`app docs` with kubectl and waited on the rollout, and it built the image from
a heredoc Dockerfile pinned to static:0.4.1 while the repo's own Dockerfile —
the one the fabric builds — pinned v0.5.1. The recipe lives in the Dockerfile
alone now; the workflow runs it, gates the export by reading /public out of the
built image so what is checked is what serves, and pushes only if the gate
passes. ghcr auth is REGISTRY_TOKEN, since a forge-issued GITHUB_TOKEN
authenticates nothing there.
The Dockerfile takes APP, so every static site in the monorepo builds one way
and the nine siblings need no new Dockerfile when they flip.
Deleted four workflows that could not have worked: deploy-liquid-docs and
deploy-zap-docs build apps/liquid and apps/zap-docs, neither of which exists
(liquid's Cloudflare job was already `if: false`), and fix-cf-domain and
setup-gui-domain are dispatch-only one-shots calling the decommissioned
Infisical /api/v3/secrets/raw route.
Also corrects three changesets that named packages absent from the workspace,
which made `changeset version` fail and release.yml publish nothing:
@hanzo/zen-models -> @zenlm/models (sync-zen-pricing.yml wrote that name every
day), and fumadocs-mdx / @fumadocs/content -> @hanzo/docs-mdx /
@hanzo/docs-content per the rename rule in LLM.md.
Co-authored-by: Hanzo Dev <[email protected]>
Ground docs.hanzo.ai in HIP-0127 (V8 · Open Edition). The spine: "the AI cloud
you can run yourself" — one unified binary, hanzo.network is the cloud, category-
first descent by the eight movements, API reference as its own separated surface.
- Sidebar (content/docs/meta.json): flat ~85-item dump with overlapping
ad-hoc labels → the eight canonical movements from openapi/capabilities.yaml
(Identity & Trust · Intelligence · Data · Streams · Observability · Commerce ·
Platform · Applications), as icon-bearing separators (---[Icon]Name---). Files
stay flat — no URL/back-link breakage. openapi/sdks/api removed from the root
descent; they remain the dedicated top-nav surfaces.
- Top nav (components/layouts/shared.tsx): add Docs + Network; API and SDKs kept
as separated surfaces.
- Landing (app/(home)/page.tsx): hero → decentralized spine; ecosystem grid →
the eight movements (category-first); breadth stats bar + models/SDKs/MCP
panels making the full surface visible. Every number traces to a source:
67 caps / 8 movements (capabilities.yaml), 157 models (ai/conf/models.yaml),
706 connectors (cloud/.../catalog.json), 6 SDK langs (openapi/CLAUDE.md).
- Docs home (content/docs/index.mdx): 69-services pitch → the run-it-yourself
spine + the eight-movements grid.
- New content/docs/network.mdx: hanzo.network / self-host — one binary, BYO GPU
or K8s, mine on any device (TEE/CC), free for public+OSS, the language seam is
the wire not FFI.
- New content/docs/architecture/philosophy.mdx: the engineering pedagogy —
one-and-one-way, decomplect, one contract → N SDKs → thin CLIs, ZAP-native.
- architecture/index.mdx: "ten categories" → the eight movements; link
philosophy + network.
Content review only — do not merge yet.
* docs: redirect /docs/{startups,deploy} → real pages (QA 404 fix)
getting-started references /docs/startups + /docs/deploy but those slugs 404
(the mdx pages didn't survive an earlier merge). Redirect to the pages that
carry the content: getting-started ($5/startup on-ramp) + services/paas (deploy).
* docs: unified docs architecture — hub + hanzo-docs/<team> submodule pattern
Ratify docs.hanzo.ai as the single unified-build hub and define the one way
content joins it, by kind:
- authored -> content/docs/<section> (in-hub or hanzo-docs/<team> submodule)
- generated -> openapi + ZAP SDK generators, gitignored, never hand-written
- ported -> sync-project-docs mirror + upstream attribution
Changes:
- ADR as a rendered docs page (content/docs/contributing/docs-architecture.mdx)
+ nav entry; LLM.md canonical model + dedup/rollout debt.
- Wire hanzo-docs/studio-docs as the reference exemplar: git submodule at
content/docs/studio/ (was a single tracked file). deploy-docs.yml checkout
now fetches submodules recursively.
- Security: cf-pages-deploy.mjs no longer hard-codes a Cloudflare API token;
it is required from env/KMS and fails fast (token must be rotated).
Standalone-vs-hub criteria, API-ref-from-openapi, and SDK-slot wiring are all
documented in the ADR. Aggregation proven: 38 API-ref pages generated from 36
openapi specs; studio section resolves from the submodule on disk.
---------
Co-authored-by: hanzo-dev <[email protected]>
- Replace docs.hanzo.ai with hanzoai.github.io/docs across 65+ files
(metadata, package.json homepages, READMEs, examples, templates, content)
- Update twitter creator from @fuma_nama to @hanzoai
- Update baseUrl to use GitHub Pages URL instead of Vercel env var
- Update RSS feed base URL
- Add GitHub Actions workflow for building docs
- Add LLM.md with detailed technical documentation for AI assistants
- Add build-all-docs.sh and dev-all-docs.sh scripts for multi-brand docs
- Add setup-fork.sh for creating new brand forks
- Fix sponsor page null tier error with optional chaining
- Update README with multi-brand documentation