HIPsHanzo Proposals
Back to HIPs
HIP-1322FinalStandards TrackInterface

Skills — The Discovery Catalogue

Hanzo AI
Created: 2026-08-21
Requires: HIP-0106, HIP-0139

HIP-1322: Skills — The Discovery Catalogue

Abstract

/.well-known/agent-skills/ is the catalogue an AI client reads to learn what this deployment can do. It is implemented in hanzoai/cloud at apps/skills (HIP-0106) and serves two public GET routes from a catalogue embedded in the one cloud binary.

This HIP states why the catalogue is generated rather than authored (§2), which brand a request is answered for (§3), and why these two routes sit at the root rather than under /v1 (§4).

Motivation

An agent that must be told what a platform offers is an agent someone has to keep telling. The discovery convention answers that once, at a fixed address, in a document the agent can fetch before it holds any credential.

The catalogue's danger is not that it is missing but that it is confidently wrong. A skill document is read as live instruction: it tells an agent an address answers and what to send there. An authored catalogue drifts from the router the moment either moves, and drift here does not degrade gracefully — it hands an agent an address that 404s and a reason to keep trying.

Specification

The key words MUST, MUST NOT, SHOULD, SHOULD NOT and MAY are to be interpreted as in RFC 2119.

§1 The surface

Two routes, public, GET only:

RouteAnswer
GET /.well-known/agent-skills/index.jsonthe brand's master catalogue
GET /.well-known/agent-skills/{skill}/SKILL.mdone skill document

The discovery surface carries no secrets and MUST NOT require a bearer. Neither route can be a typed op, so both declare their prose through the registry the router projection consults — which is why they render only while they are served, and why the generated SDKs and the spec-derived CLI carry the same sentence the document does.

§2 Generated from the router, never authored

The catalogue is generated by plugin/gen-skills from each app's own plugin/<app>/openapi.json — the app binary describing its own live router, which is the same input the fleet catalogue and openapi.yaml are built from — and embedded as catalog/.

This package MUST NOT re-derive skills at request time. It serves the embedded bytes, so the sha256 digests in index.json match the served SKILL.md exactly, and a catalogue cannot describe a route the binary does not serve.

The rule earns its place from a measured failure: the lane that built this catalogue in hanzoai/openapi projected authored intent rather than served routes and had no liveness filter, so it shipped skills for /v1/balancers and /v1/builds — which production 404s — as live instructions to an agent. The generator moved to cloud, beside the routes, for that reason.

§3 White-label: the brand is the Host

The brand is decided per request from the Host header, mirroring getWhiteLabelBrand: api.hanzo.ai serves the Hanzo catalogue, api.lux.network the Lux one, api.zoo.ngo the Zoo one. Hanzo branding MUST NOT appear on a Lux or Zoo surface.

A Host resolving to a brand with no embedded catalogue falls back to the deployment brand (CLOUD_BRAND), then to hanzo. Falling back is not guessing — every fallback is a catalogue that exists.

§4 The address is the convention's, not ours

These two routes live at the root because /.well-known/ is registered by RFC 8615 and the discovery convention names the path. HIP-0139 §3 permits an app to answer at an address not named for it exactly where an outside convention fixes the address, and this is such a case: an agent looks under /.well-known/agent-skills/ or it does not find us.

Registration order matters and is part of the contract: these routes are mounted at order 8, BEFORE IAM's /.well-known/* catch-all at order 50 and before the console's /*, so a first-match scan reaches them.

§5 The boundary against tools

  • tools (HIP-1213) is the per-tenant tool plane an agent calls through, authenticated and scoped to an org.
  • skills is the unauthenticated description of what exists, read before any call.

A skill document MUST NOT be the only place a capability's contract is written; it points at the served document, which HIP-1030 specifies.

Rationale

skills was briefly treated as having folded into tools, and the corpus recorded it as no longer a capability. It had not folded: apps/skills is its own package with its own row in manifest/apps.go and its own two served routes, and it answers a question tools does not — what exists, to a caller who has not authenticated. The record is corrected here.

Security Considerations

The catalogue is public by design, so it MUST carry nothing an unauthenticated reader may not have: no org names, no tenant addresses, no credentials, no internal hostnames. Because it is generated from each app's own router description rather than from a tenant's state, it has no tenant state to leak.

The digest in index.json is the integrity claim a client can check, and it holds only because the same bytes are embedded and served. A future lane that re-derived a skill at request time would break that claim silently, which is why §2 forbids it.

References

  • HIP-0106 — Hanzo Plugin Contract
  • HIP-0139 — Capability
  • HIP-1030 — OpenAPI — The Served Contract
  • HIP-1213 — Tools — The Tool Plane
  • RFC 8615 — Well-Known Uniform Resource Identifiers

Copyright

Released under CC0 1.0 Universal Public Domain Dedication.