29 Commits
Author SHA1 Message Date
zeekayandHanzo Dev 2d6b0cddc7 fix: call the pipeline at the address it actually lives
hanzoai/ci keeps the reusable at .github/workflows/build.yml — the one path
both planes resolve, since github.com reads a reusable only from there and the
forge reads it too. The v1 tag moved with it, so a caller still naming
.hanzo/workflows/build.yml asks for a blob that is not in the tree:

  InsertRun: read hanzoai/ci@v1:.hanzo/workflows/build.yml: object does not exist

The caller itself stays at .hanzo/workflows/cicd.yml on purpose: github.com has
no runner for these labels, so a caller placed there could never be scheduled.

Co-authored-by: Hanzo Dev <[email protected]>
2026-09-08 01:14:28 -07:00
zeekay ff535e2bf9 retire the GitHub Actions workflows
Actions are disabled on this repository, so these files have not run in a long
time and cannot run: they are build definitions no forge executes. Builds go
through the native path -- POST /v1/runner, which schedules a BuildKit job --
and CI lives under .hanzo/workflows. A dead workflow that still looks like a
pipeline is worse than none, because it reads as coverage nobody has.
2026-08-07 09:25:21 -07:00
zeekayandHanzo Dev 7e9f6af9fa ci: canonical pair — hanzo.yml + forge caller
github.com has no runner for hanzo-build-linux-amd64, so a caller under
.github/workflows is a gate that can never be scheduled. This is the ~7-line
caller on the plane that can (git.hanzo.ai git-runner fleet), pinned @v1.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-06 02:31:13 -07:00
zeekay cf813cf917 docs(readme): document the real binary name and stop naming models that do not exist
The command table said `hanzo login`, `hanzo use`, `hanzo unuse`, `hanzo
status`. Two problems: the published bin is `hanzo-helper` (1.0.8), and
`hanzo` is the CLI — a different program — so on a machine with both, every
one of those lines is swallowed by the CLI as an AI task. Table rewritten
against `hanzo-helper --help`, with a line saying why the name is not
`hanzo`.

The smart-tiers table listed zen-auto, zen-normal, zen-pro, zen-max, zen-code
and zen-agent as the routing aliases. None exist. The tiers feature is real —
`models --tiers` is a flag on the shipped binary — so the README now points
at that instead of printing a stale copy of its output. Same for the concrete
ids it suggested (glm-5.2, deepseek-v4-pro) and the "every model (Claude,
GLM, GPT, DeepSeek, Kimi)" line: the catalog is live, so ask it.

Claude Code and Codex stay named — they are what this tool configures.
2026-08-01 13:47:15 -07:00
zeekayandHanzo Dev ccdef7d8fb helper: the command is hanzo-helper — only the native binary is hanzo
@hanzo/[email protected] declared `"bin": {"hanzo": "dist/cli.js"}`, so
`npm i -g @hanzo/helper` put a second program named `hanzo` on PATH next to the
Hanzo CLI (v1.9.18, from hanzo.sh / brew). Whichever came first on PATH won, and
the two disagree about every verb: in the real CLI signing in is
`hanzo auth login`, and a bare `hanzo login` is swallowed as an AI task.

Renamed to `hanzo-helper`, and the same for the white-label builds:
lux-helper / zoo-helper / zen-helper. @hanzo/kms keeps `kms` — no collision.
Nothing is unpublished; 1.0.7 stays on npm.

The README's command table was the old bin name throughout, and its
"smart tiers" table documented `zen-auto` / `zen-normal` / `zen-pro` /
`zen-max` / `zen-code` / `zen-agent` as models you can ask for. The live
catalog has none of them — the authenticated /v1/models returns 105 ids whose
Zen family is zen5, zen5-coder, zen5-flash, zen5-mini, zen5-pro, enso,
enso-flash, enso-ultra plus the zen-<modality> models. Table cut; the README now
says to read the catalog. (`models.ts` already checks aliases against the live
catalog before printing them, so the code was honest and only the prose was not.)
`use --model` help stopped advertising the same six words.

In-program prose said `hanzo login` / `hanzo status` / `hanzo kms` in 15 files —
all now `hanzo-helper`, verified by running the built CLI.

Also dropped "every model (Claude, GLM, GPT, DeepSeek, Kimi, ...)" from the
opening: we describe our own catalog. Naming Claude Code and Codex stays — this
program's whole job is configuring them, which is a fact about the tool, not a
benchmark.

Left alone, for the model-routing owner: DEFAULT_MODEL is still the upstream id
`glm-5.2`, which commander prints as the advertised default of `--model`.

