zeekayandHanzo Dev 7c59566eee generate: feed the generator JSON — the flag I added does not work on our pin
658493a added -DmaxYamlCodePoints to lift snakeyaml's 3145728 code-point
ceiling. I verified it on generator 7.24.0, which is what the C++ lane uses, and
did not verify it on 7.14.0, which is what THIS FILE pins for every other
language. It does not work there: 7.14.0 ships an older swagger-parser that
ignores the property. Java regeneration failed after 9m27s with the same
misleading "Issues with the OpenAPI input" the flag was supposed to prevent.

So the fleet was blocked on regenerating and the fix was cosmetic. The real fix
is not to raise the ceiling but to stop going near it: swagger-parser only hands
YAML to snakeyaml, and the JSON path is Jackson, which has no such cap. -i takes
either format.

Measured rather than assumed, because "it happens to be under the limit" is not
a fix — the JSON of this document is 3,144,674 code points, 1054 UNDER the
ceiling, which would have made a coincidence look like a solution. Padded to
3,684,674 (539 KB OVER) it still validates clean on 7.14.0. The JSON path does
not have the ceiling at all.

as_json() converts once, in main(), for every language. The temp file is
deliberately not written back to the repo: there is one document, and it is
hanzo.yaml.

Side effect worth recording: java generation went from failing at 9m27s to
succeeding in 12s. The YAML parse was not merely failing, it was thrashing.

hanzo-cpp/sdk's own scripts/generate.sh now does the same one thing rather than
carrying the flag, so there is one mechanism and not two. Verified by
--check: the generated C++ tree is byte-identical across the swap.

Co-authored-by: Hanzo Dev <[email protected]>
2026-07-31 16:33:54 -07:00
2026-06-01 12:44:10 -07:00

openapi

Hanzo OpenAPI

hanzo.yaml is THE published document. One OpenAPI 3.1 surface for every Hanzo service — the one every SDK, every doc site and every tool generates from.

curl -fsSL -H "Authorization: Bearer $GITHUB_TOKEN" \
  https://raw.githubusercontent.com/hanzoai/openapi/main/hanzo.yaml

This repo is private, so that URL needs a token — unauthenticated it is a 404, not a 403, which reads like a missing file rather than a missing header. Any fetch of it without an Authorization header is broken; curl -f under set -e turns that into a build failure with nothing that names the cause.

Nothing generates from anything else, and nothing is pushed to an SDK. The SDK repos PULL this file and regenerate themselves; a client is never hand-written and never receives a patch from here.

