Commit Graph
633 Commits
Author SHA1 Message Date
zeekay aad145dec0 Name the generator we actually run
Our SDKs are generated by openapi-generator on our own CI. The docs said a
hosted third-party service, which we retired: hanzoai/openapi's LLM.md and its
regenerate-sdks.yml both already said so, while its README still called that
service "canonical" and told a reader to fetch an API key for it out of KMS.

Two sources disagreeing is how somebody follows the wrong one, and the wrong one
here sends them looking for a credential that should not exist.

The same claim had spread to what customers and agents read: five pages on
docs.hanzo.ai and six agent skills advertised a vendor we do not use, and
hip-0040 -- the standard for multi-language SDKs -- argued FOR it by name. The
argument survives without the brand, because it was never about the vendor: one
spec beats N hand-written clients. python-sdk's mock script also pulled that
vendor's fork of prism-cli; it takes upstream @stoplight/prism-cli now.

What is deliberately left alone is every occurrence that is not about us: a
filament material in a 3D-printer integration, a browser of that name in three
user-agent parsers, tokenizer vocabulary where the string is a token id, and
citations recording where Mux, Perigon and Stigg publish their own specs.
Renaming any of those breaks something real.
orphan/pre-align
2026-08-13 14:30:19 -07:00
zeekay 6d5dc78fcb Report vulnerabilities to us, not to the upstream we forked
This repo is a fork, and its SECURITY.md still carried the upstream's contact —
so a researcher who found a hole in what WE ship was told to mail a vendor who
cannot fix it, and who would then know about a live vulnerability in our
production before we did.

Fourteen repos were in that state: datastore -> [email protected], git and
its two worktrees -> [email protected], auto -> [email protected],
calendar -> [email protected], dns -> [email protected], python-sdk ->
[email protected], plus bot, gui-gates, gui-geist, playground and
playground-oauthcb pointing at brand domains with no mailbox behind them.

