Registry Format
The registry is the source of truth for every installable component, block, page, bundle, and theme.
Each item is an item.json manifest plus one or more source
files living under registry/open/ or
registry/pro/. Running
php artisan registry:build validates the tree, inlines
file content and SHA-256 hashes, and writes JSON endpoints under
public/r/<tier>/ that the
ui:add CLI fetches and writes into the consumer app.
Note
ui:show and ui:add report.Manifest
Every item declares itself through an item.json file
at the root of its source directory. Below is the real manifest for the
Button component.
{
"name": "button",
"type": "registry:component",
"title": "Button",
"description": "Displays a button or link with variants, sizes, loading and an optional animated arrow.",
"version": "1.2.1",
"license": "open",
"stability": "stable",
"knowledge": {
"keywords": ["action", "submit", "call to action"],
"useWhen": ["Triggering an immediate action such as saving or submitting."],
"avoidWhen": ["Representing a persistent on/off value; use switch or checkbox."],
"related": ["button-group", "toggle"]
},
"registryDependencies": [],
"dependencies": {
"composer": ["jml/brok:^0.2"],
"npm": []
},
"files": [
{
"path": "ui/button/button.blade.php",
"target": "resources/views/components/ui/button.blade.php",
"type": "blade"
}
],
"meta": {
"a11y": "wcag-2.2-aa-target",
"responsive": true,
"rtl": true,
"darkMode": true,
"localized": true
}
}
Field reference
| Field | Type | Description |
|---|---|---|
| name | string | Slug used by the CLI (ui:add button) and as the registry key. Lowercase, hyphenated. |
| type | string | Item kind. One of registry:component, registry:block, registry:page, registry:bundle, or registry:theme. Drives target and catalog validation. |
| title | string | Human-readable display name shown in docs and the CLI confirmation prompt. |
| description | string | One-sentence summary rendered on the docs index and in ui:status output. |
| version | string | Semver string. ui:diff and ui:update compare this against what is recorded in the consumer's ui-lock.json. |
| contractVersion | integer | Version of the normalized human/agent contract emitted by the builder. Authored v2 manifests are checked against their Blade prop names and defaults. |
| foundationVersion | semver | Minimum shared ui.css/_styles.php foundation required by the item. The CLI blocks incompatible installs. |
| license | string | "open" (MIT, no auth required) or "pro" (commercial, requires ui:auth). Must match the tier directory the item lives in; the build enforces parity. |
| stability | string | Maturity signal ("experimental", "incubating", "stable", or "deprecated"). Change impact is recorded separately in migrations. |
| registryDependencies | string[] | Other registry item slugs this item requires. The CLI resolves them recursively (with a cycle guard) and installs them automatically. Open items may not depend on pro items. |
| knowledge | object | Guidance for humans and agents: keywords, use/avoid cases, anatomy, source-derived props/slots, behaviour, examples, related items, accessibility, and theming. Sparse authored data is completed by the builder. |
| composition | object | Machine-readable layout contract: kind, surface, frame, regions, responsive rules, states, and components used. Blocks and pages expose it through ui:show --skeleton. |
| api | object | Stable component props, slots, attribute forwarding, keyboard behavior, focus behavior, JavaScript requirements, validation, and Livewire compatibility. The builder derives and signs it. |
| accessibility | object | Exact component capabilities for keyboard input, focus management, focus traps, focus restoration, Escape dismissal, ARIA requirements, roles, and ARIA attributes. |
| examples[] | object[] | Versioned executable Blade examples copied from the component preview source. The CLI, MCP server, docs, and external renderers can use them without page scraping. |
| migrations[] | object[] | Structured from/to migration guidance, summary, breaking flag, optional manual steps, and optional codemod identifier. |
| deprecation | object | Required when stability is deprecated: version introduced, replacement item, removal horizon, and optional message. |
| dependencies.composer | string[] | Composer package constraints required by the item. Source manifests omit jml/brok; the builder injects the canonical release line into published items, and the CLI enforces it before add/update. Other Composer requirements remain manifest metadata for the consumer to install. |
| packageConstraint | string | Exceptional source-only override for the builder-injected jml/brok constraint. First-party items normally omit it and inherit registry.package_constraint. |
| dependencies.npm | string[] | npm package requirements (e.g. "alpinejs:^3.0"). The CLI prints the required npm install command; it does not mutate package.json or run npm. |
| files[].path | string | Path to the source file relative to the tier root (registry/<tier>/), i.e. <kind>/<name>/<file> such as ui/button/button.blade.php. This is the single edit point for that file. |
| files[].target | string | Where the file lands in the consumer's project. Must be under resources/views/components/ui, resources/views/blocks, resources/views/pages, resources/js/ui, resources/css/themes, or public/vendor/brok (static files loaded by URL, such as the theme-script boot file). The build rejects any target outside these paths. |
| files[].type | string | File kind: "blade", "js", or "css". JS is wired into resources/js/ui/index.js; registry theme CSS receives a managed import in resources/css/ui.css. |
| meta | object | Quality signals: a11y, responsive, rtl, darkMode, localized. Displayed as capability badges in the docs UI. |
The build pipeline
php artisan registry:build (the BuildRegistry command in
apps/docs-registry) runs in four stages:
-
Scan — walks every
registry/<tier>/<kind>/<name>/item.jsonand loads the manifest. - Validate — checks that every declared source file exists, targets stay inside the allowed path set, license flags match the tier, and open items carry no pro dependencies.
-
Inline — reads each source file and
embeds its UTF-8 content plus a
sha256hash directly into the published JSON so the CLI can detect transport corruption after download. (The hash is co-shipped with the content, so it guards against accidental drift, not a tampered registry — see the integrity note below.) -
Write — emits
public/r/<tier>/<name>.jsonper item and a tier-levelpublic/r/<tier>/registry.jsonindex.
On the consumer side, ui:add <name> fetches the item
JSON from the registry endpoint, writes each files[].target
into the app, resolves registryDependencies recursively
(a cycle guard prevents infinite loops), wires any JS files into
resources/js/ui/index.js, and records the installed version
in ui-lock.json.
Three places must stay in sync
A registry item is only fully "done" when it exists in all three of the following
locations simultaneously. Guard tests (CatalogNavigationTest,
MirrorParityTest, BlockRenderTest)
enforce parity in CI and fail fast when any location is missing.
1. Registry source
registry/open/<kind>/<name>/ — the
item.json manifest plus all source files. This is the
single edit point. Never modify files anywhere else to "fix" the component.
2. Docs-app render + JS copy
The docs site renders each item's Blade in place from
registry/ via non-prefixed anonymous component paths;
there is no per-item Blade mirror. Each item's behaviour JS is copied into the docs app at its
files[].target because the lazy loader can only glob
resources/js/ui/**. Run
php artisan registry:mirror — never hand-copy files.
3. Catalog entry
The kind-specific file under apps/docs-registry/catalog-data/ drives
navigation, docs pages, and every catalog-driven guard test. An item that is installable but
not listed there is invisible. Block and page render providers derive from the catalog row; do not maintain a second test list.
Note
php artisan registry:mirror manually. Drift is gated by
php artisan registry:mirror --check, which runs inside
composer check and CI and exits non-zero if any shared
asset or per-item JS copy diverges.Validation rules
The build command rejects any manifest that violates the following rules. All checks
also run with --dry-run so you can validate without writing
output files.
-
—
Every declared file must exist.
Each
files[].pathis resolved against the item source directory; the build fails if the file is missing. -
—
Open items may not depend on pro items.
Any slug in
registryDependenciesis checked against the tier of the dependency; cross-tier references from open → pro are rejected. -
—
Targets must stay under allowed paths.
Valid prefixes are
resources/views/components/ui,resources/views/blocks,resources/views/pages,resources/js/ui,resources/css/themes, andpublic/vendor/brok. Any other target path is rejected. -
—
Published files carry SHA-256 hashes and inlined content.
The build computes a
sha256of each source file and embeds both the hash and the full file content in the published JSON. The CLI recomputes the hash on write and aborts on a mismatch. Because the hash is co-shipped with the content, this catches transport corruption and accidental drift — by itself it is not a defence against a tampered or malicious registry (an attacker who can alter the response can recompute a matching hash), and unpinned consumers rely on HTTPS transport trust to the registry host. For provenance independent of the transport, pin the publisher's Ed25519 key asregistrySigningPublicKeyinui.json: bothui:addandui:updatethen verify the registry index against its detached signature before trusting anything, failing closed on a missing or invalid signature, reject a replayed older index, and bind every fetched item to the signed index's per-item content hash — a shipped guarantee, not a planned one. -
—
License flags must match the source tier.
An item under
registry/open/must declare"license": "open"; an item underregistry/pro/must declare"license": "pro". -
—
Names are stable install slugs.
The
namefield is the CLI key and must match the catalog slug. Namespaced components may use a nested source path whose leaf differs from that slug, such asai-promptinui/ai/prompt.
Validate locally
Run the build in dry-run mode from the apps/docs-registry
directory to catch manifest errors without writing any output files:
php artisan registry:build --dry-run
To also check that shared assets and per-item JS copies are in sync with their canonical sources (useful before opening a PR):
php artisan registry:mirror --check
Item lifecycle
States and rules
proposed → experimental → stable → mature → deprecated → frozen → removed
- Experimental items can include breaking changes after an item version increase.
- Experimental and incubating components, blocks, and pages install into an
experimentalnamespace. - Stable items cannot depend on experimental or incubating items.
- Each unstable item records a feedback URL and adoption evidence.
- The registry build blocks promotion when the configured adoption threshold is not met.
- Removal needs a deprecated release and a record in
registry/removed-items.json. - A renamed or merged item leaves an alias in
registry/<tier>/aliases.json:ui:addinstalls the replacement and the old URLs redirect. - The computed engine maps the legacy
incubatingmanifest value toexperimental.
Generated evaluation
A scheduled engine evaluates each registry item and core token across adoption, quality, performance, and maintenance. It joins repository manifests, static inventory, CI quality results, runtime telemetry, contribution data, bundle budgets, contrast checks, and removal records.
The protected lifecycle queue separates the declared state from the evaluated and recommended states. A recommendation never changes source or removes an item without owner review.
Promotion evidence
Use ui:inventory --report for project and reference counts. Use the pilot survey for recommendation feedback. Record the reviewed snapshot in lifecycle.adoption.
| Target | Projects | References | Survey responses | Score |
|---|---|---|---|---|
| Incubating | 1 | 3 | 1 | 3.0 |
| Stable | 3 | 10 | 3 | 4.0 |
Warning
composer check shortcut in
apps/docs-registry runs
registry:mirror --check, Pint, and the full test suite
in one command. Run it before pushing to confirm nothing is out of sync.