Co-authored-by: Hanzo Dev <[email protected]>
2026-08-01 13:38:01 -07:00
zeekay 09a6ade307 ci: remove GitHub CI — native git.hanzo.ai + cd.hanzo.ai only
This workflow ran on a self-hosted actions-runner-controller pool. ARC is
decommissioned: CI executes inside git.hanzo.ai (Gitea Actions, .hanzo/workflows)
and delivery is cd.hanzo.ai reconciling the reviewed image pin in
hanzoai/universe. GitHub is a mirror and runs nothing.

Removed rather than repointed — there is no GitHub-side pool to move to, and
leaving it would keep ARC load-bearing.
2026-07-27 08:07:55 -07:00
zeekay 47c3a2b63a fix(claude-code): curated model picker always includes the selected model
The claude-code target listed a hardcoded HANZO_MODELS set (glm-5.2,
deepseek-v4-flash, deepseek-v4-pro, zen5-max — all verified routable) but
dropped the user's actual selection if it wasn't among them. Merge creds.model
in and dedupe so the picker never omits the chosen default, while keeping the
short curated list (the live catalog carries 60+ ids). Also add the missing
ClaudeSettings.model type and drop the redundant 'ultra' effort alias (== max).

v1.0.7
2026-07-03 11:18:53 -07:00
zeekay 7c9e87336e fix: KMS on its own host (kms.<brand>), stable doctor probes
Live infra drift (gateway redeploy): api.hanzo.ai/v1/kms is NOT proxied (404),
and the bare /health path moved (/health 404, /v1/health 200). Two fixes:

- KMS runs on its dedicated host kms.<brand> (kms.hanzo.ai, per IAM's per-brand
  KMSHost). Added brand.kms + endpoints.kms (HANZO_KMS_URL override); KMS client
  targets it instead of api.hanzo.ai/v1/kms. Verified live: kms.hanzo.ai/v1/kms/
  orgs/hanzo/secrets → 401 (gated, live).
- doctor now probes the STABLE endpoints the tool actually depends on — IAM
  /.well-known/openid-configuration + api /v1/models — not a bare /health that
  varies by gateway config. Both 200.
- kms-secrets action base-url default → kms.hanzo.ai.

Release 1.0.6 (helper + @hanzo/kms + lux/zoo/zen forks).
2026-06-30 22:37:29 -07:00
zeekay 211c8447a1 fix: npx regression + version drift; add standalone @hanzo/kms package
Two real bugs:
- npx @hanzo/helper broke when the kms bin was added — a package with TWO bins
  can't be run by 'npx <pkg>' (could not determine executable). Reverted helper
  to its single 'hanzo' bin; kms stays as 'hanzo kms' AND as its own package.
- version.ts was hardcoded '1.0.0' — 'hanzo --version' always lied. Now injected
  from package.json at build (tsup define __HANZO_VERSION__), one source of truth.

- packages/kms: new standalone @hanzo/kms (single 'kms' bin) that re-runs the
  helper's kms CLI via the new ./kms-cli export. npm i -g @hanzo/kms → 'kms'.
- exports: add ./kms-cli so the standalone package imports it cleanly.

Published: @hanzo/[email protected], @hanzo/[email protected], @luxfi/@zenlm/@zooai/[email protected].
2026-06-30 21:36:08 -07:00
zeekay 5181ec9b51 release: forks → 1.0.3 (match @hanzo/helper); normalize fork package.json
Bump @luxfi/@zenlm/@zooai/helper to 1.0.3 with @hanzo/helper ^1.0.3 (picks up
the get-account/health endpoint fixes + kms login). npm pkg fix: bin paths and
repository URL normalized so publishes are warning-free.
2026-06-30 21:30:55 -07:00
zeekay 2c47892c4b fix: correct account + health endpoints (get-account 404, /v1/health 404)
Three live-verified endpoint bugs, all where a call hit the wrong host/path:

- readApiKey + fetchUser hit api.hanzo.ai/v1/get-account (404). The account read
  lives on the IAM issuer: {iam}/get-account (…/v1/iam/get-account, 200). Same
  base as mint/revoke. Added IAM_PATHS.account.
- fetchUser also parsed the account at the top level, but GetAccount wraps it in
  a { status, sub, name, data, data2 } envelope — email/owner are under data, so
  org came back EMPTY (which kms pull needs). Now reads data.{email,owner,...}.
- doctor: api /v1/health (404) -> /health (200); iam /api/health -> /health
  (drop the /api/ prefix per house style).

