SynthesisUI

CLI reference

One command line, your whole design system.

The synthesisui CLI brings a system into any project and hands your coding agent everything it needs to build on-system. No install - it runs with npx.

Start here

Run this in any project you already have. It reads your files, writes none of them, and needs no account.

npx synthesisui@latest doctor

It counts every design value written by hand and, once a system is installed, names the token your own system already has for each one. What it reports →

Free · no account, nothing sent anywhere

adopt

Turn the design system you ALREADY have into a contract your coding agent follows - without touching a line of your CSS.

synthesisui adopt [--write] [--tokens <path>] [--slug <name>]

`init` installs our tokens, which is why it ends in a one-time setup you have to do by hand. If your project already declares its own custom properties, none of that applies: they are in `:root` and already painting the screen, and what is missing is not code but the contract - the file your agent reads before it writes UI. So adopt writes no CSS at all. It reads your stylesheets, describes your system in `_synthesisui/`, and adds a managed block to CLAUDE.md pointing at it. Your tokens keep your names, your files are not rewritten, and `clean` removes every trace. It is a dry run by default: nothing lands on disk until you pass `--write`.

Options

--write
Actually create the files. Without it, adopt only shows what it would do.
--tokens <path>
Read one stylesheet instead of searching - for tokens somewhere the scan does not reach.
--slug <name>
Name the system yourself. The default is guessed from your token prefix, then your package name.

Examples

A dry run. Nothing lands on disk until you ask.

$ npx synthesisui@latest adopt
── Adopt ─────────────────────────────────────────────────────────

  Reading your system … 3 stylesheets, 29 tokens found

    colour      19
    spacing      6
    radius       4

    from src/app/globals.css (29)

  Would create (nothing written yet):
    _synthesisui/ds/acme/system.json    your system, described
    _synthesisui/ds/acme/GUIDE.md       what your agent reads
    CLAUDE.md                           a managed block pointing at it

  Your stylesheets are not touched. Nothing outside
  _synthesisui/ is written, and `clean` removes all of it.

Then `doctor` measures your code against your own vocabulary.

$ npx synthesisui@latest adopt --write

When the scan does not reach where your tokens live.

$ npx synthesisui@latest adopt --tokens src/styles/theme.css

import

Read the app you already have and turn it into your design system - v1 mirroring your own values exactly.

synthesisui import [--dir <path>] [--dry] [--name <name>] [--census <path>]

The entrance for somebody who already shipped something. It takes a CENSUS of your project: every colour, radius, spacing and font, ranked by how often it repeats, plus the tokens you already declare - all arithmetic, no inference, the same scan the doctor runs. `--dry` writes that census to `_synthesisui/census.json` and sends nothing, so you can read the payload before it leaves the machine. Without `--dry` (and after `login`) it becomes a design system on your account, and the promise there is fidelity: v1 carries YOUR values under YOUR names, nothing normalised, nothing improved, scoring exactly as well or badly as your app does. That honesty is what makes the v2 it proposes afterwards worth approving. A role your project never names is left neutral rather than guessed, and the report says how many. An agent can annotate the census with judgement a parser cannot make - which grey is the real grey, which family is the display voice - and send that back with `--census`; any value it invents that your code does not contain is dropped.

Options

--dry
Take the census and write it to disk. Nothing is sent and no account is needed.
--dir <path>
Read this folder instead of the current one. In a monorepo this is the important one: point it at the package that holds your vocabulary.
--census <path>
Send a census file you (or your agent) already annotated instead of taking a fresh one.
--name <name>
Name the system without being asked. At a terminal the command offers a name and waits; scripts and CI should pass this.

Examples

See what your code says before anything leaves your machine.

$ npx synthesisui@latest import --dry
── What your project says ────────────────────────────────────────

  next · react · tailwind
  2 files · 12 distinct design values
  10 color · 5 radius · 4 spacing

  #ffffff color, 3× in 2 files
  12px radius, 3× in 2 files
  #71717a color, 2× in 2 files

  Written to _synthesisui/census.json
  Nothing was sent. Read the file, then run it without --dry.

Needs `login` first - this is the moment something leaves the machine. It asks what to call the system before creating anything.

$ npx synthesisui@latest import

A monorepo has one system and several consumers. Born from the package that holds the vocabulary, then measure each app against it with `doctor apps/<name>`.

