A component library can be well documented and barely used. Measuring adoption starts with finding where its components and tokens appear in the products it serves.
This is a proposed specification for a read-only Rudiment UI scanner. The rudi check commands and reports below describe the intended interface; they are examples for a tool to be built and validated.
Why measure by namespace
Import-based measurement has to account for aliases, wrappers, and re-exports. A tag-based approach offers another useful signal: references to a library’s custom-element namespace in source files.
For Rudiment UI, <rudi-button> is a recognizable usage-site reference across template languages. A scanner can count that tag without first resolving which imported Button a file uses.
- Identity is stable at the usage site. A scanner matches the tag name without tracing imports, resolving barrels, or guessing about wrappers.
- Source and runtime answer different questions. Source references show where teams integrate the library. Runtime sampling shows what rendered in the states you visited. Keep those counts separate: one source reference may render many times or never render in a sampled session.
- Other custom elements are review candidates. Separate
rudi-*tags from other custom-element references. The latter may be product-specific elements, third-party dependencies, or duplicated patterns. Review them before calling them recreations. - Token references provide a second signal. Count
var(--rudi-*)references and collect literal color values for review. A literal value may be an intentional exception; its presence alone does not establish token drift. - The namespace works with zero tooling. GitHub code search for
rudi-across the organization gives you a rough adoption census before you build anything. The CLI below makes that structured, repeatable, and trackable. - Test each supported syntax. A shared namespace gives the scanner a common target across frameworks. Each parser still needs fixtures for the template languages and component wrappers used by consuming teams.
Static scanning can miss dynamically assembled tags and usage hidden behind wrappers. Document these limits in the report. Runtime sampling can supplement the scan, but its coverage depends on the pages and states visited.
The rudi check CLI
The proposed rudi check command would run at a repository root, parse supported source files, count namespace references, and emit a JSON report with review signals.
What it scans
| Source | What it extracts |
|---|---|
.html, .astro, .vue, .svelte, .jsx, .tsx, .js, .ts | Hyphenated element tags, split into rudi-* and foreign; bare interactive HTML elements (button, dialog, input, select, details); attributes passed per rudi-* element |
Tagged template literals (Lit html, css) | Same tag and attribute extraction inside the literal |
.css, and <style> blocks | var(--rudi-*) references; non-token color values (hex, rgb(), hsl(), oklch()); --rudi-* overrides |
package.json and lockfile | Declared and resolved versions of @rudi/* packages |
Counting rule: count source-level references, not rendered instances. A rudi-button inside a shared header counts once, no matter how many pages render it. State this rule in every report so the numbers aren’t misread.
Output schema
An illustrative report, using example repository names, versions, and counts:
{
"schemaVersion": 1,
"generatedAt": "2026-07-21T06:00:00Z",
"repo": "acme/checkout",
"commit": "9f2c1ab",
"scanner": { "name": "@rudi/check", "version": "0.1.0" },
"versions": {
"declared": { "@rudi/core": "^2.3.0" },
"resolved": { "@rudi/core": "2.3.1" }
},
"elements": {
"rudi-button": {
"count": 42,
"files": 17,
"attributes": { "variant": 40, "disabled": 12, "class": 31 }
},
"rudi-dialog": { "count": 6, "files": 4, "attributes": { "open": 6 } }
},
"tokens": {
"references": { "--rudi-color-surface": 12, "--rudi-space-3": 44 },
"overrides": { "--rudi-color-accent": 2 }
},
"foreign": {
"customElements": { "acme-card": 9, "acme-toggle": 3 },
"bareInteractive": { "button": 4, "dialog": 1 },
"hardcodedColors": { "count": 23, "files": 9 }
},
"coverage": {
"elementCoverage": 0.87,
"tokenCoverage": 0.79
}
} Field notes:
schemaVersionlets you evolve the format without breaking the dashboard. Bump it on any breaking change.elements[*].attributesis the web components equivalent of prop tracking: frequentclassorstyleusage can prompt a review of defaults. Confirm the reason with consumers before changing an API or removing an apparently unused attribute.foreign.customElementslists non-library references for review. Names let a team investigate whetheracme-togglefills a legitimate product need or duplicates an existing pattern.elementCoverage= rudi element references ÷ (rudi + foreign custom elements + bare interactive elements).tokenCoverage= token references ÷ (token references + hardcoded color values). These are source-reference ratios, not measures of visual quality or the percentage of a product using the system. Some non-library references are appropriate.- Version data rides along in every report, so version-lag tracking needs no separate pipeline.
Commands
Proposed command interface:
rudi check # human-readable summary to stdout
rudi check --report out.json # machine-readable report
rudi check --ignore "**/legacy/**" Ship it as a report-only tool first. Don’t fail builds on adoption thresholds. Measurement tooling that blocks merges gets uninstalled; enforcement, if you want it, belongs in a later phase after teams trust the numbers.
GitHub Actions rollout
Start with a few repositories whose maintainers can check the results. Once the parsers and counting rules are reliable, a central scan could collect reports without requiring every team to install a workflow. The following is a rollout sketch; the scanner package and organization-scan script would need to be implemented first.
- Publish
@rudi/checkto your registry. - Create a
rudiment-metricsrepository to hold reports and the dashboard. - Add a scheduled workflow (weekly is enough) that lists organization repositories through the GitHub API, shallow-clones each, runs
rudi check --report, and commits the output todata/<repo>/<date>.json. - Build the dashboard as a static page that reads the JSON history. Astro fits, and it can live in the Field Guide, next to the docs that improve it.
- Later, offer an opt-in reusable workflow so teams can surface their own report as a PR comment.
Minimal workflow sketch:
name: rudiment-adoption-scan
on:
schedule:
- cron: '0 6 * * 1'
workflow_dispatch:
jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm install -g @rudi/check
- run: node scripts/scan-org.js # clones repos, runs rudi check, writes data/
env:
GH_TOKEN: ${{ secrets.ORG_READ_TOKEN }}
- run: |
git config user.name "rudi-bot"
git config user.email "rudi-bot@users.noreply.github.com"
git add data && git commit -m "chore: weekly adoption scan" && git push Questions the data answers
- Version lag: resolved
@rudi/coreversions across repositories, and how long each lags behind. - Component health: usage per component, attribute histograms, and override rates, ranked for improve-or-deprecate calls.
- Non-library references: other custom elements per repository, with team review to identify genuine gaps or duplication.
- Potential token drift: literal color values to review alongside intentional exceptions.
- Coverage trend: element and token coverage per repository, week over week.
Scaling the approach
Begin with a small baseline and manually inspect a sample of matches and misses. Record the scanner version and counting rules so later reports remain interpretable. Expand to scheduled scans and dashboards when the numbers answer questions teams can act on.