> ## Documentation Index
> Fetch the complete documentation index at: https://docs.mzizi.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# The API gateway

> api.mzizi.dev is a Hono Cloudflare Worker that serves the registry's files, generated at a pinned registry commit and bundled at build time. No origin, no database.

[`api.mzizi.dev`](https://api.mzizi.dev/v1) is the registry API. It is served by
[`mzizi-dev/mzizi-api-gateway`](https://github.com/mzizi-dev/mzizi-api-gateway), a
[Hono](https://hono.dev) Cloudflare Worker written in TypeScript. It has **no origin, no
database and no Supabase**. Everything it serves is a file from the registry repository,
bundled into the Worker when it is built.

It has served `api.mzizi.dev` since **29 September 2026**, when it took over from the
registry's own Worker.

<Note>
  An earlier plan for this repository was a pure-Rust `workers-rs` proxy in front of the
  registry's own API handlers. That proxy is retired, and so are the handlers: the registry
  removed its Next.js app, `/api/*` handlers included, on 2 October 2026. The gateway is Hono,
  and it implements the whole public `/v1` API itself, from files.
</Note>

## Using it

```bash theme={null}
curl https://api.mzizi.dev/v1                 # the discovery document
curl https://api.mzizi.dev/v1/ui              # the component index
curl https://api.mzizi.dev/v1/ui/button       # one component, source inline (shadcn format)
curl https://api.mzizi.dev/v1/rs/button       # its Rust (Dioxus) source, where one exists
curl https://api.mzizi.dev/v1/brand           # the brand system: 21 colour families
curl https://api.mzizi.dev/v1/architecture    # the DNA helix: 8 nodes, 4 rungs, 6 strands
curl "https://api.mzizi.dev/v1/search?q=card&node=3"   # search, filtered by node
curl https://api.mzizi.dev/openapi            # the OpenAPI 3.1 document
```

No sign-in and no key. The API is read-only: a path with a `GET` handler answers `OPTIONS`
with `204`, and every other method with `405`. Both `/v1/...` (canonical) and `/api/v1/...`
answer. `api.mzizi.dev/v1/*` redirects here.

Every response carries a header naming the Worker and the registry commit it was built from.
The pin moves (see [how the pin moves](#how-the-pin-moves)), so read it from the header
rather than from this page:

```bash theme={null}
curl -sI https://api.mzizi.dev/v1/health | grep -i x-mzizi-source
```

The answer has this shape, with the first twelve characters of the pinned registry commit:

```text theme={null}
x-mzizi-source: mzizi-api-gateway; registry=<registry commit>
```

For example, on 30 September 2026 it read `registry=9b86e034ffd8`. That is an example, not
the current value; the header is.

From registry commit `9b86e03` on, `/v1/rs/{name}` serves the twelve Mzizi Roots brand
components, and its `crate` field names each component's own crate, with a `git` field for
the source repository. See [the Rust route](#the-rust-route).

## How the data flows

```text theme={null}
mzizi-dev/mzizi-registry          registry.json, components/, content/doctrine/, lib/ …
        │   at the commit pinned in scripts/registry-ref.json
        ▼
npm run build:data                checks out that commit and runs the registry's own
        │                         readers against it, writing src/data/*.json
        ▼
the Worker bundle                 the JSON is imported as modules and deployed with the code
        │
        ▼
api.mzizi.dev                     serves from memory; reads nothing at request time
```

Three properties follow from that shape:

* **The registry's files are the data layer.** Components, doctrine, brand, changelog,
  skills and samples are files in [`mzizi-dev/mzizi-registry`](https://github.com/mzizi-dev/mzizi-registry).
  The gateway reads them at build time, not at request time.
* **The shapes are the registry's own.** The build calls the registry's readers rather than
  reimplementing them. The Supabase client is replaced with a stub that throws, so a reader
  that reached for a database would fail the build instead of shipping an empty answer.
* **A registry change reaches the API only through a commit.** Moving to newer registry
  content means changing the pin, which CI checks. A bot is built to open that commit: see
  [how the pin moves](#how-the-pin-moves).

The bundle is about 917 KiB gzipped, well under the Workers limit, so the data ships inside
the Worker rather than in separate storage.

### How the pin moves

The pin is `ref` in the gateway's `scripts/registry-ref.json`. The owner decided on 30
September 2026 to keep the pin and move it automatically, and the gateway has a bot built to
keep it on registry `main`. The gateway's README describes it under
[Registry pin bump](https://github.com/mzizi-dev/mzizi-api-gateway#registry-pin-bump).

1. **Every hour** the bot compares the pin with registry `main`. When they differ, it
   opens or updates one pull request, from the branch `bot/registry-pin`, that moves the pin.
   The pull request lists the registry commits the bump brings in.
2. **Every check runs on it**, including **parity in strict mode** against production
   `https://api.mzizi.dev`: any difference at all between the bump and what is live fails it.
3. **It merges itself (rebase) only when every check is green**, including parity and the
   checks `main`'s rules require. The merge deploys as usual.
4. **Anything else waits for a person.** A failed check gets a comment listing what failed,
   and the bot leaves the pull request for review. An unexplained parity difference usually
   means the registry changed a file the gateway reads, and the gateway's route has to
   follow it.

The bot runs on its own token, the `RELEASE_BUMP_TOKEN` Actions secret (a fine-grained token
with Contents, Pull requests and Workflows read and write), and it is live: on 2 October 2026 it opened
mzizi-api-gateway#29 and, for the MCP server's pin, agent-tools#169. It merges its own pull request only if the token
also has **Checks: Read-only** and **Commit statuses: Read-only**, because it reads the bump's
check runs and commit status before merging; without them that read fails with a `403` and
the pull request waits for a person. A bump by hand keeps working too, and the bot steps aside
for it: while another open pull request moves the pin to registry `main` it opens none, and
when a bump lands any other way it closes its own. [The MCP server's pin](/toolchain/mcp#where-its-data-comes-from) has the same bot.

## What it answers besides data

* **`308` for renamed components.** Former `nyuchi-*` names redirect to their `mzizi-*`
  names on `/v1/ui` and `/v1/rs`, keeping the sub-path and query. For example,
  `/v1/ui/nyuchi-sidebar` answers `308` to `/v1/ui/mzizi-sidebar`.
* **`410 Gone`** for retired routes: `/v1/docs`, and the retired axis and layer models under
  `/v1/architecture/`.
* **`308 /mcp`** to `https://mcp.mzizi.dev/mcp`.
* **`/.well-known/security.txt`**, with the contact `security@nyuchi.com`.

### Search

`/v1/search` searches the registry's files. It takes up to three parameters, which combine,
and at least one is required:

| Parameter | What it matches |
| - | - |
| `q` | A case-insensitive substring of a component's name or description |
| `node` | The component's node on the helix, as a number: `node=3` |
| `category` | One of the component's `categories`: `category=brand` |

`layer` is a **deprecated alias** of `node`, kept so older clients keep their results. A
request that uses it gets the same results, plus a `Deprecation: true` header and a
`meta.deprecation` note. `node` wins when both are given. Use `node`; `layer` will be removed.

### The Rust route

`/v1/rs/{name}` answers with a component's Rust (Dioxus) source where one exists, and `404`
where there is none. The document names the crate the component ships in, and the crate
differs by node: `mzizi-ui` for the primitives, `mzizi-brand` for the brand components,
`mzizi-shell` for the app chrome, and so on. For example, on 30 September 2026:

```bash theme={null}
curl -s https://api.mzizi.dev/v1/rs/mzizi-alert-banner | jq .crate
```

```json theme={null}
{
  "name": "mzizi-brand",
  "registry": "crates.io",
  "git": "https://github.com/mzizi-dev/mzizi-registry"
}
```

Read the `crate` field rather than assuming one crate for every component. The route is a
read surface: to use a component, depend on its crate. See [Mzizi Roots](/roots/overview).

### One route answers 503

`/v1/ui/{name}/versions` answers `503`. Component version history is written by releases into
the console's database, and it is not one of the registry's files, so this API does not serve
it. The response says so and points to `/v1/changelog` for release history.

Earlier builds also answered `503` on `/v1/search`, `/v1/ui/{name}/docs` and
`/v1/ai/instructions/{name}`. Their data is in files, and from registry commit `ce68c64` they
are served from files. The discovery document no longer carries a `database` block; its
`data` block reads `"source": "files"`.

### The discovery document and OpenAPI text

`/v1` and `/openapi` are served from the registry, and from `ce68c64` on
both say that files are the data layer and that Mzizi owns and operates the API. Neither names
Supabase as a data source or Nyuchi as operator. Two mentions of Supabase remain in `/openapi`, and both are accurate: the
`/data-layer` route describes the wider ecosystem's data layer, and the retired `/docs` route
notes that its old table is historical.

## Parity

The acceptance test for the cutover was
[`scripts/parity.mjs`](https://github.com/mzizi-dev/mzizi-api-gateway/blob/main/scripts/parity.mjs).
It sends read-only requests to a baseline and a candidate: every route, every component slug
on `/v1/ui/{name}` and `/v1/rs/{name}`, the renamed names, the filters, the error paths and
the method handling. It diffs status, `Location`, content type, the CORS, cache and security
headers, and the body. Intentional differences are listed in the script with their reasons.

Before the domain moved, parity against the deployed Worker ran **1,359 requests with 0
unexplained differences**. Only two differences are intentional: the bare `/v1` now serves the
discovery document instead of an HTML 404, and an unknown path gets a small JSON 404.

```bash theme={null}
node scripts/parity.mjs --baseline https://api.mzizi.dev --candidate http://localhost:8787
```

## Rollback, in brief

There is no older Worker to fall back to. The registry's own Worker served the app the
registry removed on 2 October 2026, and it is being deleted, so `api.mzizi.dev` stays on the
gateway. To undo a bad change, revert it in a pull request; the merge redeploys. To undo a bad
deploy faster than that, roll the `mzizi-api-gateway` Worker back to its previous deployment
(`wrangler rollback`, or *Deployments* in the Cloudflare dashboard), then revert on `main` so
the next deploy does not bring the change back.

## Developing

```bash theme={null}
npm ci
npm run build:data     # check out the pinned registry commit, generate src/data/
npm run dev            # wrangler dev on http://localhost:8787
npm test               # offline route tests
npm run parity         # live api.mzizi.dev against the local Worker
```

The repository is rebase-only. See its `CONTRIBUTING.md` for changing a route or moving the
pin.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.