npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@urbicon-ui/design

v8.7.0

Published

The urbicon CLI — version-pinned design validation and design-manifest tooling for projects built with Urbicon UI. Wraps @urbicon-ui/design-engine for editor hooks and CI.

Readme

@urbicon-ui/design

The urbicon CLI — version-pinned design validation and design-manifest tooling for projects built with Urbicon UI.

It is the local, version-correct half of the Urbicon design loop: the knowledge and rules are the ones shipped with the @urbicon-ui/* version you installed, and the filesystem operations (reading/writing your project's design.manifest.md) run on your machine — things a public, stateless remote MCP server structurally cannot do. Under the hood it wraps the zero-dependency @urbicon-ui/design-engine; the same engine backs the remote validate_design MCP tool, so local and remote verdicts agree.

What the loop buys, measured. One A/B pair on v8.3.1 (2026-08-18): Haiku 4.5 built the same three-page auth app twice, with @urbicon-ui/* installed either way. One run had this CLI and its edit-time gate wired in, the other had neither.

| | left to itself | CLI + gate wired | | --------------------------------- | -------------- | ---------------- | | urbicon validate src/ | 373 errors | clean | | — raw Tailwind colours | 273 | 0 | | — hand-written dark: patches | 96 | 0 | | — focus not focus-visible | 4 | 0 | | knowledge lookups / package reads | 0 / 8 | 23 / 0 | | catalog components re-implemented | 72 | 29 | | blind-judged design quality | 16/40 | 17/40 |

The mechanism is the lookups row: without the CLI the agent reads the installed package and guesses; with it, it asks and gets the answer for the version it actually has.

The last three rows are the honest limits, and they matter more than the headline. A clean validate means the linter found nothing, which is not the same as correct — the wired run still shipped text-on-surface-muted, a class naming no token, which therefore renders as nothing, and the linter missed it. Re-implementation drops but does not stop: a wired agent still hand-builds components the catalog ships. And design quality does not move. Two further findings from the same eval: the loop raises craft scores on no model tier (three tiers, three arms), and it does not make runs cheaper (two independent pairs, no advantage either time). Token discipline is what you get; taste and budget stay with you.

Install

bun add -d @urbicon-ui/design   # dev tooling — not a runtime dependency

This exposes the urbicon command (a self-contained, Node-runnable bundle — no Bun required at the consumer side).

Running it standalone (no local install). The bin is urbicon but the package is @urbicon-ui/design, so a bare bunx urbicon … from a project that hasn't installed it fails with GET …/urbicon 404 (it looks for a package literally named urbicon). To run the CLI without a local install, name both the package and the bin:

bunx --package @urbicon-ui/design urbicon validate src/   # or: npx --package @urbicon-ui/design urbicon …

Inside a project that already has @urbicon-ui/design installed, plain bunx urbicon … resolves fine.

Onboarding a consumer project

bun add -d @urbicon-ui/design   # then:
bunx urbicon init               # wire the project into the design loop

Starting from scratch? The @urbicon-ui/sv add-on (beta) does the mechanical setup in one line — bunx sv create my-app --add @urbicon-ui installs blocks + this CLI and wires the Tailwind stylesheet — and then hands over to urbicon init --hook below.

urbicon init is idempotent and non-destructive. It:

  1. Gives the agent context — inserts a managed <!-- urbicon:start … --> block into AGENTS.md (or --agents-file CLAUDE.md) describing the tools, the design loop, and the token rules. The single biggest lever on whether generated UI stays on-system.
  2. Seeds the design memory — scaffolds design.manifest.md (never overwriting an existing one).
  3. With --hook, merges the PostToolUse gate into .claude/settings.json; with --ci, writes the design-gate workflow.

After upgrading the library, re-run bunx urbicon init. The block is stamped with the CLI version that wrote it, and urbicon context — step 1 of the design loop — warns when the block's content no longer matches the installed CLI's template, so an agent sees the drift and can fix it itself. (The check is content-based: a release that doesn't change the template stays quiet, and a verbatim hand-paste of the current template counts as current.) A re-run refreshes the block in place wherever it lives (AGENTS.md or CLAUDE.md, in your casing); a hook entry or CI workflow you have customised is kept and reported, never overwritten.

Then run the guided intake — bunx urbicon verb adopt (brownfield) or onboard (greenfield) — to fill the manifest with this project's design intent. From there an agent can urbicon primer for the knowledge every task needs (component selection + the token core, one call), urbicon context to read the intent, urbicon find / get-component to discover the catalog, urbicon pattern / principles / css-reference for the task-specific rest, compose, and urbicon validate what it produced.

The component knowledge is local and version-pinned: @urbicon-ui/design pulls in the @urbicon-ui/design-content bundle, so find / get-component match the library version you installed — no extra install, no skew against the latest-only hosted MCP.

Commands

| Command | What it does | Replaces (remote) | | ------------------------------ | ----------------------------------------------------------------------------------------------------- | --------------------------- | | urbicon init | Wire a project into the design loop (AGENTS.md block, manifest scaffold, --hook/--ci). | — (local only) | | urbicon validate [paths...] | Lint .svelte markup against the design rules. The CI gate. | mirror of validate_design | | urbicon i18n [check] | Audit @urbicon-ui/i18n: parity / unused keys / hardcoded strings / audit (all). | — (local only) | | urbicon hook | PostToolUse adapter — validate the just-edited file, block on failure. | — (local only) | | urbicon primer | The always-needed bundle in one call: component selection + the token core. Run it first. | — | | urbicon find [query] | Fuzzy component discovery over the version-pinned catalog. | find_components | | urbicon get-component <slug> | A component's API (its llm.txt) from the bundle. | get_component | | urbicon icons [query] | Icon discovery (no query: the full grouped reference). | find_icons | | urbicon recipe [id] | Complete Svelte 5 code recipes from the catalog. | get_recipe | | urbicon guide [slug] | Canonical package guides (auth reference, blocks guide system, migration notes, table scroll models). | urbicon://guide/auth | | urbicon pattern [name] | Composition patterns per page archetype. | get_pattern | | urbicon principles | Design heuristics (--topic <t>); --rubric for the judge rubric. | get_design_principles | | urbicon css-reference [sect] | The token truth: naming, dark mode, override patterns. | get_css_reference | | urbicon context | Print the project's design.manifest.md summary. | get_design_context | | urbicon record-decision … | Append an ADR to the manifest. | record_design_decision | | urbicon sync-manifest | Re-index data-design-pattern markers into the manifest. | sync_design_manifest | | urbicon verbs | List the design verbs (recipes over the design loop). | the MCP prompts | | urbicon verb <name> | Print one verb recipe to stdout. | the MCP prompts |

The CLI covers the full knowledge surface locally, so the design loop runs offline and version-pinned end to end. When an urbicon-ui MCP connection is also present, prefer the CLI: the remote serves latest, the CLI serves the version this project installed.

The three manifest commands move off the remote server deliberately: a public remote server has no access to your repo's filesystem, so manifest upkeep belongs on the consumer side (this CLI, or the agent's own write tools).

validate

urbicon validate src/                    # lint a whole tree (CI)
urbicon validate App.svelte --strict     # fail on warnings too, not just errors
urbicon validate src/ --craft-floor 40   # also fail files scoring < 40/100 on craft
cat Page.svelte | urbicon validate -     # lint stdin
urbicon validate src/ --json             # machine-readable: { ok, craftFloor, results }
urbicon validate src/ --record           # also append a drift entry to the history (CI)

validate reads ## Token Overrides from your design.manifest.md (if present) and treats those token cores as valid, so a token your project defines on top of Urbicon's is not flagged as hallucinated — the local, manifest-sourced counterpart to the remote validate_design(extraTokens). Since v6.44 that is a genuine gate release rather than a warning tweak: token-hallucination is an error (a token that names nothing renders with no styling at all), so a manifest that declares your token is what keeps validate at exit 0. Nothing else is relaxed — the other error rules are unaffected. --record appends one ValidationHistoryEntry per run to the sidecar design.manifest.history.ndjson so drift is measurable over time (CI opts in; the editor hook stays silent).

Quoting is not violating. The class rules (raw colours, dark:/focus:, z-index/motion, hallucinated tokens, deep imports) scan only class-bearing content — class/*Class* attribute values, string/template literals in <script> and {…} expressions (tv() configs, slotClasses), and @apply — never element text content, style= attributes or other string attributes. A docs page that shows bg-green-500 in prose or a before/after snippet is not flagged for it. Plain .ts/.js input (a tv-config module) is scanned across all its literals; for extension-less non-Svelte stdin pass the engine's mode: 'code'.

Exemptions for deliberately off-system surfaces (a landing poster, a page rendering linter output): suppress specific rules — never everything — via

  • an in-file pragma, visible next to what it exempts: <!-- urbicon-ignore magic-dimension inline-style — reason --> (// and /* */ forms work in TS/JS); the em-dash starts the free-text reason;
  • or a ## Exempt section in design.manifest.md, one bullet per path: - `src/routes/+page.svelte` — `magic-dimension`, `inline-style` — reason (a trailing / on the path exempts the subtree).

