Docs
CLI
Run it with your package manager’s runner — pnpm dlx, npx, yarn dlx or bunx. There is nothing to install globally.
Commands
| Command | What it does |
|---|---|
| init | Writes components.json, the cn() utility and the design tokens. |
| add <names…> | Installs components and everything they depend on. |
| list | Shows the registry, marking what you already have. |
| update [names…] | Compares installed components against the registry. |
| plan <prompt> | Chooses the blocks and components for a screen you describe; --model asks Claude. |
| diff [names…] | Shows how installed files differ from the registry's current ones. |
| doctor | Checks the setup, installed components, updates and agent docs. |
| audit [paths…] | Finds hardcoded colours, off-scale sizes, physical directions and bypassed components. |
| agents [targets…] | Writes the catalogue for the coding agents working in this project. |
| login [key] | Stores a licence key, for components that require one. |
| logout | Removes the stored key for --registry, or every stored key. |
| whoami [--check] | Reports whether this machine is signed in. |
Flags
| Flag | What it does |
|---|---|
| --registry <url> | A registry base URL, or a directory on disk. |
| --cwd <path> | Run against a different project root. |
| --yes | Accept defaults and never prompt. For CI. |
| --overwrite | Replace files you have edited. Says what it discards. |
| --skip-install | Write files without installing npm packages. |
Your edits are safe
add records a hash of every file it writes. That is what lets update tell three things apart: a file you have not touched, one you have edited, and one that changed upstream.
Re-running add on an untouched project does nothing. Re-running it after you have edited a component leaves your version alone and says so.
up to date src/components/ui/spinner.tsx locally modified src/components/ui/button.tsx up to date src/components/ui/calendar.tsx ! Only locally modified files differ; none were touched.Re-run with --overwrite to replace them and lose those edits.Checking a project
doctor checks a project’s setup and prints a checklist: React, TypeScript and Tailwind 4; the import alias still matching tsconfig.json; the tokens still in the stylesheet; every installed file still present; the npm packages they import; updates available; and whether the agent docs are stale. It reports what it finds rather than a score, writes nothing, and exits non-zero only when something fails. --offline skips the checks that need the registry.
audit reads the project’s own code for the ways a design system erodes: Tailwind palette colours, literal colours in classes or inline styles, arbitrary sizes off the spacing scale, physical utilities like ml-4 that break right-to-left layouts, and a native <button>, <input> or <dialog> where the Dowel component is installed. It skips the files Dowel wrote, and runs the same rules as the library’s own CI. --fix rewrites only the physical utilities, whose logical form is exact, and asks first. --json is for CI.
diff shows the change behind an “update available”: a unified diff from your file to the registry’s, so an upstream fix can be read before it is applied, or carried across by hand into a file you have edited.
Licensed components
Components that require a licence are listed in the registry like any other — with their description, what they depend on and how many files they are — but their source is served only to a licence holder. login checks the key against the registry before storing it, so a bad key fails when you paste it rather than days later during an install.
The key is stored in your own config directory, readable only by you, and never in the project: a key in components.json is a key in git. For CI, set DOWEL_TOKEN from your secrets store instead — it takes precedence over anything stored, which is also what logout will tell you if it is still set.
A key is only ever sent to the registry it belongs to, and only over HTTPS. A stored key belongs to the registry login checked it against; one in DOWEL_TOKEN belongs to the default registry unless DOWEL_TOKEN_REGISTRY names another. The registry an install reads comes from components.json, which is part of whatever repository you are in, so the CLI refuses rather than send your key to a server that repository chose.
Private registries
--registry takes an HTTPS URL or a path on disk, so a fork or an internal mirror works without forking the CLI. It can also be set once in components.json.
@dowel-ui/registry builds one. An organisation declares its own components and extends this registry, and the result is a single URL serving both — so add acme-callout installs their component and pulls in whatever it depends on from upstream. A local item replaces an upstream one of the same name, and the build reports which, because doing that by accident is expensive.
The build refuses to emit a file it cannot read, an import written against the installed path rather than the authored one, or a component that imports something it never declared. Each of those would otherwise fail in a consumer’s repository, where it is hardest to trace.
What it will not do
- Install into a Tailwind v3 project. The tokens use
@theme, which v3 cannot parse. - Install into a JavaScript project. The published source is TypeScript; a half-working transform would be worse than a clear refusal.
- Overwrite a file you have edited, without
--overwrite.