One file per repo, three names for it. The names exist because different tools look for different filenames; the CONTENT existing three times is how they drift, and a drifted agent guide is worse than none — it is confidently wrong. Where a name already held the only guide, that file BECAME LLM.md byte for byte rather than being replaced by a copy, so nothing was rewritten or lost. Repos where two names held genuinely DIFFERENT guides were skipped, not merged: symlinking there would delete one of them, and choosing which paragraphs survive is not a sweep's decision. Co-authored-by: Hanzo Dev <[email protected]>
3.7 KiB
hanzo-starter — agent notes
The canonical Hanzo app starter and the reference the hanzo.app builder forks.
Vite + React 19 + @hanzo/gui (UI) + @hanzo/iam (auth) + @hanzo/base (data).
Keep it minimal and REAL — every surface must build and run, no fabricated UI.
One way, decomplected
- Providers (
src/providers.tsx) mount in the canonical order every Hanzo surface ships:GuiProvider→IamProvider→BaseProvider.BaseProvidergets aBaseClientcarrying the IAM access token; it is rebuilt when the token changes (src/lib/base.tsbaseAs). That single seam is what makes everyuseQuery/useMutationorg-scoped to the signed-in user. - Env is one place (
src/env.ts), read fromimport.meta.env.VITE_*. - UI is one system —
@hanzo/guiprimitives only (no second kit, no Tailwind). Sign-in/home/notes are the three views.
Gotchas (do not regress)
@hanzo/guiunder Vite needs three things invite.config.ts(it is the Tamagui line; the in-browser builder runtime can't do this, which is the whole reason this ships as a real repo): (1) aliasreact-native→react-native-web, (2)defineprocess.env.TAMAGUI_TARGET/NODE_ENV/__DEV__, (3)dedupereact/react-dom/react-native-web. No Tamagui compiler, noone, no Expo — the optimizer is a perf pass, not a correctness one.@hanzo/guiprops are Tamagui LONGHAND with this v5 config:alignItems/justifyContent/backgroundColor/padding/alignSelf/borderRadius/textAlign— NOT theitems/justify/bg/p/self/rounded/textshorthands. Shorthands pass at runtime but FAILtsc.ButtonusesonPress;Inputusesvalue/onChangeText.- PKCE storage is
localStorage(not sessionStorage) so the verifier/state survive the round-trip to hanzo.id. schema.sqlis the data contract. It is thedatabaseSchemaDDL the deploy translates into Base collections (provisionBaseFromDDL). Keep it in lockstep withsrc/views/notes.tsx.
Deploy contract (Hanzo Cloud)
- Static SPA:
npm run build→dist/, served at<slug>.hanzo.appfrom object storage (the*.hanzo.apppublished-sites edge). No server process. - On publish,
schema.sql→provisionBaseFromDDLcreates the collections (org-scoped, IAM-native). Runtime read/write is browser →VITE_HANZO_BASE_URLwith the IAM token. - IAM redirect registration is the one external requirement: the IAM client
(
VITE_HANZO_CLIENT_ID, defaulthanzo-app) must allow this origin's/auth/callback. Production needs ahttps://*.hanzo.app/auth/callbackwildcard on the shared client (or a per-apphanzo-<app>client).
Proven
tsc --noEmit clean · vite build → dist/ · renders under Vite with zero
console errors · login() performs a real PKCE S256 redirect to
https://hanzo.id/login/oauth/authorize and hanzo.id serves its sign-in form.
Build
CI (.github/workflows/ci.yml) runs npm ci && npm run typecheck && npm run build — build-verification only, NEVER a container image (Hanzo Cloud owns
deploys; do not build images locally).
Working here
Merged from AGENTS.md, which held only this. One rule, one place.
Agent guide
Canonical instructions for this repo live in LLM.md (and its
CLAUDE.md symlink). Read it before changing anything.
TL;DR: Vite + React 19 + @hanzo/gui + @hanzo/iam + @hanzo/base. Keep it
minimal and real. @hanzo/gui needs the react-native-web alias + Tamagui
defines in vite.config.ts and uses Tamagui LONGHAND props (tsc enforces this).
schema.sql is the Base data contract. Prove changes with npm run build
(tsc + vite). Never build a container image locally — Hanzo Cloud owns deploys.