---
title: Registry contract
description: Base addresses, discovery, paged catalogs and immutable release downloads.
group: Reference
---

# Registry contract

Connect a registry base address, such as `plugins.hay.so` or `https://plugins.example.com/team/`. Hay adds HTTPS to a bare hostname and preserves nested path prefixes. The trusted host discovers catalog endpoints and downloads artifact bytes; plugin frames do neither.

## Discovery

Hay requests `<base>/.well-known/hay-registry.json`:

```json
{
  "schemaVersion": "hay.registry.discovery/1",
  "name": "Team tools",
  "catalog": "v1/registry/plugins",
  "release": "v1/registry/releases/{id}/{version}"
}
```

`name` is nonempty and up to 100 characters. `catalog` is required; `release` is optional. The release template must contain exactly one `{id}` and one `{version}`; Hay URL-encodes each value before substituting it.

Paths resolve against the registry base, including `catalog`, `release`, pagination `next` and artifact paths. For a base of `https://plugins.example.com/team/`, `artifacts/file.hay-plugin.json` resolves under `/team/`, not relative to a catalog page. Keep paths relative to preserve a nested prefix. Absolute URLs and protocol-relative origins are refused; every resolved URL must remain on the registry origin.

Only a discovery response of HTTP 404 or 410 falls back to `<base>/index.json`. Invalid discovery JSON, redirects and other failures are errors, not a reason to bypass discovery.

## Paged catalog

A dynamic catalog returns:

```json
{
  "schemaVersion": "hay.registry.page/1",
  "plugins": [{
    "manifest": {"...": "complete hay.app/1 manifest"},
    "bundle": {
      "path": "artifacts/<sha256>.hay-plugin.json",
      "sha256": "<64 lower-case hexadecimal characters>",
      "size": 1234
    }
  }],
  "next": "v1/registry/plugins?after=<opaque-cursor>"
}
```

This illustrates the shape; supply a complete manifest, real digest and exact size. Omit `next` on the final page. Each ID/version pair must be unique across the catalog. A page has at most 100 entries and 1,000,000 bytes. Hay’s hosted service currently returns up to 50 entries per page, within the byte limit.

The current client assembles pages automatically, with limits of 5,000 releases, 100 pages, 20,000,000 cumulative catalog bytes and a 30-second overall operation deadline. Cycles, duplicate releases and exceeded bounds fail explicitly. This is bounded browsing, not an unlimited catalog client.

## Direct release lookup

When discovery supplies `release`, installation looks up the exact ID/version without walking catalog pages:

```json
{
  "schemaVersion": "hay.registry.release/1",
  "manifest": {"...": "complete hay.app/1 manifest"},
  "bundle": {
    "path": "artifacts/<sha256>.hay-plugin.json",
    "sha256": "<64 lower-case hexadecimal characters>",
    "size": 1234
  }
}
```

The returned manifest must match the requested ID and version. Without a direct endpoint, Hay finds the release through the bounded catalog read. Direct lookup does not bypass integrity checks, installation review or capability grants.

## Static compatibility

Static tooling exports a discovery file whose `catalog` is `index.json`; no release endpoint is required. That catalog keeps the original format:

```json
{
  "schemaVersion": "hay.registry/1",
  "name": "Team tools",
  "plugins": [{
    "manifest": {"...": "complete hay.app/1 manifest"},
    "bundle": {
      "path": "artifacts/<sha256>.hay-plugin.json",
      "sha256": "<64 lower-case hexadecimal characters>",
      "size": 1234
    }
  }]
}
```

A legacy index is limited to 100 entries and 1,000,000 bytes. Hosted publishing is not capped at 100 releases: the service uses paged catalogs and direct lookup. Its legacy index returns an explicit upgrade error once it exceeds the compatibility bounds, rather than silently omitting older releases.

## Artifact integrity and transport

`sha256` hashes the exact downloaded artifact bytes, including whitespace and trailing newlines. `size` is the exact byte count, from 1 to 2,000,000. The artifact is a complete `hay.bundle/1` bundle; its manifest must exactly equal the release metadata. A digest from another serialization fails verification.

Public registries require HTTPS. Numeric loopback HTTP is allowed for local development. Plain HTTP on public hosts, embedded credentials, fragments, redirects and cross-origin paths are refused. Public and custom registry requests omit credentials. The host’s built-in [personal-registry](personal-registries/) access is the narrow exception: an online-validated bearer session goes only to the current account’s exact private base, with every endpoint and artifact confined to that path. Cookies remain omitted and redirects are refused.

Each request has at most ten seconds, within the operation’s 30-second deadline. Streamed byte limits apply even without a trustworthy Content-Length. Discovery is bounded at 16,000 bytes; catalog pages and direct release metadata at 1,000,000 bytes; bundles at 2,000,000 bytes.

## Source identity and trust

A registry’s base address identifies the source independently of its catalog transport. Saved `/index.json` addresses normalize to their parent base. Historical installation provenance remains intact; source comparisons recognize the equivalent old and new address for updates and restoration. Changing a descriptor endpoint does not create a new publisher or permit a foreign-source replacement.

Provenance records the registry source, download URL, digest, size and installation time. A plugin cannot change its provenance or grants through SDK calls. The read-only registry protocol is a host responsibility, not a `window.Hay` plugin API.

The format is unsigned. A digest verifies bytes against the selected registry, not legal identity or code safety. The [publisher API](publisher-api/) separately authorizes publication under an account-owned namespace. Static custom registries need no Hay account service; author names there remain self-reported.

## Marketplace and install links

Marketplace search returns latest public plugins for human browsing, independently of the full release catalog. Its APIs and numeric release ordering are documented in the [publisher API](publisher-api/). An exact `hay://install` link pins the registry base, plugin ID, version and SHA-256. It opens an overview in Hay; **Review installation** and inline approval remain separate. It never changes the saved registry selection or grants capabilities. See the [install-link contract](marketplace/).

## Downloadable schemas

Structural schemas are available for [discovery](reference/registry-discovery.schema.json), [catalog pages](reference/registry-page.schema.json), [direct releases](reference/registry-release.schema.json) and [legacy indexes](reference/registry.schema.json). Passing a schema does not prove same-origin confinement, template validity, exact bytes or installation approval; runtime checks still apply.

## Errors

Invalid JSON, unsupported fields, duplicate releases, unavailable versions, pagination cycles, oversized responses, wrong digests, manifest mismatches and redirects fail closed. Fix the registry or publish a correctly versioned release; do not bypass review or replace user records to work around an error.
