Shelf is open source and in early preview
Shelf
Get started

Registry

Where the system team publishes, and every product adds from. Plain files on any static host.

A registry holds components, blocks, foundations, and the helpers they share. The system team publishes to it and products add from it. Each product records the revision it installed, so the team can see who is behind, and each product can see what changed upstream.

one registry, every product
One registry holds button, dialog, and foundations with their revisions. Three products add from it with shelf add; each records what it installed, and one has changed its button locally.

What's in a registry

Plain files, no database and no service. index.json lists every item, and each item is a folder with a registry.json and its source.

layout
A registry folder: index.json, then one folder per item.
components/dialog/registry.json
type
component, block, foundation, or lib. It decides where the files go.
files
The source that gets copied. Stories and tests stay behind.
dependencies
Packages that shelf add installs.
shelfDependencies
Other items it builds on, added with it the first time.
figma
Optional. A figma.com link to the item's design. The registry site shows Open in Figma; it doesn't change the revision.

Blocks

A block composes components into a finished piece of a page, such as a login form or an app shell. It is an item like any other: shelf add login-form adds the components it uses, then writes the block to paths.blocks, which defaults to src/components/blocks. Its imports point at your copies of those components. See Blocks.

Revisions

A revision is a hash of an item's files and dependencies, computed by Shelf. Change a line and the item has a new revision; there is nothing to bump by hand. Every product records the revision it installed in .shelf/lock.json.

Staying in sync

shelf status shows which installed items have a newer revision, and shelf update brings them up to date. When the revision hasn't changed, nothing happens. When it has, files you haven't touched take the new version, files only you changed stay yours, and files you and Shelf both changed are merged, with conflict markers where you both changed the same lines. Pass --overwrite to take Shelf's version instead.

terminal
shelf add button when the product is already up to date.

Items a component builds on, such as foundations, stay as they are when you add something else. Shelf says when a newer version exists and which command updates it. See ownership and provenance for every case.

Hosting

Point registry in shelf.config.json at a directory or an http(s) URL. To publish, build it once and upload the output to any static host.

build validates every item the way add reads it, then writes only the files that install. It also writes revisions/: every revision the items have had in git history, so a product can always get back the exact version it installed. Build from a full clone; a shallow one only has today's revisions.

Shelf Registry

The same build is also a site. Open the registry URL in a browser to browse every item with its source, revisions, and Storybook previews, and to see where each one is used. The folder that shelf add installs from is the one people read, so the two can't disagree.

Catalog
Every item with its description, install command, packages, and the items it needs and is needed by.
Source and history
The files an item installs, highlighted, and each revision it has had with the commit that introduced it.
Previews
Stories from a Storybook build, passed with --storybook and served from the same host.
Usage
A matrix of projects by item, grouped by namespace, from a usage.json passed with --usage. Each project has a page with the command that fixes each item.
Agents
llms.txt lists every item and links its registry.json, so an agent can find the right one before writing new UI.
.github/workflows/registry.yml

Pass --no-site to write only the files that install.

Usage

shelf usage reads what is already in git: each project's .shelf/lock.json and the imports in its source. It reports which items each project installed, which it actually imports, which are out of date or changed locally, and which it uses through a shared workspace package instead of its own copy. No service collects anything; run it wherever the code is.

terminal
shelf usage over two apps and the shared package they import.
Projects
Every directory with a shelf.config.json. Set "project": "payments/bill-pay" to name it; the part before the last slash is its namespace.
Shared packages
A workspace package that installs items and re-exports them credits the apps that import it.
Revisions
An item counts as this registry's when its revision is the current one, one from git history, or one in revisions/.
Output
--json writes the whole graph, sorted, so the same code always gives the same file.

Across repositories

--github acme finds every repository in the organization with a shelf.config.json through GitHub code search. Shelf makes a shallow clone of each, reads it, and deletes it; a repository already scanned from a local directory is skipped. The token comes from GH_TOKEN or GITHUB_TOKEN: use a GitHub App token or a fine-grained personal access token that can read the repositories. It is sent to GitHub as a header, never written into clone URLs. For other hosts, pass each repository with --repo.

.github/workflows/registry.yml

usage.json includes file paths and repository URLs. When it covers private code, publish the registry to a host behind your sign-in, not public GitHub Pages.

Formatters

Shelf compares installed files byte for byte with what it installed, so a formatter that rewrites them makes every item look changed. Exclude installed paths from your formatter, or accept the reformatted files as your own changes.

.oxfmtrc.json

Private registries

A registry behind sign-in takes request headers. Write the token as a ${VAR} reference so the config can be committed and the secret can't.

shelf.config.json
Variables
Read from the environment first, then .env.local, then .env in the project root. A missing one fails before any request, naming the variable.
HTTPS only
Shelf won't send headers over plain http, except to localhost.
Redirects
Followed only within the same origin. A redirect elsewhere, usually to a sign-in page, fails instead of passing your token along.
Errors
A 401 or 403 shows the server's message and what to check. Header values are never printed or written to the lock.