Forward-only. No backwards compatibility, no deprecated paths, no /api/ prefix, no cross-brand references. A single bearer JWT from Hanzo IAM (https://hanzo.id) authenticates every route, and every route is /v1/<service>/<resource> — the same path through the gateway (api.hanzo.ai) and through the service's own hostname.

One exception — AI inference is top-level. hanzoai/ai serves its OpenAI- and Claude-compatible surface at the bare /v1/* paths (/v1/chat/completions, /v1/completions, /v1/embeddings, /v1/models, /v1/rerank, /v1/messages) because every OpenAI/Anthropic SDK hard-codes them: there, the path IS the compatibility contract.

curl -H "Authorization: Bearer ${HANZO_TOKEN}" \
     https://api.hanzo.ai/v1/chat/completions -d '{"model":"zen5","messages":[...]}'

curl -H "Authorization: Bearer ${HANZO_TOKEN}" \
     https://api.hanzo.ai/v1/billing/balance

OIDC discovery: https://hanzo.id/.well-known/openid-configuration. hanzo.yaml is a file in this repo, not a served endpoint — /v1/discovery was probed, it 404s, and no handler for it exists.

The files

File What it is
hanzo.yaml the published document. Generated by merge.py; never edited.
<service>/openapi.yaml one self-contained authored spec per service.
cloud/openapi.yaml not authored here — hanzoai/cloud's own woven document, copied verbatim by sync.py.
capabilities.yaml the ONE registry: every capability, in exactly one domain.
flows.yaml the canonical example set — the same six journeys in every SDK.
CAPABILITIES.md generated index. Never hand-edit.
merge.py sync.py generate.py skills.py audit.py build · resync · clients · skills · measurement.

The capability index is CAPABILITIES.md, generated from capabilities.yaml, so it cannot drift from what is here. There is no second index in this file to fall out of date.

Two commands

python3 sync.py     # pull hanzoai/cloud's woven document, then merge
python3 merge.py    # rebuild hanzo.yaml + CAPABILITIES.md from the specs

sync.py is the whole resync: it fetches origin/main in a hanzoai/cloud checkout (../cloud, or --cloud DIR, or CLOUD_DIR), writes origin/main:openapi.yaml here byte-for-byte, and re-merges. --check reports staleness without writing. Nothing is ever written back to hanzoai/cloud.

That document is the one input here that cannot lie about what is served — cloud weaves it from its own router and gates the weave against source — so merge.py lets it WIN wherever it and an authored spec describe the same route. The authored specs cover what other binaries serve, cloud's covers what cloud serves, and hanzo.yaml is the union with truth on top.

Conventions

  • info.version: 8.0.0 (the V8 generation). The /v1 path is the immutable contract — there is no v2, ever. Breaking changes ship as new resources.
  • operationIds are BARE in each spec (logs_query); merge.py namespaces them <svc>_ in the published document. Never self-prefix.
  • No cross-file $ref. Each spec is self-contained.
  • No deprecated: true. No /api/ prefix. No dates in filenames.
  • Security: every operation uses BearerAuth. No service has its own login.
  • Errors: 4xx client, 5xx server, JSON body with status and msg.
  • A product whose own authored routes answer 404 — probed at api.hanzo.ai AND at its own host — is DELETED, not annotated. skills.py has no liveness filter, so an unserved route ships as a live instruction to call a dead endpoint. See LLM.md, "Who reads this repo".

Validate

python3 -c "import yaml, glob; [yaml.safe_load(open(s)) for s in glob.glob('*/openapi.yaml') + ['hanzo.yaml']]; print('OK')"

java -jar ~/.cache/openapi-generator/openapi-generator-cli-7.14.0.jar validate -i hanzo.yaml

npx -y @redocly/cli preview-docs hanzo.yaml

Clients

generate.py runs openapi-generator (pinned 7.14.0) over hanzo.yaml for every language; sdks.yaml is the per-language data, and each SDK repo carries only a call site. There is no second generator and no unified SDK monorepo.

python3 generate.py --all            # regenerate every client in place
python3 generate.py go               # just one
python3 generate.py --all --check    # fail if a committed client drifted
Lang Canonical repo Generator Ships as
Python hanzoai/python-sdk python hanzoai on PyPI
TypeScript hanzoai/js-sdk typescript-axios hanzoai on npm
Java · Kotlin hanzoai/java-sdk · hanzoai/kotlin-sdk java · kotlin (okhttp) ai.hanzo:hanzo-{java,kotlin}-cloud
Ruby hanzoai/ruby-sdk ruby gem
Rust hanzo-rs/sdk rust (reqwest) crates/hanzo-client — own scripts/generate.sh (needs a template override)
Go hanzo-go/sdk go package hanzoai at the module root — own scripts/generate.sh (no directory to own)

A language stays in sdks.yaml while its whole invocation is expressible as data, and leaves when it needs something that is not — a template file, or a layout take cannot describe. It then owns the whole invocation in its own repo. A row here AND flags there is two declarations of one contract.

Examples are not a per-SDK decision either: flows.yaml names the six journeys (hello, chat, money, store, agent, tools) and every SDK renders the same six from the same operationIds. python3 test_flows.py is the gate — an id that no longer resolves fails here, once, instead of in six clients separately.

Agent skills

skills.py derives /.well-known/agent-skills/ from the same per-service specs, clustering GET endpoints by resource — read-only by construction, no destructive verb ever becomes a skill — and emits a SKILL.md per cluster plus an index.json carrying a sha256 of every file.

python3 skills.py                 # dist/agent-skills/<brand>/…  (hanzo, lux, zoo)
python3 skills.py --no-services   # unified tree only (what the cloud binary embeds)
python3 skills.py --check         # drift gate
python3 test_skills.py            # golden test

Output is white-labeled per brand: a Lux surface reads Lux / api.lux.network / lux.id, a Zoo surface Zoo / api.zoo.ngo / zoo.id — never Hanzo. dist/ is generated at build time and is not committed.

License

BSD 3-Clause. Copyright Hanzo AI, Inc.

S
Description
Mirror of github.com/hanzoai/openapi
Readme
22 MiB
Languages
Mustache 52.8%
Python 43.7%
Go 0.9%
Shell 0.8%
Java 0.3%
Other 1.5%