$ npx synthesisui@latest import --dir packages/ui
── This root holds several projects ──────────────────────────────

  3 apps (apps/web-admin, apps/web-dashboard, apps/web-review) - and this
  census is the average of all of them.
  That is a fine DIAGNOSIS and a poor system: a light app and a dark one
  average into a palette that is neither.

  The shape that works, if your vocabulary is shared:
      synthesisui import --dir packages/ui   the system comes from here
      synthesisui doctor apps/web-dashboard  how far this one is from it

connect

Wire your agent to the system: the check as a hook, the system as tools, and a contract that stops repeating itself.

synthesisui connect [--no-hook] [--no-mcp]

Three layers, and only the first one guarantees anything. The HOOK runs the check after every file your agent writes, so whether it happens stops being the agent's decision - measured on a real build, an instruction to run the check by hand sat at line 24 of a 44-line file and was ignored. The TOOLS let it ask this system what a value is called instead of guessing. And the CLAUDE.md block, seeing the hook installed, stops demanding a check that already happened, because two places asking for the same thing is drift in the instructions. Both config files belong to you: every write is a merge, running it twice changes nothing, and a file it cannot parse is refused rather than replaced. Restart your editor session afterwards - hooks and tools are only read at startup.

Options

--no-hook
Skip the hook. The tools and the contract still land.
--no-mcp
Skip the tools. The hook and the contract still land.

Examples

Both layers, merged into whatever config is already there.

$ npx synthesisui@latest connect
── Connected ─────────────────────────────────────────────────

  ✓ .claude/settings.json  the check now runs after every write
      npx synthesisui@0.16.13 hook
  ✓ .mcp.json              four tools, so the agent can ask instead of guess
  ✓ CLAUDE.md              rewritten for what is installed

  Reopen your editor session - both are read at startup.

mcp

The design system as tools your agent can query. Local, no account, no network.

synthesisui mcp

Started by your editor, not by you - `connect` registers it. Four tools: check_file measures one file and names the token this project already has for every literal; find_token answers what the system calls a value, and refuses when nothing holds it; list_components is the live catalogue with what each component is for; add_component materializes one as real code. It reads the system already installed in the project, so it works offline and needs no account.

Examples

You never run `mcp` by hand. This registers it - then restart the session.

$ npx synthesisui@latest connect

hook

The check, run by your editor after every write rather than remembered.

synthesisui hook

Started by your editor, not by you - `connect` installs it. It reads the file that was just written and reports the token this project already has for anything hardcoded, plus any --ds- name the system does not declare. It never blocks: refusing an edit makes the check an adversary, and an adversary gets disabled within a day. And it is silent when there is nothing to say, because a hook that speaks on every edit is noise, and noise is what gets a hook removed.

Examples

You never run `hook` by hand. This installs it - then restart the session.

$ npx synthesisui@latest connect

doctor

Audit any repo for drift - every design value written by hand, and the token your system already has for it.

synthesisui doctor [paths…] [options]

The only command that needs nothing: no account, no install, no network. It reads your files and writes none of them. It does not need a system from us either: if your project declares its own tokens - `--acme-color-primary` in `:root`, Tailwind v4's `@theme`, anything at the root - it measures your code against YOUR vocabulary and names the drift with your own words. With one of our systems installed it also reports where the code overrules a component the system defines, and where the system contradicts itself. With no tokens anywhere it still counts the distinct design values written by hand, which is the number worth knowing before anything else.

Options

--verbose
Every finding, file by file. The default is a summary.
--strict
Exit 1 when THIS repo has drift or overrides - for CI.
--strict-system
Also exit 1 when the design system itself is inconsistent.
--laws
Show every usage law, not just the busiest components.

Examples

Nothing installed yet? It still has something to tell you.

$ npx synthesisui@latest doctor
── Doctor ────────────────────────────────────────────────────────

  No system installed - 1 file read

  4 distinct design values are written by hand here.
  No design system is installed, so none of them has a name yet.

  Give them one:
      npx synthesisui@latest init --ds <slug>

With a system installed, every loose value gets named.

