Skip to content

Registry vs catalog

Four different authorities use the words "registry" or "catalog" in this codebase. This page is the disambiguation table. The single most common documentation drift in Matrix is treating these as one thing.

The four authorities

1. Artifact registry — the binary store

Question it answers: "Where do I download the bytes for @open-matrix/chat@0.2.3?"

Backing store:

  • Cloud product: a Gitea instance at registry.hivecast.ai, exposing the npm-compatible API at /api/packages/<scope>/npm/.
  • Local install: the bundled package store seeded by hivecast install into <host-home>/packages/{system,global}/node_modules/....

Implementation today: Gitea is provisioned by projects/deploy-cloud/setup-aws.sh and proxied by projects/deploy-cloud/Caddyfile.bare. Local seeding is seedBundledHostPackages in projects/matrix-3/packages/hivecast/bin/hivecast.mjs.

Does not own: package descriptions, search, version ranges semantics, runtime state, mount claims.

2. Package catalog — system.packages

Question it answers: "What can I install? What does this package describe itself as?"

Backing store: A discovery-index.json written next to the Gitea artifacts (or under <host-home>/registry/ for local mode). The catalog is a key-value projection of every package's matrix.json discovery metadata across versions.

Implementation today: SystemPackageRegistryActor at projects/matrix-3/packages/system-catalog/src/SystemPackageRegistryActor.ts. Mounted as system.packages. Single op: registry.search.

Does not own: the artifact bytes themselves, the running mount inventory, or whether anything is currently mounted.

Note: The op is named registry.search (not packages.search). That is a v1 naming wart — the actor mounts at system.packages, but its single op uses the registry. prefix. New code should keep registry.search for compatibility; future revisions may add a packages.search alias.

3. Live actor registry — system.registry

Question it answers: "Which logical mounts are currently claimed by which providers, and which providers are alive right now?"

Backing store: in-memory in the system runtime. State is rebuilt from provider heartbeats; there is no on-disk truth.

Implementation today: ServiceRegistryActor at projects/matrix-3/packages/system-platform/src/ServiceRegistryActor.ts. Mounted as system.registry. Ops: registry.register, registry.heartbeat, registry.unregister, registry.list, registry.resolve, registry.children, registry.providers. Compatibility ops service.register / service.resolve / service.list / service.deregister remain for older callers.

Does not own: package availability, package metadata, downloadable artifacts.

4. System catalog — system.catalog

Question it answers: "Give me a unified read-only view of every mount in this Host, what runtime serves it, what ops it accepts, and what its providers declare."

Backing store: none. system.catalog is a read projection that builds its result on every call by joining system.registry.registry.list, system.runtimes.runtimes.registered, system.gateway.http.gateway.http.status, and (for filtered searches) live $introspect calls against each provider.

Implementation today: SystemCatalogActor at projects/matrix-3/packages/system-catalog/src/SystemCatalogActor.ts. Mounted as system.catalog. Ops: catalog.list, catalog.resolve, catalog.roots, catalog.children, catalog.tree, catalog.search.

Does not own anything. It is purely derived. Two consequences:

  1. If system.registry is wrong, system.catalog is wrong. Fix system.registry.
  2. system.catalog is safe to recompute aggressively; it has no write surface.

Authority table

QuestionAuthorityWriteable?
Where are the bytes?artifact registry (Gitea / local store)yes (publish flow)
What can I install?system.packages (discovery-index.json)yes (publish flow updates index)
What is currently mounted?system.registry (ServiceRegistryActor)yes (register/heartbeat/unregister)
What is the unified view?system.catalog (SystemCatalogActor)no — read projection
What URL serves an app?system.gateway.http.gateway.http.status (out of scope here, see docs-gateway)no — derived from runtime records

Why this matters

Treating "registry" as one concept causes three classes of bug:

  1. Stale catalog. Code asks system.registry for "available packages." system.registry only knows about running mounts; the answer omits anything not started. The right authority is system.packages.
  2. Phantom mounts. Code writes to system.catalog to "register a package." system.catalog is read-only; nothing happens. The right authority is system.registry (for live mounts) or the publish flow (for the artifact registry).
  3. Cross-Host bleed. Code assumes the artifact registry is per-Host. It is not — the cloud-product artifact registry is registry.hivecast.ai, shared across every linked Device. Per-Host state lives in system.registry, not in the artifact registry.

See also

Source: This separation is enforced by the directory structure. Each authority lives in its own package and exposes its own actor mount. There is no shared state between them on disk; all coupling is through declared request/reply ops.