Registry Interface
This repository contains the local registry interface used by Cabin’s public OSS core:
- a deterministic local JSON package index;
- a local file-registry write path for
cabin publish --registry-dir; - a read-only sparse HTTP client that consumes the same static layout;
- package archive metadata that preserves the manifest-declared fields the resolver and build pipeline need.
It does not contain the registry service itself: account systems,
ownership workflows, token issuance, hosted storage, signing policy, and
other server-side control planes are outside the OSS core’s boundary
(the hosted service is developed under the repository’s separate
registry/ workspace, not in the Cabin crates).
The client side of a remote registry protocol is an experimental,
-Z remote-registry-gated track; see
Experimental remote registry client.
Local File Registry
cabin publish --registry-dir <dir> writes a deterministic file registry
that the resolver can read back through --index-path <dir>.
<registry>/
config.json
packages/
fmtlib/
fmt.json
gabime/
spdlog.json
artifacts/
fmtlib/
fmt/
fmtlib-fmt-10.2.1.zip
gabime/
spdlog/
gabime-spdlog-1.13.0.zip
config.json identifies the registry layout and the relative packages
and artifacts directories. Registry packages are always scoped
(<scope>/<name>), so each package’s index file nests one scope
directory deep and its artifact filename embeds the scope
(<scope>-<name>-<version>.zip, self-identifying outside the tree).
Each packages/<scope>/<name>.json file contains the deterministic
per-package version list. Each version points at its source archive by
a registry-relative path such as
../../artifacts/fmtlib/fmt/fmtlib-fmt-10.2.1.zip. Legacy
bare-name registries (packages/<name>.json,
artifacts/<name>/<name>-<version>.zip) remain readable and
vendorable; only new publication requires a scope.
The file-registry writer:
- stages package archives and canonical metadata through the same
package code used by
cabin package; - requires a scoped name and validates each name component before it becomes a path component;
- rejects duplicate versions;
- writes version entries in deterministic semver order;
- replaces the artifact and the per-package index atomically: each file is staged in a sibling temporary file and only renamed onto its destination after a successful write, so an interrupted publish leaves the previous artifact and index in place;
- uses a simple registry lock file to avoid concurrent mutation;
- keeps archive checksums in the index so the artifact pipeline can verify bytes before extraction.
The existing read path (cabin resolve, cabin fetch,
cabin build --index-path) accepts either a registry root with
config.json or the legacy flat-fixture layout described in
package-index.md, so a registry written by
cabin publish --registry-dir can be consumed end to end without
any conversion step:
cabin publish --manifest-path fmt/cabin.toml --registry-dir registry
cabin resolve --manifest-path app/cabin.toml --index-path registry
cabin fetch --manifest-path app/cabin.toml --index-path registry --cache-dir cache
cabin build \
--manifest-path app/cabin.toml --index-path registry --cache-dir cache \
--build-dir build
Sparse HTTP Read Path
The sparse HTTP client reads the same file-registry shape over plain
GET requests:
GET <url>/config.jsonGET <url>/packages/<scope>/<name>.jsonGET <url>/artifacts/<scope>/<name>/<scope>-<name>-<version>.zip
A bare name (legal only in locally-produced file registries) reads
from the flat packages/<name>.json /
artifacts/<name>/<name>-<version>.zip shape; the hosted registry
serves scoped routes only.
The client is read-only. It does not publish packages, mutate registry
state, persist HTTP metadata for offline use, or infer a default remote
source. Commands that need an index source require --index-path,
--index-url, or a local config default.
HTTP archive bytes still flow through the artifact cache. Cabin hashes
the bytes, checks them against the index’s sha256:<hex> value, stores
the archive under the content-addressed cache path, and extracts it with
the same path-traversal protections used for local archives.
Transport And Format Boundaries
The package index document shape is shared by the local filesystem and sparse HTTP read paths. Transport-specific code lives outside the domain model:
cabin-indexparses package index documents from local files;cabin-registry-fileowns the local mutable file-registry layout;cabin-index-httpperforms read-only HTTP fetches and hands the retrieved JSON to the same typed index model;cabin-registry-apiowns the experimental authenticated mutation routes (publish / yank, behind-Z remote-registry);cabin-artifactverifies, caches, and extracts source archives without knowing whether bytes came from a file or HTTP.
The separation is intentional: adding a new local or static read transport should not require changing package metadata, the lockfile, or the build planner.
Experimental Remote Registry Client
Gated behind -Z remote-registry, with no compatibility promise, Cabin
is growing a client for authenticated remote registries. The protocol
both sides implement - bearer-token reads, network-backed package
publishing, and a yank command - is specified in
remote-registry.md. Under this experimental
track:
- the registry
config.jsonfieldsauth-requiredandapiare recognized; without-Z remote-registrytheir presence fails the index load with an error naming the field (never a silent ignore); - client-side credential handling uses
Authorization: Bearertokens issued on the registry’s web UI, whose URL the client discovers from theWWW-AuthenticateCabin login_urlchallenge on unauthenticated responses; - publishing uses
PUT /api/v1/packages/<scope>/<name>/<version>with a length-prefixed metadata + archive frame, and yanking usesPATCH /api/v1/packages/<scope>/<name>/<version>/yank; - remote
cabin publish(an HTTP index source without--registry-dir) reuses the local staging pipeline byte-for-byte: the same validation, the same publish lints, and the same deterministic archive plus canonical per-version metadata document ascabin publish --registry-dir- only the final write differs, going through the typedcabin-registry-apiclient to the API origin the registry’sconfig.jsondeclares.
The registry service itself - accounts, token issuance, storage -
remains outside the OSS core, in the repository’s separate registry/
workspace.
Out Of Scope
The local OSS core deliberately excludes:
- registry account or ownership services (the server side of the experimental protocol above);
- artifact signing policy;
- Git repository indexes;
- persistent HTTP metadata caching;
- binary artifact caches or remote build caches.
See package-index.md,
package-format.md, and
artifacts.md for the concrete on-disk documents and
archive rules.