Suppressions are always visible: the report prints n suppressed with per-rule counts (--json carries results[].suppressed), a suppression that matched nothing is marked stale, and an unknown rule id raises an invalid-suppression warning instead of silently suppressing nothing.

The linter scores two independent axes: correctness (raw colours, dark:/focus:, hallucinated tokens — deterministic, always the blocking gate) and craft (20 "looks generic" heuristics — advisory by default, because they are FP-prone). --craft-floor <n> opts the craft axis into the gate: any file scoring below n fails, checked per file so one generic page cannot hide behind clean ones. Leave it off and craft stays informational.

Exit codes — designed for hooks and CI:

| Code | Meaning | | ---- | ------------------------------------------------------------------------------------------------------------------------------- | | 0 | Clean, or only warnings/notes | | 1 | Failed — validate found errors (with --strict, warnings too), or a command could not complete (e.g. a manifest write error) | | 2 | Usage error — bad flags / unreadable input |

--skip-heuristics runs only the deterministic rules (no distribution notes).

i18n

Audit @urbicon-ui/i18n usage — one check, or audit for all. Run under Bun (it dynamic-imports .ts locale bundles).

urbicon i18n audit src/ --translations src/lib/translations  # parity + unused + hardcoded
urbicon i18n parity --json                                   # data-level locale audit only
urbicon i18n unused --dynamic-keys 'errors.*'                # scan, allowlisting dynamic key families
urbicon i18n hardcoded src/ --strict                         # gate the advisory hardcoded-string lint too