Verified live: hanzo doctor now green (IAM 200, Cloud API 200); models table,
--tiers, and detail all work. Release 1.0.3.
2026-06-30 17:55:38 -07:00
zeekay 85aac13802 release: @hanzo/[email protected] (kms login + pull live on npm) 2026-06-30 17:37:24 -07:00
zeekay 66ee6f5bc3 kms: standalone login so 'kms pull' works self-sufficiently
The gap behind 'kms pull must work' was that the standalone kms had no way to
sign in — and an hk- API key can't auth to KMS (it needs an IAM JWT the KMS
verifies against hanzo.id JWKS). Fix: one device-login primitive, every door.

- lib/signin.ts: deviceSignIn() — the RFC 8628 flow against hanzo.id, persists
  accessToken + user to the shared ~/.hanzo/config.json. Extracted from login.ts.
- kms-cli.ts: 'kms login' + pull/list. Self-sufficient standalone tool.
- auth.ts: 'hanzo auth login' — same session.
- login.ts: browserLogin now composes deviceSignIn + key mint (DRY).

One token store: sign in via kms login, hanzo login, or hanzo auth login — all
write the same session, so kms pull works after any of them. Verified live:
kms login returns a real device code from hanzo.id.
2026-06-30 17:36:55 -07:00
zeekay 29b6cd166f kms: use the canonical live KMS API, drop invented endpoints
KMS already serves the one-way secret surface (hanzoai/kms embed.go): the dev's
IAM login token goes straight to /v1/kms/orgs/{org}/secrets — KMS verifies it
against hanzo.id JWKS (authorize + canActOnOrg). No /v1/kms/oidc/login or
/v1/kms/get-secrets exchange (those were invented; they 404). One token, one way.

- lib/kms.ts: listSecrets + getSecret + pullSecrets over the real endpoints.
  Respects KMS's security boundary — list returns KEYS ONLY; values are read
  one-by-one (bounded concurrency), no bulk-value dump.
- commands/kms.ts: org comes from the login session (--org override); IAM token
  from config.accessToken. pull/list unchanged in UX.
- actions/kms-secrets: same canonical list-then-get; token input is an
  IAM-issued token KMS trusts (GitHub OIDC only if KMS trusts that issuer).
- npm-release.yml: pass org=hanzo + KMS_IAM_TOKEN.