All of them now carry one policy and one address, [email protected], matching
what cloud and gateway already used. The policy says out loud to report here
rather than upstream, because the next fork will inherit the same file and the
same instinct.
2026-08-13 14:29:13 -07:00
zeekay 4afc34a41c merge(feat/browser-zapd-autospawn): consolidate onto main 2026-07-21 17:18:50 -07:00
zeekay 72684151a7 chore(hanzo-flags): commit uv.lock 2026-07-19 20:02:48 -07:00
zeekay 21966d79d0 feat(tools): hybrid local+cloud tools -- HanzoCloud client, cloud code/vector actions, vision
Adds a shared HanzoCloud client (core/cloud.py; lazy httpx, api.hanzo.ai /v1)
and wires the cloud half of the hybrid tools: code gains cross-repo
search/context/ask/index over the cloud index, vector gains a cloud-backed
store plus an infinity-embedded local option, net gains a vision tool. Bumps
hanzo-tools 0.3.2->0.3.3, -code 0.1.2->0.1.3, -net 0.1.2->0.1.3, -vector
0.2.0->0.2.1 and declares httpx where the cloud path is used. New tests cover
the code/net cloud actions. import hanzo_tools.core is green.
2026-07-19 20:02:48 -07:00
b780f68da8 fix(generate): authenticated spec fetch — hanzoai/openapi is private (#49)
raw.githubusercontent.com/hanzoai/openapi/main/hanzo.yaml 404s (openapi is a
private repo), so every spec-update regen failed at the fetch. Fetch hanzo.yaml
through the GitHub Contents API with a SPEC_TOKEN (repo/contents:read on
hanzoai/openapi) instead. Local SPEC=... override unchanged.

Co-authored-by: zeekay <[email protected]>
2026-07-18 12:31:17 -07:00
zeekay 81dce282a5 hanzo-flags: the Python client for the native flags engine
Flags were natively supported in Rust (the hanzo-flags crate — the evaluation
core, pub-exported for Rust callers and FFI-exported for the rest), Go (in-process
via CGO to that core), and TypeScript (@hanzo/flags over /v1/flags). Python was the
gap. This closes it.

hanzo-flags POSTs an evaluation context to cloud /v1/flags — the same
PostHog-compatible endpoint every other client speaks — and answers is_enabled /
variant / payload from the response. It mirrors @hanzo/flags exactly: a HanzoFlags
client bound to one host, load(distinct_id, person_properties=, groups=), the same
three-field result, an async twin, and a one-shot evaluate().

Two invariants match the family: fail-open (a transport error yields the last good
or empty result with errors_while_computing set, never a raise on the hot path)
and cache-by-context+TTL. Zero runtime dependencies — stdlib urllib only, so a
flag check never drags httpx/pydantic into a service.

Tests stand up a local /v1/flags stub and prove the request shape is
PostHog-compatible, the accessors resolve booleans/variants/payloads, the TTL
cache holds, and both a 5xx and an unreachable host fail open. 7/7 green.
2026-07-17 13:00:33 -07:00
zeekay 44edb35d63 feat(hanzo-train): add Tinker-shaped training client (0.1.0)
Hand-written package for the engine /v1/training API: ServiceClient +
TrainingClient (create/list/get/delete/forward_backward/optim_step/
sample/save_weights), dataclasses, sync httpx, completed-future
.result() wrapper so tinker fut.result() code ports 1:1. 22 pytest
tests over httpx.MockTransport, no network.

Wired like siblings: publish-pypi hanzo-train-* tag case, rye+uv
workspace member, uv source, pyright exclude. uv.lock relock also
catches the lockfile up to on-disk truth (hanzoai 3.1.1,
hanzo-tools-browser 0.5.10) -- no package versions changed.
2026-07-15 18:16:32 -07:00
zeekayandHanzo Dev 459942b34d ci: route linux/amd64 jobs to hanzo-build-linux-amd64 ARC scale set
Co-authored-by: Hanzo Dev <[email protected]>
2026-07-10 21:51:56 -07:00
zeekay 1ca5ccadc3 release(hanzo-tools-browser): 0.5.10 — zapd connect-or-spawn auto-start 2026-07-08 08:50:48 -07:00
zeekayandGitHub 0b45461a6f feat(browser): auto-start zapd when absent (connect-or-spawn) (#47)
The browser MCP tool no longer requires a human to have started zapd.
ZapdConsumer.connect() now dials the router and, on failure, auto-starts
the shared singleton (locate the zapd binary, spawn it detached, wait for
the socket) then dials once more — mirroring zapd's own host-mode
connect-or-spawn. No consumer-side lock: the singleton invariant lives in
zapd (advisory-lock bind), so concurrent spawns are safe. The OS unit is
the primary starter; this is the bare-machine fallback so the tool just
works.
2026-07-08 08:49:21 -07:00
zeekay 6cb5821ebb feat(browser): auto-start zapd when absent (connect-or-spawn)
The browser MCP tool no longer requires a human to have started zapd.
ZapdConsumer.connect() now dials the router and, on failure, auto-starts
the shared singleton (locate the zapd binary, spawn it detached, wait for
the socket) then dials once more — mirroring zapd's own host-mode
connect-or-spawn. No consumer-side lock: the singleton invariant lives in
zapd (advisory-lock bind), so concurrent spawns are safe. The OS unit is
the primary starter; this is the bare-machine fallback so the tool just
works.
2026-07-08 08:36:14 -07:00
zeekay f7511ac282 fix(hanzoai): 3.1.1 — guard optional ZAP import so import hanzoai works without the [zap] extra
zap.py is an httpx.BaseTransport; httpx is not a base dep (client core is urllib3).
3.1.0 imported zap.py eagerly in __init__, so `import hanzoai` crashed on missing
httpx in any clean install. Guard the import (try/except ImportError) and declare
httpx under the [zap] extra. import hanzoai now works with or without extras.
2026-07-05 19:49:03 -07:00
zeekay 3e22e2c016 release(hanzoai): 3.1.0 — opt-in ZAP-native transport 2026-07-05 19:20:31 -07:00
1f05cff4f5 feat(hanzoai): optional ZAP-native transport (opt-in, public API unchanged) (#46)
Add hanzoai.zap: an httpx.BaseTransport / AsyncBaseTransport that routes the
SAME typed client calls through hanzo_zap.CloudClient over the ZAP binary wire.
Opt in with Hanzo(http_client=hanzoai.zap_http_client(...)); default stays HTTPS.

- hanzo-zap is an optional extra [zap], imported lazily so "import hanzoai"
  still works when it (and zap-proto) are not installed.
- Public __all__ is byte-identical; new names are additive and kept out of __all__.
- Request to ZAP mapping: path to dotted method, api-key header to Bearer auth,
  body forwarded verbatim.
- Tests: back-compat lock + request-translation via mock CloudClient (no network).

Co-authored-by: hanzo-dev <[email protected]>
2026-07-05 19:18:09 -07:00
zeekay f66cbfff8a fix(workspace): complete member set — install real toolset, fix 20 integration failures
The uv workspace listed only 10 of 61 packages as members, so `uv sync`
never installed fs/shell/agent/reasoning/lsp/refactor/todo/jupyter/memory —
and hanzo-tools-core's integration suite (which asserts each imports with an
exact TOOLS count) failed 20 tests against the absent packages. Add the 9
required tool packages as members + [tool.uv.sources] workspace pins so the
real toolset installs and the suite validates live code. Honest fix — install
what the test asserts, don't weaken the assertions. Suite: 24 passed / 12
skipped (was 20 failed / 4 passed). Lock resolves clean (tree-sitter, tornado,
nbformat added). No regressions: hanzoai 3/3, browser 11/11, hanzo-mcp boots.
2026-07-05 12:11:35 -07:00
zeekay f9dc5d477f fix(workspace): pin hanzo-tools + hanzo-tools-core to on-disk source (kill PyPI shadow)
hanzo-tools-core was a [tool.uv.sources] gap: not a workspace member, so uv
resolved it from PyPI 0.3.0 — the OLD package that still ships the duplicate
hanzo_tools/core/ WITHOUT ToolImage, shadowing canonical hanzo-tools.core and
breaking 'from hanzo_tools.core import ToolImage' (browser tests: 6 fail/5 error).
Add hanzo-tools + hanzo-tools-core as workspace members AND [tool.uv.sources]
= { workspace = true } so both resolve on-disk (0.3.1 empty shim), never the
shadowing wheel. Purge the stale untracked pkg/hanzo-tools-core/hanzo_tools/
build artifact. Finishes the decomplect 8b9e82d9 started. Browser tests: 11/11 green.
2026-07-05 12:07:52 -07:00
zeekay c172ab6c49 fix(hanzoai): restore core SDK modules wiped by #45 regen — unbreaks hanzo-mcp (3.0.1)
#45 regenerated hanzoai as a pure OpenAPI client and DELETED the hand-written
core-SDK modules (config/mcp/session/protocols/…) that live in the same package
but aren't part of API generation. hanzo-mcp imports all four → the published
hanzoai 3.0.0 crashed EVERY hanzo-mcp consumer on startup ('No module named
hanzoai.protocols') → the MCP server wouldn't boot → Claude Code couldn't
reconnect. Restore the 4 self-contained modules hanzo-mcp needs (verified: zero
imports of the removed Stainless internals); they coexist with the generated
api/models client. Left agents/auth/cluster/llm_client OUT — they import the
removed ._client and need migration to the new client (separate follow-up, no
reconnect-path consumer). Bump 3.0.0→3.0.1. Boot-proven: hanzo-mcp starts,
26 tool packages / 29 tools, MCP initialize OK.
2026-07-05 09:50:51 -07:00
zeekay 86eefc092c fix(browser): route MCP register through _result_to_mcp — ToolImage→ImageContent
The browser tool's bespoke register() returned execute()'s dict RAW, so FastMCP
flat-JSON-serialized a screenshot's ToolImage (base64 inline, 250K chars) →
overflowed the agent context and wedged the run — the SAME bug main's
ImageContent converter (8b9e82d9) fixed for every OTHER tool via
BaseTool.register→_result_to_mcp, but the browser tool bypassed that path.
Now both registration paths share the one converter: nested ToolImage anywhere
in the result becomes a native MCP ImageContent block the client SEES. One way.
2026-07-05 04:29:07 -07:00
53c123a3f5 feat(hanzoai): regenerate client from unified OpenAPI spec (retire Stainless) (#45)
Replace the Stainless-generated `hanzoai` client (188 legacy LLM-gateway
endpoints) with an openapi-generator `python` (urllib3 + pydantic v2)
client built from hanzoai/openapi `hanzo.yaml` — the full unified
api.hanzo.ai/v1 surface (493 API groups, 1710 models, all /v1 products).

- scripts/generate.sh: the one-way generator; emits only pkg/hanzoai
  (other pkg/hanzo-* packages untouched).
- pyproject: deps -> urllib3 / python-dateutil / pydantic>=2 /
  typing-extensions; version 2.2.3 -> 3.0.0 (breaking surface change).
- tests/: Stainless client tests replaced with a surface smoke test.
- .github/workflows/generate.yml: regenerate on openapi spec-update.
- Base URL https://api.hanzo.ai, Bearer hk- / JWT auth.

Verified: wheel hanzoai-3.0.0 builds, installs into a clean venv, and
`import hanzoai` + product API construction succeed.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-04 20:07:32 -07:00
zeekay f3db3d33fd Merge branch 'chore/ui-rag-v1-paths'
# Conflicts:
#	pkg/hanzo-tools-browser/hanzo_tools/browser/browser_tool.py
2026-07-04 13:59:42 -07:00
zeekay 2738527a5a fix(browser): screenshots/pdf save-to-disk + return path, never inline huge base64
A full-page PNG returned as inline base64 (100K+ chars) overflows an agent's
context window and wedges the whole run — the #1 cause of 'the browser tool
hangs' (two mobile-QA agents died on 6.6MB transcripts). Both capture paths
(native-zap _extension_command + the playwright fallback) now persist to
~/.hanzo/screenshots (or a caller path) and return a compact {path,size};
base64 is inlined ONLY for a small PNG (<=40KB). Adds _save_capture + _extract_b64.
2026-07-04 12:33:52 -07:00
zeekayandHanzo Dev 1ab641d393 fix(billing): drop extraneous /api prefix — api.hanzo.ai/v1/billing
The billing tool hardcoded api.hanzo.ai/api/v1/billing (double prefix). Per
the /v1-only canonical API contract, the gateway serves everything under bare
/v1/* — never /api/. Scrub to api.hanzo.ai/v1/billing.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-03 12:31:09 -07:00
zeekayandHanzo Dev 3214c798a5 browser/zapd_consumer: self-heal a dead cached socket
connect() trusted a cached ZapClient forever; if the router restarted, every
call raised BrokenPipeError and the consumer stayed wedged. list_providers/route
now drop the dead client and reconnect once.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-03 12:31:09 -07:00
zeekay a14e44a822 feat(mcp): native MCP ImageContent — tools return images the client can SEE
HIP-0300 tools serialize results to JSON text, which flattened images into
useless base64-in-text. Add a ToolImage value type + one converter in
BaseTool.register: any ToolImage anywhere in a result becomes a real
mcp.types.ImageContent block; text-only results stay byte-for-byte JSON.
Emitters wired: fs read of image files, browser screenshots (bidi+playwright).
This gives hanzo-mcp vision parity with zai-mcp — an agent with native vision
(Claude) sees pixels directly, no per-task vision tool needed.

Also decomplect the core-package collision that caused this class of bug:
hanzo-tools-core shipped a DUPLICATE hanzo_tools/core/ that nondeterministically
shadowed canonical hanzo-tools (dropping ToolImage, the sophisticated register,
etc. — same shadow class as the 0.3.0 error-reexport gap). Finish the
'merge core into hanzo-tools' refactor: move id_tool into hanzo-tools, make
hanzo-tools-core a pure empty metapackage. Now ONE package owns hanzo_tools.core.

Versions: hanzo-tools 0.3.2, -core 0.3.1 (shim), -browser 0.5.9, -fs 0.3.4,
hanzo-mcp 0.15.12 (floors bumped). Verified: fs read PNG -> [text, image];
fs stat -> [text]; 29 tools intact; 9 tests pass.
2026-07-03 00:45:49 -07:00
zeekay 617084b1ab test(hanzo-mcp): guard every hanzo.tools entry point imports cleanly
Regression guard for the hanzo-tools 0.3.0 core re-export gap that silently
dropped fs/exec/code/git/fetch/agent, leaving hanzo-mcp with only 13 tools.
Fails loudly if any entry point stops loading or the core error contract
(ToolError/ConflictError/InvalidParamsError/NotFoundError) regresses.
2026-07-02 23:57:21 -07:00
zeekay b1caa18c7f release(hanzo-tools): 0.3.1 — ship core error-class re-exports
PyPI hanzo-tools 0.3.0 shipped a core/__init__.py that never re-exported
ToolError/ConflictError/InvalidParamsError/NotFoundError from core.unified.
Six tool packages (fs, shell, agent, code, vcs, net) import those names at
entry-point load and silently failed, so hanzo-mcp exposed only 13 tools
instead of the full axis set. The re-export fix already landed in git
(4406ef32) but 0.3.0 was never republished. Bump to 0.3.1 to ship it.

Verified: entry points 20→26 loaded, hanzo-mcp tools/list 13→29.
2026-07-02 23:55:25 -07:00
zeekay da181e9d0f fix(hanzo-mcp): 'tool list' crash on @property descriptions (v0.15.11)
DynamicToolRegistry stored getattr(tool_class, 'description'), which for a
class-level @property returns the property DESCRIPTOR (not a str). 'tool list'
then did len(config.description) → 'object of type property has no len()',
breaking the entire tool-catalog command. Add _extract_tool_description
(mirrors _extract_tool_name): resolve a @property via a cheap instance, else
coerce to str, always returns str. Plus a defensive isinstance guard in the
list display path. Regression test covers property/unevaluable-property/plain/
absent + asserts every registered entry's description is len()-safe. 2 passed.
2026-07-02 23:00:52 -07:00
zeekay 41b9dc0b21 Merge remote-tracking branch 'origin/rip/api-callers-to-v1' 2026-07-02 13:18:52 -07:00
zeekayandHanzo Dev 6ac1e43ddc rip: migrate KMS universal-auth login to canonical /v1/kms/auth/login
hanzo-kms (sync + async): /api/v1/auth/universal-auth/login →
/v1/kms/auth/login. Body already canonical {clientId,clientSecret};
TokenResponse already parses {accessToken,expiresIn,tokenType}.

Scoped per CTO ruling: ONLY endpoints with a real canonical /v1/kms/*
target are migrated. The remaining /api/v3/secrets/raw/*,
/api/v1/auth/{kubernetes-auth,aws-auth}/login and /api/v3/auth/login
have NO canonical route (or a different API shape) on the kms.hanzo.ai
server and are left intact — rewriting them would mint dead /v1 paths.
They are flagged for a separate SDK-port task. Clean break, no aliases
(org rule: one way, /v1/, never /api/).

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-02 13:16:42 -07:00
zeekay 01566be773 release: bump auth-fixed packages for publish
Ship the canonical hanzo-app client_id + /v1/iam/get-account fixes:
- hanzoai 2.2.2 → 2.2.3
- hanzo-cli 0.2.1 → 0.2.2
- hanzo 0.4.2 → 0.4.3
- hanzo-tools-auth 0.1.0 → 0.1.1
2026-06-30 22:21:53 -07:00
zeekay afb00aaed6 auth: fix get-account endpoint (bare /v1/get-account 404s)
get_user_info hit {api_base_url}/v1/get-account (api.hanzo.ai/v1/get-account),
which 404s — the account read lives on the IAM issuer at /v1/iam/get-account
(same base as mint_api_key). Response is a {status,sub,name,data,data2}
envelope; accessKey is under data (get_api_key already reads it there).
2026-06-30 17:56:31 -07:00
zeekay 43cdcd4377 auth: align all SDK packages to canonical <org>-<app> client ids
IAM seeds apps as <org>-<app> (iam cmd/iam/cli/init_apps.go:57-59):
hanzo-app, zoo-app, lux-app — AppName == ClientID. Several packages used the
inverted 'app-hanzo'/'app-hanzobot' or placeholder '*-client-id', none of which
IAM knows — device/PKCE login would fail. One value, everywhere:

- hanzoai/auth.py: login_with_pkce default -> IAM_CLIENT_ID (hanzo-app)
- hanzo-cli/auth.py: DEFAULT_APP, DEFAULT_CLIENT_ID -> hanzo-app
- hanzo/commands/auth.py: IAM_CLIENT_ID -> hanzo-app
- hanzo-tools-auth/session.py: DEFAULT_APP, DEFAULT_CLIENT_ID -> hanzo-app
- hanzo/commands/iam.py: --app default + doc example -> hanzo-app
- hanzo-cli/bot/commands.py: BOT_IAM_APP/CLIENT_ID app-hanzobot -> hanzo-bot
2026-06-30 17:23:10 -07:00
zeekay f07ff89b29 auth: fix device login + API-key flow to real hanzo.id/IAM contract
Verified against iam (controllers/token.go, user.go, init_apps.go), ai
(controllers/account.go), and login (middleware.ts) sources:

- client_id hanzo-app (canonical brand CLI/desktop/mobile app seeded with the
  device_code grant), not the unseeded hanzo-dev/app-hanzo.
- Device flow uses RFC paths hanzo.id proxies to IAM — POST /oauth/device and
  /oauth/token — form-encoded (IAM reads device-grant params via Query(), skips
  JSON), keyed off the response body so a proxy can't desync polling.
- get_user_info reads /v1/get-account (IAM Claims with accessKey inlined),
  not the nonexistent /v1/user.
- Replace fictional named-key CRUD (/v1/api-keys) with Hanzo's real single
  per-user hk- key model: get_api_key (read accessKey), mint_api_key (self via
  /v1/iam/mint-user-keys), get_or_create_api_key (read-first), revoke_api_key.

Email/SMS/Google/GitHub/web3 all work since the device flow delegates login UI
to the browser approval page (providers wired per iam wire_providers.go).
2026-06-30 17:23:10 -07:00
9ca5085925 chore(tools-ui): RAG client paths /api/* -> /v1/* (#43)
The hanzo-tools-ui docs-RAG client targets api.hanzo.ai (host already
canonicalized on main). Move the paths off the residual /api/ prefix to
top-level /v1/, matching the cloud-api route rename and the openapi
v1.0.0 lock-in (no /api/ prefix):

  /api/search-docs       -> /v1/search-docs
  /api/chat-docs         -> /v1/chat-docs
  /api/index-docs        -> /v1/index-docs
  /api/search-docs/stats -> /v1/search-docs/stats

Hard cutover, coordinated with hanzoai/cloud (productsvc + ai serve these
at /v1), universe cloud-api-v1 AUTH_PUBLIC_PATHS, hanzo-docs RAG clients,
and the openapi cloud spec.

Co-authored-by: Hanzo Dev <[email protected]>
2026-06-30 17:06:30 -07:00
zeekay 4db9f8f78a chore(tools-ui): RAG client paths /api/* -> /v1/*
The hanzo-tools-ui docs-RAG client targets api.hanzo.ai (host already
canonicalized on main). Move the paths off the residual /api/ prefix to
top-level /v1/, matching the cloud-api route rename and the openapi
v1.0.0 lock-in (no /api/ prefix):

  /api/search-docs       -> /v1/search-docs
  /api/chat-docs         -> /v1/chat-docs
  /api/index-docs        -> /v1/index-docs
  /api/search-docs/stats -> /v1/search-docs/stats

Hard cutover, coordinated with hanzoai/cloud (productsvc + ai serve these
at /v1), universe cloud-api-v1 AUTH_PUBLIC_PATHS, hanzo-docs RAG clients,
and the openapi cloud spec.
2026-06-30 16:58:58 -07:00
6cb701adc1 Point cloud clients at canonical api.hanzo.ai front door (#42)
The cloud API now sits behind one front door (ingress -> gateway -> cloud).
api.cloud.hanzo.ai / cloud-api.hanzo.ai / functions.hanzo.ai are redundant
aliases routing to the same backend, so migrate clients to api.hanzo.ai.

- hanzo-tools-ui: HANZO_CLOUD_API default cloud-api.hanzo.ai -> api.hanzo.ai
  (docs RAG paths /api/search-docs|chat-docs|index-docs are served at /api on
  the cloud backend per AUTH_PUBLIC_PATHS; kept as-is)
- hanzo base status: Functions remote host functions.hanzo.ai ->
  api.hanzo.ai/v1/functions (the canonical gateway path)

Non-breaking: the aliases still resolve to the same backend.

Co-authored-by: Hanzo Dev <[email protected]>
2026-06-30 16:49:00 -07:00
558f1afed6 refactor(iam): drop Casdoor branding — Hanzo IAM only (white-label) (#41)
Co-authored-by: Hanzo Dev <[email protected]>
2026-06-30 14:56:32 -07:00
a1ab42289f fix(ci): PyPI upload token-fallback for per-project scope (#40)
hanzo-iam is owned on PyPI by HANZO_AI_PYPI_TOKEN, not PYPI_TOKEN, so it 403'd.
Each upload now tries PYPI_TOKEN then falls back to HANZO_AI_PYPI_TOKEN, so any
hanzo-* package publishes regardless of which token owns its project.

Co-authored-by: Hanzo Dev <[email protected]>
2026-06-30 14:36:47 -07:00
a1cdb92c24 fix(ci): auto-discover packages + retry PyPI uploads on 429 (#39)
The hardcoded MAIN/TOOLS package lists silently dropped hanzo-zap and the
newer packages, so tag-triggered 'publish all' never shipped them. Derive
the list from pkg/ so it can never go stale again. Also retry uploads with
backoff: PyPI 429-rate-limits rapid multi-package bursts, which dropped the
tail of a large publish (hanzo-hooks, hanzo-tools-gimp, hanzo-tools-s3).

Co-authored-by: Hanzo Dev <[email protected]>
2026-06-30 14:04:13 -07:00
zeekay 1ae66bac7d docs(brand): add hero banner 2026-06-28 20:08:36 -07:00
zeekay 23608fe495 chore(brand): dynamic hero banner 2026-06-28 20:08:35 -07:00
zeekay e8680ed46e fix(tools): correct PyPI long_description metadata + stale tool-count tests
Packaging metadata (twine check was PASSED-with-warnings -> clean PASS):
- config/llm/mcp/vector: add missing 'readme = README.md' ([project] key);
  README files existed but were never wired into the dist metadata.
- net/plan/vcs: fill empty (0-byte) README.md files referenced by the
  readme key, so long_description is no longer missing.

Tests (hanzo-tools-core/test_all_tools.py drifted from current sources):
- browser: 1 -> 3 tools (browser, cdp, playwright after the zapd split)
- mcp_tools: 4 -> 5 tools
- required-tool total: 21 -> 23
2026-06-26 11:57:48 -07:00
zeekay e67fa9d2b6 release: hanzoai 2.2.2
Patch release carrying the HIP-0111 IAM endpoint migration in
hanzoai.resources.iam (/iam/api/get-account + /iam/api/userinfo ->
canonical /v1/iam/oauth/userinfo), already in-tree since e1a38363 but
unreleased. 2.2.1 is taken on PyPI; bump to 2.2.2 (x.x.x+1).
2026-06-26 11:57:39 -07:00
zeekayandGitHub 0b844fdd33 fix(iam): migrate userinfo/get-account to canonical /v1/iam/oauth/userinfo (HIP-0111) (#38)
Co-authored-by: Zach Kelling <[email protected]>
2026-06-24 19:16:18 -07:00
zeekay 1e8038c0c0 fix(iam): canonical /v1/iam paths, drop forbidden /api/ (HIP-0111)
hanzo-tools-iam built URLs as {base}/api/{path} — forbidden per HIP-0111
(no /api/ prefix; one way). Now {base}/v1/iam/{path}; health probe is
/v1/iam/healthz. Asserts JSON shape, not bare 200, to dodge the IAM SPA
catch-all that serves 200 text/html for unregistered paths. Adds a test
for _iam_url + IAM_BASE_URL. (Test harness wiring for this non-member
package is a separate packaging task — code verified: 0 /api/ remain.)
2026-06-24 13:50:24 -07:00
zeekay ddc00162ec refactor(s3): back hanzo-s3 with boto3 over hanzoai/s3, drop minio
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.
2026-06-24 13:50:24 -07:00
zeekay 2a753b334d feat(cli,mcp): complete S3 control surface — hanzo s3 + s3 MCP tool
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.
2026-06-24 13:50:24 -07:00
zeekay 77c94812a6 kms: use canonical KMS env + client names 2026-06-24 10:50:44 -07:00
zeekayandGitHub 49d7e66286 chore(hips): remove duplicated HIP docs — canonical is hanzoai/HIPs (#37)
No duplication: the SDK must not carry copies of governance proposals.
HIP-0300 duplicated canonical hip-0300; the rest diverge. Canonical home is
hanzoai/HIPs (git history preserves these). Forwards-only, no backcompat.
2026-06-23 17:58:19 -07:00