| Check | Finds | Gates? | | ----------- | ----------------------------------------------------------------------------------- | ----------------------------------------- | | parity | missing/extra keys, empty values, {{param}} drift, malformed/incomplete _plural | errors gate | | unused | defined keys referenced nowhere (confirmed/suspect) + keys used-but-undefined | used-but-undefined gates; unused advisory | | hardcoded | literal UI copy in .svelte markup that bypassed i18n | advisory (gate with --strict) |

Config via i18n.audit.json / --config + flags (--translations, --dynamic-keys, --ignore-keys, --ignore-strings, --base-locale); --json for CI. Backed by the @urbicon-ui/i18n/audit subpath; the pure data-level auditTranslations also runs as a Vitest assertion without the CLI.

context / record-decision / sync-manifest

urbicon context                       # summarise ./design.manifest.md
urbicon context --json                # the parsed manifest (+ history + contextBlock) as JSON

urbicon record-decision \
  --title "Tabs for settings" \
  --decision "Use Tab over Sidebar" \
  --rationale "Three groups, shallow nesting"

# Changed your mind? Link both ends instead of leaving two contradictory ADRs:
urbicon record-decision \
  --title "Sidebar for settings" \
  --decision "Use Sidebar over Tab" \
  --supersedes "Tabs for settings"

