The prior /api/* -> /v1/* sweep (65c8be420) missed one line in the Cloud service
Quick Start: the create-API-key example used api.hanzo.ai/api/add-token while the
sibling chat-completion example right below it correctly uses api.hanzo.ai/v1/*.
Per the always-/v1-never-/api convention, this is now api.hanzo.ai/v1/add-token.
(cherry picked from commit d0008980da)
MeetHanzoMenu gets a resolveHref map so ecosystem items with a docs page
resolve to that page instead of bouncing to the marketing home; unlisted
ids keep the canonical link. Requires @hanzogui/shell >= 7.6.3, already
the pinned version. Every mapped target page exists.
Adds the /docs/webhooks page: endpoint registration, signature verification
(Node + Go), retry/backoff semantics, delivery logs, test sends, and secret
rotation. Nav entry under Streams.
The product is hanzoai/datastore. ClickHouse is its upstream, named where
provenance is the subject and nowhere else.
Co-authored-by: Hanzo Dev <dev@hanzo.ai>
A find-and-replace of "Infisical" -> "Hanzo KMS" ran across the KMS docs and
put a SPACE inside every identifier it touched. An identifier can never contain
a space, so every affected code block was copy-paste broken:
kind: Hanzo KMSSecret # not a valid k8s kind
--policy-name Hanzo KMSSecretsAccess # not a valid AWS IAM name
--role-name Hanzo KMSECSExecutionRole
HanzoKMSException / HanzoKMSClient / HanzoKMSSdkSettingsBuilder
Table name: Hanzo KMSLogs # DynamoDB forbids spaces too
147 substitutions across 41 files. k8s kinds drop the prefix entirely and
everything else just loses the space, keeping the brand.
The kinds are not a guess — they are what the cluster serves:
kmssecrets / kmsdynamicsecrets / kmspushsecrets .secrets.lux.network, i.e.
KMSSecret, KMSDynamicSecret, KMSPushSecret.
Also collapses three different apiVersions onto the one that exists. The docs
taught secrets.hanzo.ai/v1alpha1 (x2) and secrets.kms.hanzo.ai/v1alpha1 (x16)
alongside the correct secrets.lux.network/v1alpha1 (x7) — and the middle one
matches no installed CRD at all (the group is kms.hanzo.ai, not
secrets.kms.hanzo.ai). All 25 now match the group universe uses in 175 places.
Filenames still read infisical-*.mdx. Renaming them changes published URLs, so
that is a separate call — the content they serve is correct now.
The per-project descriptions were generic marketing lines that did not
distinguish one service from another — "Backend-as-a-Service with realtime and
auth" describes half the catalog. Replaces them with the specific thing each
component is, e.g. Base as the multi-tenant SQLite backend with polyglot
in-process extension runtimes and age-encrypted WAL replication, which is what
makes it the storage substrate rather than one more BaaS.
Also adds the World API OpenAPI spec (628 lines) so /v1/world is documented on
the same plane as every other service, and drops a stale langfuse component.
apps/docs/docs/{browser,server}.ts are regenerated index maps (they open with
@ts-nocheck and import the docs-mdx runtime), not hand-edited.
Both directories were published and reachable by URL — /docs/sdks and its 11
language pages all answer 200, /docs/openapi's 72 pages likewise — but neither
appeared in meta.json, so nothing linked to them. Written, deployed, and
undiscoverable unless you already knew the path.
sdks -> Build, right after cli (11 pages: python, go, rust, cpp, kotlin,
swift, node, iam, ast, …)
openapi -> Reference, before architecture (72 endpoint pages)
studio/ is deliberately NOT added: the directory is EMPTY. A nav entry pointing
at nothing is worse than no entry — it promises a page and delivers a shell.
Either fill it or delete the directory.
Found by diffing the directory listing against the nav rather than trusting
either one: 'services' and 'cli' were already listed, so the reported
/docs/cloud and /docs/cli gaps were stale — cloud docs live at
/docs/services/cloud and are reachable via Services -> Hanzo Cloud.
Standing brand rule: we are not LiteLLM and do not position ourselves as one.
HANZO_AI.md did it three times — a heading 'Complete Model Catalog (OpenRouter +
LiteLLM Compatible)', 'every model available through OpenRouter and LiteLLM',
and 'OpenRouter + LiteLLM = access to every AI model' — which frames our catalog
as someone else's reach rather than our own API.
Deliberately NOT touched, because a blanket sweep would have broken both:
- llm.mdx's `litellm_params:` — a real YAML config key inside a code example.
Renaming it would publish a config that does not work.
- ai-functions.md's 'e.g. vLLM, Ollama, LiteLLM' — naming third-party services
a reader may point us at. Factual and correct, same as the Vercel AI Gateway
page elsewhere in these docs.
The rule is about how we describe OURSELVES, not about erasing other people's
product names.
The API reference asked fonts.scalar.com for 13 webfonts on every load. Our CSP
is font-src 'self' data:, so all 13 were blocked — 13 failed requests, 13 console
errors, and type that silently fell back to whatever the OS happened to have, on
our most public developer-facing page.
Naming Geist in a font stack did not fix it: nothing self-hosted it, so
@font-face resolved to an empty list and Geist only appeared for people who
happened to have it installed. Measuring the live page is what caught that.
Now the fonts actually ship: Geist-Variable.woff2 and GeistMono-Variable.woff2
beside the bundle. One VARIABLE file per family covers weights 100-900, so the
whole thing is two same-origin requests (~141KB) instead of ten static cuts.
Wired through Scalar's own seam — it reads --scalar-font / --scalar-font-code
everywhere it sets type, so overriding those two properties beats an !important
war against its selectors and survives a bundle upgrade.
Deleted the 13 dead @font-face blocks from the vendored bundle rather than
leaving them neutered: 15 font declarations where 2 suffice is the same
complecting in miniature. Two rules, one place. Verified the bundle still parses
and that the reference directory now contains ZERO external hosts.
The vendored Scalar bundle carried 13 @font-face rules pointing at
fonts.scalar.com. Our CSP is font-src 'self' data:, so every one was blocked —
13 failed requests and 13 console errors on every single load of our public API
reference, while the type silently fell back off-brand.
Patched the vendored bundle: each 'src: url(https://fonts.scalar.com/...)
format(woff2)' becomes 'src: local(Inter)'. Valid CSS, zero network, 0 refs
left, bundle still parses (2505070 -> 2504397 bytes).
Type now asks for Geist Sans and Geist Mono to match the rest of docs. Honest
caveat in the comment: /reference is a static page outside Next's font
pipeline, so Geist is not self-hosted HERE — it resolves if locally installed
and falls back cleanly. Self-hosting the woff2 is the follow-up.
The placeholder was gated on `#app:empty` — but Scalar mounts as a SIBLING of
#app, so #app is empty forever and the loading message became a permanent
146px band pinned above the real reference on every visit, on both viewports.
The first thing a customer saw on our API reference was a load state that
never resolved.
Gated on `html.booting` instead, cleared by a MutationObserver on the first
rendered node with a load-event fallback — so it cannot outlive the load
regardless of where Scalar mounts.
Also: the file claimed 'no runtime CDN' while Scalar fetches fonts.scalar.com
(13 CSP-blocked requests per load, silently falling back off-brand). Comment
corrected to state the truth and Geist pinned so the reference matches docs.
Brand: 'LLM API gateway with all models' -> 'One API for every model';
'chat-completions proxy' -> 'chat completions'. Honesty: dropped the '$5 free
credit' line from base-docs pricing (that grant is disabled).
Two independent defects made every documented 'first API call' fail:
1. FICTIONAL MODEL IDS. `zen-omni` and `zen-coder` appear ZERO times in the
live catalog (api.hanzo.ai/v1/models, 440 models). Every SDK sample -
python, typescript, go, cpp, swift, kotlin - told the customer to call a
model that does not exist, so even a correct request 400s. Corrected to the
real ids: zen5 and zen5-coder.
2. DEAD HOST + STALE PINNED MODEL. llm.hanzo.ai is retired and 301s (a POST
returns the literal string 'Permanent Redirect', not a completion), and
`claude-sonnet-4-5-20250929` is long superseded. Both removed: the host is
gone from customer-facing docs entirely rather than documented as retired,
and pinned upstream ids give way to our own current zen5.
50 files. Verified against the live catalog, not assumed.
The <script src="analytics.hanzo.ai/script.js" data-website-id> tag is a shim:
it talks to a read LENS instead of the one ingestion front door, so a docs site
could only ever produce pageviews — no errors, no product events, and a separate
per-site id to keep in sync. Replaced across all 12 sites with @hanzo/event
POSTing api.hanzo.ai/v1/event, which Cloud fans server-side into the web
(analytics), product (insights) and error (sentry) lenses. `product` is the only
per-site knob; Cloud resolves the tenant, so no site carries an id any more.
One implementation, not twelve: packages/analytics (@hanzo/docs-analytics)
mounts the provider, adds a pageview per client-side route change, and honors
Global Privacy Control / Do-Not-Track by disabling the client outright. The main
hub's inline Insights snippet goes too — that lens is already fed by the one
stream.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Our own docs branded a Hanzo product as an 'AI Gateway' (/docs/llm title+H1,
skills index, and ~90 files across docs/bot-docs/cloud). Renamed to 'AI API'
to match hanzo.ai/app/bot. Third-party product names are facts about someone
else's product and are NOT rewritten: 'Vercel AI Gateway' restored verbatim
(same carve-out as LiteLLM); HanzoBot's own 'Gateway' transport untouched.
Pins ghcr.io/hanzoai/static 0.4.1 -> v0.5.1: only v0.5.1 carries 79ac4f9
(serve directory index in place), so docs was the last host 301ing /docs/x/
-> /docs/x/index.html, which poisons Next's router into prefetching
.../index.html/__next._tree.txt — 8 failed requests per page load.
The docs App CR + pods pull ghcr.io/hanzoai/docs (public), but deploy-docs.yml
built+pushed+patched ghcr.io/hanzo-docs/docs (private) → every operator deploy
ErrImagePull'd (kept alive only by a manual crane-copy). Converge both on the
canonical public ghcr.io/hanzoai/docs per the Hanzo registry rule: CI push target
now equals the CR pull source. Immutable SHA tag only (drop floating :latest).
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The user's actual complaint: the top nav's Models & Agents linked OUT to
hanzo.ai marketing mid-docs. This is a DOCS surface — items that have a docs
home now stay internal: Models→/docs/services/models, Agents→/docs/agents,
MCP→/docs/mcp, Pricing→/docs/services/pricing, Developers→/docs. Only
Enterprise (marketing-only, no docs page) resolves out. (The earlier
resolveHref work fixed the secondary Meet-Hanzo dropdown; THIS is the primary
top nav the user meant.)
The search dialog used `type: 'hanzo'`, POSTing to a remote auth-gated API a
public static site can't call — every query silently returned empty. The
`/api/search` route also froze to the force-static empty-query `[]`.
- route: export `staticGET` (the whole flexsearch index) instead of the dynamic
GET; tokenize `forward` (prefix / as-you-type) over titles + section headings
only. A full-body forward index exceeds V8's max string length and OOMs the
export; headings-only is ~20MB / 1.7MB gzipped.
- dialog: `type: 'flexsearch-static'` from /api/search — no server, no auth.
- core: wire the missing `flexsearch-static` case into useDocsSearch; re-export
buildIndexDefault so the route can tag pages (All/Services/SDKs/API/Products).
Verified on the built out/api/search: agents 85, authentication 113, getting
started 40, prefix "deplo"->/docs/deploy; all five filters return results.
7.5.1 predated the resolveHref prop, so the docs-aware nav map (meet-hanzo.tsx,
already committed) was a silent no-op. 7.6.1 ships resolveHref (+ the logo
product-switcher trigger), so the Meet Hanzo product items now resolve to their
/docs/* paths instead of bouncing to hanzo.ai marketing. Lockfile updated for
the frozen-lockfile build.
hanzoai/static's default CSP is default-src 'none', which blocks all client JS —
the docs' own interactivity and the Scalar OpenAPI reference at /reference. Set a
secure docs CSP (self + inline/eval for the renderer; object-src/frame-ancestors
still locked) via the App CR env. Already applied live; declaring it here for
durability. (k8s/** is outside the deploy-docs trigger paths, so this is
config-only.)
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Elevate the highest-leverage docs surfaces to one voice — plain-language clarity
(start from why it matters, define jargon in the same breath) with confident,
restrained marketing prose. Prose only; no numbers, links, ids, or structure changed.
- home (index.mdx + landing page.tsx): sharper hero lead, one crisp benefit-first
line per domain, tightened the one-name-one-route framing
- getting-started: effortless first-principles opener (one address, one key, one setup)
- architecture/philosophy: Feynman opener for the one-binary/one-contract core idea
- pubsub, o11y: concrete why-you-reach-for-it openers
SDKs (two-line model per SDK-ARCHITECTURE):
- Rewrite /docs/sdks: Python (flagship), TypeScript, Go, Rust, C++, Swift,
Kotlin — each with Cloud SDK vs AI/Agents lib, install, quickstart, and links
to the per-language org (hanzo-<lang>) + umbrella (hanzoai/sdk).
- Verified install matrix. GA shown as runnable: pip install hanzo / hanzoai,
npm i @hanzo/ai / @hanzo/sdk, go get github.com/hanzoai/go-sdk. Coming soon:
Rust / C++ / Swift / Kotlin (source usable today via git/FetchContent).
- Replace c.mdx with cpp.mdx; add swift.mdx, kotlin.mdx; update meta.json + hub.
API reference (now LIVE in the static export):
- Native Fumadocs OpenAPI is disabled under NEXT_EXPORT (dotted API slugs break
Next static export), so the reference was never live on docs.hanzo.ai. Add a
self-contained Scalar page at /reference rendering the unified spec — all
/v1 endpoints across every service.
- Ship the spec (public/openapi/hanzo.yaml) and the Scalar bundle
(public/reference/scalar.standalone.js) with the export; no runtime CDN.
sync-openapi.sh now refreshes public/openapi/hanzo.yaml too.
- Reachable from nav (home API Reference card → /reference), the /docs/openapi
index, and the SDK hub. Fix stale SDK links + "unified gateway" wording.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The pinned lucide-react has no 'Chrome' export → Turbopack build failed (caught
at BuildKit, never reached prod). Remove the version-specific brand icons; use
Plug for every native connector row. Verified with a clean local build (20/20
tasks green, export contains the Native connectors + MCP servers sections).
New <ConnectorsCatalog/> on /docs/mcp: native connectors (GitHub App / OAuth2 —
GitHub, GitLab, Slack, Google, Discord, X) up top, then the open MCP ecosystem
indexed LIVE from the official registry (registry.modelcontextprotocol.io,
CORS-open, cursor-paginated, 600+ active servers), searchable across both, with
the connect method per entry. Same lazy-island + strip-plugin-allowlist pattern
as ModelsCatalog. One discoverable place for everything Hanzo connects to.
Fix stale landing stats: 157→436 models (the real catalog), 706 'MCP connectors'
→ 600+ MCP servers (the registry we now index), and the prose to match.
Consolidate to ONE way (native forge): build+deploy lives in .hanzo/workflows/
deploy.yml (Hanzo Git → act_runner → BuildKit → ghcr.io/hanzoai/docs → App/docs
→ hanzocd). Gut .github/workflows/deploy-docs.yml to a sync-notice (GitHub is a
mirror; .github is sync-only per the native-forge convention). Point docs-app.yaml
at the native image repo (ghcr.io/hanzoai/docs, matching the live deploy). Delete
docs-cd-rbac.yaml (the GitHub-Actions-runner App-patch RBAC — dead now that the
build is native). Removes the duplicate/buggy CF-Pages + GitHub-build layers.
Follow-up: this line existed only on the remote lineage (not local main),
so it wasn't covered by the prior brand pass.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Purge "LLM gateway" / "unified proxy" / vs-LiteLLM framing across all
Hanzo-authored docs, marketing, and skill copy per SDK-ARCHITECTURE brand
rules. Hanzo is a full AI SDK / AI cloud, not a proxy.
- "LLM Gateway" → "AI Gateway"; hero/positioning copy → "one API for every
model". "unified proxy"/"unified gateway" removed from Hanzo copy.
- Drop "Fork of LiteLLM" / LiteLLM-as-backbone positioning. Keep genuine
third-party LiteLLM integration docs, the bot's own WebSocket Gateway
protocol, and functional config keys (litellm_params, LITELLM_MASTER_KEY)
intact.
- SDK links → canonical homes: zen-docs API table (go get
github.com/hanzo-go/sdk, pip install hanzo, npm i @hanzo/ai, cargo add
hanzo); org preset SDK entries point js-sdk→hanzo-js/sdk,
python-sdk→hanzoai/python-sdk (flagship).
Generated/synced trees (apps/spec/content/docs HIP corpus and
projects/hanzoai/bot, both gitignored) are out of this repo's committable
scope — their brand fix belongs in the source repos.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
docs.hanzo.ai ships as a static export (hanzoai/static) with no server, so the
AISearch widget's /api/chat route can never run in prod. Stream the gateway
directly from the browser with @hanzo/ai createAiClient
(POST api.hanzo.ai/v1/chat/completions, model enso) using a publishable key from
NEXT_PUBLIC_HANZO_CHAT_KEY -- never a server secret. The bespoke provideLinks
source cards and "Powered by Hanzo AI" header are unchanged.
- lib/hanzo/use-chat.ts: useChat-shaped hook over @hanzo/ai; streams text +
accumulates the provideLinks tool call; fail-secure on missing key / errors
- components/ai/search.tsx: swap the @ai-sdk/react transport for useHanzoChat
- lib/hanzo/client.ts: point chatEndpoint at the gateway root (the SDK appends
/v1/chat/completions); add chatKey + chatModel
- components/registry/index.ts: treat lib/hanzo/* as host-provided infra
- package.json: add @hanzo/ai ^0.2.2
Answering is balance-gated: fund the hanzo-docs org wallet, mint a pk, and set
NEXT_PUBLIC_HANZO_CHAT_KEY in the static deploy env.
Pass MeetHanzoMenu a resolveHref that maps ecosystem product ids → their docs
paths (models→/docs/services/models, agents→/docs/agents, mcp→/docs/mcp,
gateway→/docs/llm, api→/docs/api, keys→/docs/api-keys) so the top-nav items keep
users IN the docs instead of bouncing to hanzo.ai marketing. Forward-compatible:
a no-op on the current shell (prop lands in @hanzogui/shell next publish), and
next.config ignoreBuildErrors makes the unknown prop safe until then.
User flagged too many monogram fallbacks. Add real logos for hanzo (the Hanzo
brand mark, converted to currentColor so it themes), poolside, ai21, aion-labs,
inception, kwaipilot, meituan, morph, relace, xiaomi — from @hanzoai/icons +
@hanzo/brand. Remaining monograms are genuine community fine-tuners with no
brand mark anywhere (gryphe, sao10k, thedrummer, undi95, …).
User flagged too many monogram fallbacks. Add real logos for hanzo (the Hanzo
brand mark, converted to currentColor so it themes), poolside, ai21, aion-labs,
inception, kwaipilot, meituan, morph, relace, xiaomi — from @hanzoai/icons +
@hanzo/brand. Remaining monograms are genuine community fine-tuners with no
brand mark anywhere (gryphe, sao10k, thedrummer, undi95, …).
THE real reason the catalog never rendered: remarkPassthroughUnknownJsx
(source.config.ts) fires on content/docs/services/ and converts EVERY PascalCase
JSX element to an empty fragment (<></>) to neutralize foreign Mintlify/Docusaurus
JSX in ported docs. It was silently gutting first-party <ModelsCatalog/> at
compile time in every build — which is why it serialized to $undefined, never
hydrated, and never fetched, despite 200s and passing the export gate.
Add a FIRST_PARTY_JSX allowlist (ModelsCatalog) the strip skips — a unique name
no upstream platform ships, so it can't reintroduce the API collisions the strip
guards against. Verified in the compiled output: <ModelsCatalog/> is preserved
(not <></>), $undefined is gone, and the skeleton (animate-pulse/aria-busy)
renders in the static export.
Also keep the component as a dynamic() client island (preview/lazy.ts) imported
into getMDXComponents — the proven GraphView pattern for a clean client boundary.
The catalog was registered only via getMDXComponents, but in this Fumadocs
static-export pipeline a local 'use client' component referenced that way
serialized to $undefined during SSG — so <ModelsCatalog/> rendered NOTHING and
the client subtree failed to hydrate (React #418), the useEffect never fired,
and no /v1/models fetch happened. The catalog silently never rendered despite
the page returning 200. Import it directly in the MDX (the repo's established
pattern for client components, e.g. cart-provider) so the reference resolves.
Vendor 29 mono brand logos (currentColor SVG) from @hanzoai/icons — OpenAI,
Anthropic, Google, Qwen, Mistral, DeepSeek, NVIDIA, Meta, Cohere, Perplexity,
xAI, Amazon, Microsoft, HuggingFace, Zhipu, MiniMax, Moonshot, and more —
inlined as strings so the static export needs no runtime dep or CDN. ProviderChip
renders the real logo when available, monogram chip otherwise (long-tail
community providers with no brand mark). Keyed by normalized provider name.
Reframe /docs/mcp around the unified server (the user-facing vision): one
'hanzo' MCP added to Claude Code/Cursor exposes 13 HIP-0300 action-routed tools
+ cloud services (IAM/commerce/storage/gateway) + linked connectors (GitHub,
Slack, Google, Discord, X). Adds the client setup (claude mcp add / mcpServers
json) and documents the real tool index — GET api.hanzo.ai/v1/tools, 1,468 tools
across builtin/skill/connector/agent/function. Fixes the stale '260+ tools'
claim. Keeps the MCP-as-a-Service hosting section below.
Each provider group gets a stable monogram chip (deterministic tint from the
name), so the 59-provider / 436-model catalog has per-provider visual identity
like OpenRouter — self-contained (no external logo assets, works in the static
export), theme-legible, and uniform across every provider incl. the long tail.
Hanzo families keep their lucide glyphs.
api.hanzo.ai/v1/models now serves the full 378-model all-providers catalog
(was a 35-model do-first subset). Group the ~343 non-Hanzo models BY PROVIDER
(OpenAI, Anthropic, Google, Qwen, …) sorted by count, instead of dumping them
in one 'More models' table — so the catalog reads like OpenRouter. Hanzo
families (Enso/Zen) stay curated up top. Name falls back to id for third-party
rows (fullName null upstream).
Hero + docs home pitched 'eight movements' — obscure musical metaphor that
undersells (the platform is more than 8 buckets). Reframe: name the value
(identity, inference, data, observability, commerce), drop the '8 Domains'
stat, and lead the domain-cards section with 'One binary. The whole platform.'
Domain cards stay (they're the IA); 'domains' matches capabilities.yaml.
docs.hanzo.ai/docs/services/models now RENDERS the full catalog inline —
fetches api.hanzo.ai/v1/models at runtime and shows every model grouped by
family (Enso/Zen/…) with context window, input/output price per 1M tokens,
capabilities, and copy-to-clipboard ids. OpenRouter-style, always current
(static export, live data), zero link-out.
Rips the stale hand-written page (claimed '376+ models from 58 providers'
with fabricated ids like zen4-pro/openai-gpt-5-nano and made-up prices) and
replaces it with the real 35-model gateway catalog + honest usage snippets.
New <ModelsCatalog/> registered in getMDXComponents (SSG-safe: renders a
skeleton at build, hydrates + fetches on the client).
- Mount AISearch panel + floating "Ask AI" trigger in the home layout
(parity with /docs) so the landing page has it too.
- Default the docs-AI model to `enso` (was zen-coder-flash/zen5) —
matches hanzo.chat/hanzo.app; override via HANZO_AI_MODEL.
Fresh buildId also busts the cached "Powered by Inkeep AI" chat chunk
(the Inkeep rebrand shipped in 7ed5e4c but lingers in already-open tabs).
docs.hanzo.ai's AI chat now runs entirely on our own stack. The live
/api/chat route was already native (Hanzo gateway) but ungrounded — it
now retrieves from our rag-api index before answering, and cites sources:
- retrieval: rag-api /query — native index over the docs
- generation: Hanzo gateway (api.hanzo.ai/v1, zen-coder-flash)
- sources: provideLinks tool, populated from the indexed metadata
Purged Inkeep repo-wide (only our stack, one way):
- removed the dead third-party Inkeep handler (lib/inkeep -> lib/ai)
- widget credit "Powered by Inkeep AI" -> "Powered by Hanzo AI"
- create-app generator: dead `inkeep` provider -> native `hanzo`
(installs the ai/hanzo registry bundle; INKEEP_API_KEY -> HANZO_API_KEY)
- 4 legacy *-docs apps: de-Inkeeped schema, fixed dangling imports
Zero `inkeep` references remain in the codebase.