Verified: GET /v1/kms/orgs/hanzo/secrets?env=devnet is LIVE (401, gated) on
api.hanzo.ai — endpoint exists, needs a real IAM token to list.
2026-06-30 17:31:16 -07:00
zeekay 5abfd085e1 kms: get-secrets (verb-noun, matches /v1/iam/get-account house style) 2026-06-30 14:18:27 -07:00
zeekay 19de01901b kms: dev secrets via the one OIDC mechanism (IAM issues, KMS owns)
A developer's `hanzo login` already mints an IAM OIDC token; `kms pull --env
devnet` exchanges it for a short-lived KMS token and writes a local .env. Clean
orthogonal separation — IAM is a pure issuer (/v1/iam), KMS owns secrets/envs/
authz (/v1/kms); they compose through the token, neither imports the other. No
broker, no /api/, no compound words (oidc, not oidc-auth).

- src/lib/kms.ts: kmsLogin + kmsSecrets + pullSecrets over /v1/kms/oidc/login
  and /v1/kms/secrets; tolerant of {K:V} or [{secretKey,secretValue}] shapes.
- src/commands/kms.ts + src/kms-cli.ts: `hanzo kms` and standalone `kms` bin —
  one implementation, two entry points. pull/list, env devnet|testnet|mainnet|
  production (default devnet), dotenv out.
- CI shares the SAME mechanism: .github/actions/kms-secrets loads secrets via a
  GitHub OIDC token through /v1/kms/*; reusable .github/workflows/npm-release.yml
  publishes any package with NPM_TOKEN from KMS (self-hosted runners, no
  long-lived token in GitHub); release.yml ships helper + forks on tag.
- DRY: dev and CI use one /v1/kms exchange; one login, one token store.
2026-06-30 14:16:11 -07:00
zeekay c3e378aa5a v1.0.1: expose ./cli subpath so brand forks can import the CLI
The forks (@luxfi/@zenlm/@zooai/helper) re-run our CLI with HANZO_BRAND set,
but exports only published '.', so import('@hanzo/helper/dist/cli.js') failed
with ERR_PACKAGE_PATH_NOT_EXPORTED. Add a stable './cli' export and point the
forks at @hanzo/helper/cli (not a deep dist path). Bump fork deps to ^1.0.1.
Fix stale zoo.id → zoolabs.id comment.

Published: @hanzo/[email protected], @luxfi/[email protected], @zenlm/[email protected],
@zooai/[email protected].
2026-06-30 13:42:45 -07:00
zeekay 15f1777c6b default model glm-5.2; Claude Code sets top-level model to the Hanzo default 2026-06-30 13:32:55 -07:00
zeekay 6f7fe9799f models: rich live catalog from pricing.<brand>/v1/pricing/models
hanzo models now renders the same rich data as the console Models page —
provider (normalized: glm→Zhipu, qwen→Qwen, Zen first-party), plan tier,
context window, params/arch, and input/output $/Mtok — joined with your live
routing set for honest availability. Catalog ids are OpenRouter-style for
third-party (z-ai/glm-5.2); the routing id is the last path segment, so the
join keys on {id, name, last-segment} and each row shows the id you actually
pass to --model. Adds `hanzo models <name>` detail view + --all; falls back to
the plain id list if the catalog is unreachable. Pricing host derives from the
brand site (pricing.<host>), white-label correct.
2026-06-30 13:17:52 -07:00
zeekay 20fc8642ad package: publishConfig.access=public for scoped first publish 2026-06-30 12:44:07 -07:00
zeekay 506c178b30 Dynamic cloud catalog + smart tiers + one-command ecosystem installer
- models: read the catalog live from api.hanzo.ai/v1/models; nothing hardcoded.
  Effort words (auto/fast/high/max/code/agent) are sugar over the cloud's own
  zen-* routing aliases — the cloud picks the concrete model. Default = zen-auto.
- claude-code: write the live model list into providers.hanzo (was a static array).
- credentials carry the live model list so configure() stays sync + orthogonal.
- config: honor HANZO_API_KEY env so the CLI works headless / in CI.
- ecosystem: one data-driven registry (dev, mcp, node, desktop+Enso, extension,
  ide, slack, github); 'hanzo install' checklist + per-component npm/guide runner.
- login wizard offers ecosystem setup as its final out-of-box step.
- add eslint flat config (deps were present, config was missing); lint clean.
- brand: add public web root (site) so fork install links white-label correctly.
2026-06-30 12:43:52 -07:00
zeekay 9e8c057be0 Drop local .claude/settings.local.json from tracking; gitignore .claude/ 2026-06-29 15:27:10 -07:00
zeekay 84e62b5d69 Two install modes, model tiers, providers-based Claude Code config
- Two install targets, user picks (or --mode shell|tools):
  * tools  — additive providers.hanzo block in tool config (Claude Code /
    Codex / Claude Desktop); keeps the default Anthropic login intact, switch
    per-session with /model hanzo/<model>. This is how Claude Code reads a
    custom provider (verified against a live ~/.claude/settings.json).
  * shell  — managed export block in the detected shell rc (zsh/bash/fish):
    ANTHROPIC_BASE_URL + ANTHROPIC_AUTH_TOKEN + ANTHROPIC_MODEL → Hanzo becomes
    the default for every Anthropic-compatible tool. Sentinel-delimited;
    install/uninstall round-trip preserves all other rc content (tested).
- Friendly model tiers → live ids (all verified against api.hanzo.ai/v1/models):
  default=glm-5.2, flash=deepseek-v4-flash, pro=deepseek-v4-pro,
  ultra=qwen3.5-397b, max=zen5-max. resolveModel() accepts a tier or a raw id;
  wired into login/use; `hanzo models --tiers` shows the map.
- Default model is glm-5.2 (fast all-rounder, works on both /v1/chat/completions
  and /v1/messages). Zen models confirmed live (zen5-pro returned exact output).

Verified live: tier 'pro' → deepseek-v4-pro → real completion.
2026-06-29 15:27:02 -07:00
zeekay a5a45126fe feat(models): expand HANZO_MODELS to full zen5 ladder + new DO-AI models 2026-06-29 15:23:43 -07:00
zeekay b7d7372209 brand: Zen login host is id.zenlm.org (we own zenlm.org, not zen.id)
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).
2026-06-29 15:14:42 -07:00
zeekay ddf1b1779d Add brand white-labeling + lux/zoo/zen fork scaffolds
- 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.
2026-06-29 15:09:16 -07:00
zeekay 8cf9e4ba70 feat(targets): providers-based Claude Code config + Claude Desktop for all platforms
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.
2026-06-29 15:08:24 -07:00
zeekay 8d3a4fda76 Align helper to canonical /v1/iam issuer + add bare-invoke and paste-key flows
- 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.
2026-06-29 15:03:55 -07:00
zeekay f53ee829f6 Rebuild @hanzo/helper around real hanzo.id device login + coding-tool config
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.
2026-06-29 13:57:59 -07:00