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.
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.
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.
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.
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.
- 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.
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.
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.
- 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.