$ npx synthesisui@latest doctor
── Doctor ────────────────────────────────────────────────────────

  Ember v22 - 87 tokens, 3 files read

  Token coverage  ░░░░░░░░░░░░░░░░░░░░░░░░    0%
                  0 from the system, 6 by hand

  6 values by hand · 5 already have a name
  4 overrides · 4 left the system

  Where to start
      1. the 4 overrides that left the system  4 places
      2. #f5f2f6 → --ds-color-obsidian-100     2 files  (cheap)
      3. #a79eb2 → --ds-color-obsidian-300     2 files  (cheap)

In a monorepo, point it at what you actually ship.

$ npx synthesisui@latest doctor apps/web packages/ui --verbose

Exits 1 when this repo drifts. Drop it in CI.

$ npx synthesisui@latest doctor --strict

login

Connect the CLI to your account (device flow).

synthesisui login

Opens a short device-code flow so the CLI can reach your private systems and the hosted AI commands. Public gallery systems don't need it.

Examples

$ npx synthesisui@latest login
→ opening https://www.synthesisui.com/device?user_code=WXYZ-1234 (code pre-filled)
✓ logged in as you@company.com

init

Write _synthesisui/config.json (framework target + folders) and optionally bring a system in.

synthesisui init [options]

Bootstraps a project: records where pages and components live and which framework you target, so later commands need no flags. With --ds it also pulls that system in right away (tokens + rules + philosophy + CLAUDE.md).

Options

--styles <css|tailwind>
How materialized components are styled (default: css).
--target <next|general>
Framework target (default: next).
--pages-dir <dir>
Where generated pages go (default: app).
--components-dir <dir>
Where components live (default: components).
--ds <slug>
Bring this system in immediately.

Examples

$ npx synthesisui init --styles tailwind

bootstrap and bring a system in, one step.

$ npx synthesisui init --styles tailwind --ds halogen

list

List the published design systems.

synthesisui list

Examples

$ npx synthesisui list
ember        v13   Warm obsidian, incandescent gradients
halogen      v11   Cool, clinical, high-contrast
…

add

Materialize a design system into _synthesisui/ds/<slug>/ (tokens, recipes, GUIDE, CLAUDE.md).

synthesisui add <slug> [options]

Brings the whole system into your project: tokens.css + theme.css, the recipe catalog, rules.md / philosophy.md (when authored) and a GUIDE.md the agent reads. Public systems need no login.

Options

--version <n>
Pin a version (default: latest).

Examples

$ npx synthesisui add halogen
$ npx synthesisui add halogen --version 3
$ npx synthesisui add halogen
✓ Halogen v11 → _synthesisui/ds/halogen/
✓ CLAUDE.md updated - the agent now knows the system

use

Print a ready-to-paste prompt for your coding agent to build/modify UI on-system.

synthesisui use <slug> "<intent>"

Reads only local state (no network) and prints a prompt describing the task on-system: which files to read first, the data-ds scope, the styling contract and where files go. Works for both building new UI and modifying existing UI. Pipe to pbcopy to copy just the prompt.

Examples

$ npx synthesisui use halogen "a pricing section with three tiers and a highlighted plan"

modifying existing UI - it locates the file first, then changes only what's needed.

$ npx synthesisui use halogen "make the card shadow softer in components/StatCard.tsx"

template

Materialize a whole page from a system template into your project.

synthesisui template <slug> <name>

Codegens a deterministic page from the system's templates - the .tsx plus co-located scoped CSS (responsive + the CSS-only hamburger). Refine it in place; it stays on-system. (Formerly `page`; the old name still works.)

Options

--target <next|general>
Override the project target.
--as <name>
Name the output (templates/<name>/) - multi-page safe: two landings never collide.
--out <path>
Override the page file path (advanced; default: templates/<name>/<name>.tsx).

Examples

$ npx synthesisui template halogen dashboard-sidebar

a second landing page that won't clobber the first.

$ npx synthesisui template halogen landing --as landing-home

component

Bring one component (recipe + compiled CSS) from a system into the project.

synthesisui component <slug> <name>

Granular 'bring specific': writes a single component under _synthesisui/ds/<slug>/components/ - handy for one you refit or created on the platform. Its styles reference the DS tokens, so install the system (add <slug>) for tokens.css to resolve.

Options

--version <n>
Pin a version (default: latest).

Examples

$ npx synthesisui component halogen pricing-tier
$ npx synthesisui component halogen pricing-tier
✓ pricing-tier → _synthesisui/ds/halogen/components/pricing-tier.{json,css}

