zen.id is not a domain we control; use the id.<domain> pattern on the owned
domain (matches id.lux.network / id.zoo.network style). Zoo already correctly
uses zoolabs.id + api.zoo.ngo (no zoo.network).
- brand.ts: one codebase, four ecosystems. HANZO_BRAND selects defaults for
Hanzo (hanzo.id/api.hanzo.ai/hanzo-app), Lux (lux.id/api.lux.network/lux-app),
Zoo (zoolabs.id/api.zoo.ngo/zoo-app), Zen (zen.id/api.zenlm.org/zen-app). IAM
hosts verified against login/middleware.ts tenant map. Explicit
HANZO_IAM_URL/API_URL/CLIENT_ID still override everything.
- endpoints.ts derives defaults from the active brand; CLI name/description are
brand-aware so a fork shows its own identity (white-label rule: never show
another brand).
- forks/{lux,zoo,zen}: thin packages (@luxfi/helper, @zooai/helper, @zenlm/helper)
that set HANZO_BRAND and depend on @hanzo/helper — DRY, no code duplication.
Verified: all four brands resolve correct hosts; all three coding-tool targets
(Claude Code, Claude Desktop, Codex) round-trip configure/unconfigure cleanly.
claude-code.ts: switch from env.ANTHROPIC_* (session hijack) to providers.hanzo
entry — additive, non-destructive. Users switch with /model hanzo/deepseek-v4-pro
without losing the default Anthropic connection. HANZO_MODELS list reflects the
live api.hanzo.ai catalog (Zen + GLM + DeepSeek + Qwen + Kimi + Nemotron).
claude-desktop.ts: new target. Writes mcpServers.hanzo into claude_desktop_config.json.
Config path is platform-aware: ~/Library/... (macOS), %APPDATA%\Claude (Windows),
~/.config/Claude (Linux). API key passed as env var to `npx @hanzo/mcp`.
index.ts: register claudeDesktop in TARGETS.
- Single coherent endpoint model matching the dev CLI: IAM issuer base
https://hanzo.id/v1/iam (HANZO_IAM_URL), all IAM ops issuer-relative
(/oauth/device, /oauth/token, /mint-user-keys, /revoke-user-keys); cloud API
https://api.hanzo.ai for /v1/get-account + inference. Device auth carries
params in the query string with response_type=device_code, matching dev.
- Bare `hanzo` / `npx @hanzo/helper`: runs login+setup when signed out, shows
status when signed in.
- `hanzo login` now offers browser device login OR pasting an existing hk- key;
`--key` supports non-interactive setup.
- White-label override verified (HANZO_IAM_URL/API_URL/CLIENT_ID → lux-app etc).
Verified end-to-end: paste-key → Claude Code settings.json wired correctly.
Verified against the actual Hanzo sources (iam, ai, console2, login):
- Device login (RFC 8628) against hanzo.id /oauth/device + /oauth/token,
form-encoded, client_id hanzo-app, body-keyed pending/slow_down handling.
- API key = the per-user IAM accessKey (hk-): read via /v1/get-account,
self-minted via /v1/iam/mint-user-keys (authorized as self by the login JWT).
- CodingTarget abstraction: one interface, Claude Code (settings.json env) and
Codex (config.toml provider) implementations. Verified round-trip preserves
all unrelated user config.
- Commands: login, use/unuse, auth (status/key/rotate/revoke/logout),
status, models, install (dev/mcp/extension), doctor.
- Endpoints overridable for white-label (HANZO_IAM_URL/API_URL/CLIENT_ID).
- TypeScript 6, tsup bundle, clean typecheck.