urbicon sync-manifest                 # scan ./src for data-design-pattern markers
urbicon sync-manifest --src app --manifest app/design.manifest.md

context summarises the whole manifest — the product intent (audience, voice, references, anti-references), the token overrides, the pattern-usage index, the recorded ADRs — and, when a *.history.ndjson sidecar exists, the recent validation-drift trend. All commands default the manifest to ./design.manifest.md and the scan root to ./src; override with --manifest / --src.

The manifest is a plain Markdown file with these sections (urbicon creates a scaffold on first write):

## Product Intent

**Audience:** who uses this — context, constraints, expertise
**Voice:** three adjectives, comma-separated
**References:** / **Anti-references:** bullet (or comma) lists

## Token Overrides

- `surface-brand` # project tokens `urbicon validate` should accept

## Pattern Usages # auto-generated by sync-manifest

## Design Decisions # append-only ADRs from record-decision, newest first by date

The ADR log is append-only and ordered by --date, so a back-dated entry lands where it belongs rather than on top. --supersedes "<title>" marks the named entry superseded and links both ends; urbicon context then lists it as history instead of as a current stand (it stays in the file — seeing that a stand was tried and dropped is the point of an append-only log). An unknown or ambiguous title fails loud rather than recording a dangling link.

Design verbs

Ten recipes that string the knowledge, the linter, and the manifest into one loop — the same single source that is served remotely as MCP prompts. They ship in this package under skill/, so they run offline and version-locked.

urbicon verbs            # list them
urbicon verb compose     # print one recipe — pipe it to an agent, or read it inline

| Verb | Use-case | | --------------------------------- | ---------------------------------------------------------- | | onboard / adopt | seed the manifest for a greenfield / brownfield project | | compose / redesign / polish | build / rework / tighten a page (gated on linter + rubric) | | critique / fix | judge without changing / repair correctness defects | | retheme / audit / migrate | rebrand / check consistency / roll out a change app-wide |

skill/SKILL.md is the router (intent → verb). Every recipe opens by reading the manifest and closes by writing the decision back.

Enforcement — hook + CI

The gate runs in two places a stateless remote server structurally cannot reach: at edit time (a Claude Code hook) and in CI. Ready-to-copy templates ship in templates/.

Edit-time hook. Wire urbicon hook as a PostToolUse hook so every edited .svelte file is validated the moment it is written — the loop becomes enforced, not something the agent must remember. On a failure the hook exits 2 and the findings are fed back to the agent to fix; a clean edit is silent. Merge templates/claude-settings.json into your .claude/settings.json:

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|MultiEdit|Write",
        "hooks": [{ "type": "command", "command": "bunx urbicon hook" }]
      }
    ]
  }
}

Add --craft-floor 40 to the command to gate the craft axis too. (urbicon hook reads the edited path from the hook event on stdin — it does not take path arguments.)

Keep the bunx prefix. A hook command runs in a plain shell whose PATH does not include your node_modules/.bin, so a bare urbicon hook exits 127 and gates nothing — and it fails silently, because the agent only ever sees exit 2. If your project was scaffolded before this was fixed, re-run urbicon init --hook: it repairs that exact entry in place.

CI. Run urbicon validate over your source tree; a non-zero exit fails the build. Copy templates/ci-github.yml, or add one step to an existing workflow:

bunx urbicon validate src/ --json              # correctness gate (blocking)
# add --craft-floor 40 to also gate the craft axis — one run, correctness is always on

Notes

  • Bundled to dist/cli.js at publish time (bun build --target node, shebang preserved). In the monorepo, run the TypeScript source directly: bun run packages/design/src/cli/index.ts <command>.
  • validate / hook / context / record-decision / sync-manifest / init are content-free (engine + your repo only); verbs / verb read the recipes shipped under skill/ (package-relative, still no content-bundle dependency); css-reference and principles --rubric come straight from the engine.
  • find / get-component / icons / recipe / guide / pattern / principles read the version-pinned @urbicon-ui/design-content bundle (a runtime dependency). The guided onboarding interview lives in the adopt / onboard verbs.

Related