kms.hanzo.ai runs luxfi/kms, which has never served an /api/* route. This
SDK was sending Infisical's: /api/v3/secrets/raw for every secret operation,
/api/v3/auth/login for user auth, /api/v1/auth/kubernetes-auth/login for k8s.
Only one call in the whole package — /v1/kms/auth/login — was ever real.
It stayed invisible because older luxfi/kms builds embedded a console SPA
behind a root catch-all that answered every unmatched path with 200
text/html. A wrong URL came back as a JSON decode error, which reads like a
parsing bug in the client rather than "this endpoint does not exist." That
catch-all is gone (cmd/kms/main.go ends in notFoundJSON), so those paths now
return honest JSON 404s and the SDK fails outright.
The route table is not the only thing that was wrong. The data model was
Infisical's too — project_id, workspace, secret version, secret comment,
shared-vs-personal type — and luxfi/kms has none of those concepts. It keys
one value by (org, path, name, env) in ZapDB at kms/secrets/{path}/{env}/{name}
and a write upserts it in place. Half-migrating would have left response
models that cannot validate what the server sends, so the vocabulary moves
with the paths:
list_secrets(path, env) -> names GET /v1/kms/orgs/{org}/secrets
get_secret(path, name, env) GET /v1/kms/orgs/{org}/secrets/{path}/{name}
put_secret(path, name, value, env) POST /v1/kms/orgs/{org}/secrets (create AND replace)
delete_secret(path, name, env) DELETE .../secrets/{path}/{name}
health() GET /v1/kms/healthz
Two server behaviors now have one home, hanzo_kms/routes.py, shared by the
sync and async clients so they stay mirror images:
- The server splits the trailing path at its LAST slash into (path, name),
so each segment is escaped individually. Escaping the joined string
encodes the separators away and the server reads one long name. A name
containing "/" is rejected outright: it would be written under one key
and read back under another, so the write looks like it succeeded and
the read never finds it.
- There is no versioned read. get_secret(version=N) raises
VersionUnsupportedError rather than quietly returning the current value.
org is new and required — it scopes both the URL and the JWT owner claim.
Constructor field, HANZO_KMS_ORG, defaults to "hanzo".
Auth collapses to what the server actually offers: client credentials
exchanged at /v1/kms/auth/login, or a pre-issued IAM bearer token. The AWS,
Azure, GCP, Kubernetes and SRP methods were Infisical's and none were served.
That also fixes a divergence where the async client silently ignored
HANZO_KMS_TOKEN — env parsing is now one function.
Callers migrated with it: hanzo-cli's `hanzo kms`, the hanzo-tools-kms MCP
tool, and hanzo-tools-auth's session client, all of which were building the
removed auth models and calling the removed create/update pair. Each now
constructs KMSClient() and lets it read the environment.
Tests: pkg/hanzo-kms/tests pins the wire shape — no request URL may contain
"/api/", per-segment escaping survives the server's last-slash split, sync
and async emit byte-identical request lines, and a decoder rejects the
200-HTML/JSON-404 shapes instead of reading them as empty results. Wired into
hanzo-packages-ci without `|| true`, so a regression turns CI red instead of
waiting for a decode error in production.
hanzo-kms 1.1.0 -> 1.1.1.
Co-authored-by: Hanzo Dev <[email protected]>
hanzoai/s3 (SeaweedFS fork w/ consensus+ZAP) is the canonical object
store; the minio pip package and its branding are gone. hanzo-s3 is now
a thin native boto3 adapter exposing a stable surface (S3Client + Bucket/
Object/Stat) so the hanzo s3 CLI and s3 MCP tool are unchanged. Removed
the dead MinioAdmin re-export (no consumer) and all MinIO naming.
CLI (7) + MCP S3Tool (14) tests green; ruff clean.
Closes the last gap in the one-way Hanzo control surface. IAM/KMS/PaaS
already had both CLI subcommands and MCP tools; S3 had neither.
- hanzo s3: buckets/mb/rb/ls/stat/rm/presign over hanzo_s3 (MinIO) client,
creds from env (inject from KMS, never plaintext). Registered in the
unified hanzo CLI alongside iam/kms/paas.
- hanzo-tools-s3: S3Tool MCP tool (same action-dispatch pattern as PaaSTool),
exported via the hanzo.tools entry point; s3 added to loader prefix map.
- uv workspace: map hanzo-cli/iam/kms/s3 + tools-s3 to local sources so the
unified CLI resolves on-disk packages (fixes hanzo_iam ImportError from a
stale published 1.29.0 wheel shadowing local 1.30.0).
Tests: 7 CLI + 14 MCP, all green.
Follow-up to 9c377be (hanzo-iam 1.30.0). Consumer packages now read only
the canonical IAM_ prefix — no upstream-brand alias chain, matching the
new IAMConfig.ENV_PREFIX contract enforced by test_env.py.
Touched modules:
- hanzo-cli: hanzo_cli/auth.py, hanzo_cli/bot/commands.py
- hanzo-tools-auth: hanzo_tools/auth/session.py
- hanzo-tools-iam: hanzo_tools/iam/iam_tool.py
- hanzo: src/hanzo/commands/{auth,iam}.py
- hanzoai: auth.py, llm_client.py
- tests: test_auth_pkce.py (import IAM_CLIENT_ID)
Also adds the generated pkg/hanzo-iam/uv.lock — matches the convention
of the other 17 axis pkgs that track their lockfiles.
Bumps hanzo-iam from 1.29.0 (older Casdoor SDK port) to 1.30.0 with a
purpose-built IAM SDK aligned to the canonical IAM_ env contract.
- ENV_PREFIX="IAM_" only — no HANZO_IAM_ / {ORG}_IAM_ fallback chain.
- IAMConfig.from_env reads IAM_ENDPOINT, IAM_CLIENT_ID, IAM_CLIENT_SECRET,
IAM_ORG, IAM_APP, IAM_CERT, IAM_USERINFO_URL.
- New FastAPI middleware module wraps Casdoor sign-in flow with
request-state user injection.
- 19 unit tests covering env-read, validation, and FastAPI integration.
Consumer packages (hanzo-cli, hanzo-tools-auth, hanzo-tools-paas) bump
their hanzo-iam dep to >=1.30.0.
Tag: hanzo-iam-1.30.0
Add TOML config parser that converts hanzo.toml manifests into PaaS
container API payloads. New `deploy up` command reads hanzo.toml from
CWD and creates or updates containers. Also adds --config flag to
`deploy create` for explicit manifest path. Adds tomli dependency for
Python 3.9/3.10 compat.
Co-authored-by: Hanzo Dev <[email protected]>
The installed @hanzo/bot binary (v2026.2.16) reads OPENCLAW_GATEWAY_TOKEN
for the node run command's token resolution, not BOT_GATEWAY_TOKEN.
Also writes gateway config to bot.json so the config loader picks it up
as a fallback.
Add install, login, logout, run, stop subcommands to `hanzo bot` for
managing local bot agent nodes that connect to gw.hanzo.bot. Browser
OAuth flow authenticates against hanzobot-client-id with dedicated token
storage at ~/.hanzo/bot/token.json. Password grant fallback via
--no-browser flag.
Normalize env var lookup: IAM_ canonical prefix with HANZO_IAM_ accepted
as backwards-compatible fallback via _env() helper in both auth.py and
bot/commands.py.
Every service command (vector, kv, search, doc, events, pubsub, queues,
jobs, secrets, tasks, fn, auto, flow, ml, o11y, cx, growth, platform)
now makes authenticated HTTP calls via shared service_request/check_response
utilities in base.py. No stubs, no hardcoded data, no placeholders.
Bump hanzo 0.4.0→0.4.1, hanzo-cli 0.2.0→0.2.1.
- Add `hanzo bot` command group (status, logs, deploy, env, events) via PaaS API
- Replace all storage placeholders with real boto3 S3 API calls to s3.hanzo.ai
- Rename `hanzo storage` → `hanzo s3` (storage kept as alias)
- Rewrite `hanzo dev` as lazy-install passthrough to @hanzo/dev binary
- Rewrite `hanzo net`/`hanzo node` as passthrough to hanzod binary
- Remove ~350 lines of inline orchestrator/node code in favor of os.execvp()
- Add `hanzo k8s` command group to hanzo-cli that wraps kubectl with
Hanzo-managed auth and default namespace. Uses KubectlGroup that
dynamically proxies unknown subcommands to kubectl (e.g.
`hanzo k8s get pods` -> `kubectl get pods -n hanzo`).
- Remove REPL mode from hanzo wrapper: bare `hanzo` now shows help
instead of dropping into interactive REPL.
- Remove hanzo-ai, hanzo-chat, hanzo-repl entry points.
- Make hanzo-cli a core dependency of hanzo (was optional [cli] extra).
- Remove unused typer dep, move openai/anthropic/prompt-toolkit to
optional extras ([ai], [interactive]).
Co-authored-by: Hanzo Dev <[email protected]>
Run ruff check --fix and ruff format across the repo to fix ~495
auto-fixable lint errors (mostly I001 import sorting) and reformat
225 files to match the py312 target.
Co-authored-by: Hanzo Dev <[email protected]>
Extract _exchange_iam_token method for cleaner auth caching logic.
Fix deploy_env to send full container payload on PUT (PaaS requires it).
Add e2e test scaffold.
Co-authored-by: Hanzo Dev <[email protected]>
- Merged hanzo-cli into main hanzo package (v0.2.4)
- Removed hanzo-mcp-client (using official MCP client)
- Removed empty packages (hanzo-a2a, hanzo-cluster, hanzo-miner, hanzo-tools)
- Added hanzo and hanzo-repl to CI pipeline
- Updated all packages with parallel testing (pytest-xdist)
- Consolidated from 15 to 8 active packages
- Fixed imports and dependencies after consolidation
- All CI tests passing with 111 total tests across 5 packages