upgrade

Move an installed system to the latest version and get a migration brief for your agent.

synthesisui upgrade <slug> [options]

Re-materializes the artifacts under a new v<n>/ (the old folder stays, for rollback and diff), regenerates the components the CLI itself wrote, and writes UPGRADE.md - a deterministic list of what changed, breaking items first. Hand that file to your coding agent. A variant that never rendered anything is housekeeping, not a breaking change, and the brief says so.

Options

--force
Rewrite UPGRADE.md even with no version gap left - useful when the brief on disk is stale.
--from <n>
With --force: which older snapshot on disk to diff from.

Examples

$ npx synthesisui@latest upgrade ember
↑ Ember v18 → v22 (kept v18/ for rollback)
  rules.md → 7 rules (read these first)

── Upgraded ember: v18 → v22 ─────────────────────────────────────

  No breaking changes detected.

  The migration brief is at _synthesisui/ds/ember/UPGRADE.md

clean

Strip create-next-app boilerplate so the system has a clean surface to land on.

synthesisui clean [--force]

Dry run by default: it lists what it would remove and touches nothing. The starter's own CSS fights a design system for the same selectors, and its leftovers are the single biggest source of a page that renders unstyled after install.

Options

--force
Apply the changes. Without it, dry run.

Examples

See what it would remove, remove nothing.

$ npx synthesisui@latest clean
$ npx synthesisui@latest clean --force

request

The queue of what your agent needed and the system refused to invent.

synthesisui request [component|token] [--done <id>]

When the agent hits a gap - a component the catalogue lacks, a value with no token - the contract makes it file the gap instead of inventing, with the use case and what it considered already written. Run bare to read the queue; close a request once you have authored it or decided against it. Nothing expires on its own.

Options

--name
What the agent would call it.
--for
The use case, concretely.
--considered
Catalogue entries considered, and why each did not fit.
--value
Token requests: the concrete value.
--done <id>
Close a request, by hand, on purpose.

Examples

Read the queue. Also printed by doctor.

$ npx synthesisui@latest request
$ npx synthesisui@latest request component --name "keyboard-hint" --for "a drawn key cap in a shortcut legend"
$ npx synthesisui@latest request --done 1xhueo

sync

Send the local record - checks, fixes, open requests - to your system's dashboard.

synthesisui sync

The hook writes a ledger on your machine and never touches the network. This is the one command that ships it, by hand, to the overview page of a system you own. Re-running is free: the server dedupes events and treats the request queue as a snapshot, so the local files stay the source of truth.

Examples

After a working session, or from CI after a merge.

$ npx synthesisui@latest sync

Hosted AI · login required, spends credits

generate

login required

Generate a token-only component recipe for your system with hosted AI.

synthesisui generate "<description>"

Our AI generates a new component as a validated token-only recipe (anti-hallucination by construction) and writes it under _synthesisui/ds/<slug>/generated/. It wears the system automatically.

Options

--ds <slug>
Target system (default: the installed one).
--name <name>
Preferred component name.

Examples

$ npx synthesisui generate "an upgrade banner with a title, message and a primary CTA"
✓ upgrade-banner generated (recipe + css)
  → _synthesisui/ds/halogen/generated/upgrade-banner.{json,css}

advise

login required

Get engagement-pattern proposals tailored to your product (hosted AI).

synthesisui advise "<value proposition>"

Describes your product and gets back proposed engagement patterns to consider - it proposes, never auto-applies.

Examples

$ npx synthesisui advise "habit-building app for tracking personal finances"

refit

login required

Adapt a component you already have INTO your system, and get the code back.

synthesisui refit <file> [--ds <slug>]

Point it at a file you wrote (or one an agent wrote for you) and it comes back re-expressed in your tokens, keeping the structure and the behaviour. Uses hosted AI, so it needs login and spends credits - the deterministic commands never do.

Examples

$ npx synthesisui@latest refit components/pricing-card.tsx

Several systems installed? Name the one to fit into.

$ npx synthesisui@latest refit app/hero.tsx --ds vesper

Global options

These work on any command.

--registry <url>
Registry URL (or set SYNTHESISUI_REGISTRY_URL).
--dir <path>
Consumer project root (default: current dir).
--version <n>
Install a specific version (default: latest).
-h, --help
Show help.