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

inspect

Read this repository and say what it sees - your components, their variant axes and options, their parts and shape, and where one is built from another. No account, no network, nothing written.

synthesisui inspect [--dir <path>] [--scope <path>]

The first contact, and the only command that promises all four at once: it asks for no account, makes no network call, writes no file, and still gives the deep reading. It answers a different question from `doctor`: `inspect` says WHAT DO YOU SEE, `doctor` says WHERE IS THIS DRIFTING. Knowledge comes first in the output and repeated values come second, because the components with their variant axes are the hard part and a terminal is read top down. What this version could not interpret is named with the file and the line, never summarised away. It ends by pointing at `connect` - the step that lets your agent ask any of this - and it does not run it for you. Because it never reaches the network, matching uses the names built into this CLI rather than the live catalogue; `import` matches against the full list.

Options

--dir <path>
Read a different directory than the current one.
--scope <path>
Read only this folder - repeatable, for a monorepo where the system lives in one package.

Examples

Nothing is asked for and nothing is written. Measured on a five-file Next project that had never seen SynthesisUI: 163ms.

$ npx synthesisui@latest inspect
── What this project composes ────────────────────────────────────

  Button             2x in 1 files  variant(primary|ghost) size(lg)
  Button             1x in 1 files  variant(secondary) size(sm)

  5 of 5 components came out with a blueprint - 100%, 26 declarations
  2 parts named across 5 components - read off their own markup
  5 of them arrived with a SHAPE - the parts nested as they nest in your code
  3 places where one of your components is built out of another

── What your project says ────────────────────────────────────────

  next . react . tailwind
  5 files . 13 distinct design values

  6px radius, 5x in 3 files
  12px spacing, 4x in 2 files
  #2563eb color, 3x in 2 files

  17 stylesheet declarations - no reader in this version understands
  this shape
      app/globals.css:4  .promo-banner { background: #2563eb }

── Your agent cannot ask any of this yet ─────────────────────────

  Nothing was written, and nothing was sent.

  To let it ask before it invents:
      npx synthesisui@latest connect

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] [--shell]

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, and the project's MCP server asks for approval once. THE HOOK'S COST, AND HOW TO CUT IT. The hook runs through npx, which resolves this package against the registry on every edit - that wait is the network, not the check itself, whose analysis is about 80ms. Adding synthesisui to your devDependencies makes npx resolve it locally: measured on a real repository, 2525ms became 295ms. Run connect again afterwards and it switches by itself. THE COMMAND THAT OPENS YOUR AGENT IS DERIVED, never a fixed pair of names: it comes from which governance file this repository carries - `CLAUDE.md` for Claude Code, `AGENTS.md` for Codex - so a repo that uses one is never told to open the other, and a repo that carries neither is not told to open anything. Cursor has no line there on purpose: it is an editor you open, not a terminal command. The flags shown are the ones that let the agent write without approving each change, and what they skip is said in a line next to them. YOUR PRs CAN CARRY THIS TOO. `synthesisui ci` writes a check that annotates the exact line and fails only when the count goes UP - never on the debt you already have. It is not offered at the end of connect on purpose: a repository that has no design system yet has no debt to gate, and the one thing that screen should say is how to start.

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.
--shell
Add the terminal check to your shell profile without being asked. Without it, connect offers once and takes no for an answer.

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.358 hook
  ✓ .claude/settings.json  every session now opens with what this environment is missing
  ✓ .mcp.json              19 tools, so the agent can ask instead of guess
  ✓ CLAUDE.md              how to turn this repo into your system
  ✓ /sui-init              the first run, start to finish

── Do this next ──────────────────────────────────────────────

  1  Open a new agent session in this repo

      claude --dangerously-skip-permissions

  2  and say

      import my design system

  I read what is already in your code - the colours, the type, the shapes,
  the components. Nothing is invented.
  That flag lets it write without asking each time. Drop it to approve
  every change yourself.
  A new session is what loads the skills and tools just installed, and the
  project's tools ask for approval once - say yes.

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. Eleven tools, and the four that carry the day: `check_file` measures one file and names the token this project already has for every literal; `validate_recipes` answers whether a batch of recipes would arrive whole before any of them is sent; `request_component` and `request_token` file what the catalogue could not cover, so a workaround becomes a queue item instead of evaporating in chat. And `refresh_system`, which is why a reader we ship on Tuesday reaches this repo without anybody remembering a command: the agent compares the CLI that measured `census.json` with the one it is talking to, and calls it when they differ. It never asks a person anything and never overwrites a recipe somebody wrote on the screen.

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

mode

Tell the check what kind of work you are doing - building with what the system has, or growing it.

synthesisui mode [consume|create|off]

The check knows the same thing either way: that an option you wrote is not one your system declares. What changes is what it DOES with that. In `consume` you are assembling a screen out of what already exists, so inventing an option is the mistake rather than the creativity - the check refuses, and the refusal carries what your system offers in its place. In `create` you are growing the system, so a new option is the work, and it reports and gets out of the way. With no mode at all nothing is ever blocked, which is how this worked before you had the choice: nothing blocks unless you asked for it. The mode is local to your clone and never committed - your choice never blocks anybody else on your team. Run it with no argument and it answers where you are.

Examples

Building a screen out of the system. The check now refuses an option the system does not declare.

$ npx synthesisui mode consume

Answers where you are without changing anything.

$ npx synthesisui mode

Back to nothing being blocked.

$ npx synthesisui mode off

autopilot

login required

Turn the Autopilot on or off FOR YOU in this system, and see which line your work is landing in - without leaving the terminal.

synthesisui autopilot [on|off]

The Autopilot applies what the platform finds on your work without asking. Until now the switch lived on the settings screen, which meant leaving what you were doing to change it. This is the same switch, from where you already are: it changes YOUR setting in this system and nobody else's, and it prints the state it read BACK - never the one it tried to write, because a switch that looks on and is not is worse than one that refuses. Run it with no argument and it answers without changing anything. Either way it says where your work is landing: straight on the main line your team installs, or in your own branch, waiting for whoever owns the system to approve it. If your role does not let you change it, the refusal names the role that can. Your sync keeps going up either way - what stops is the Autopilot acting on it.

Examples

Answers where you are - the state, why it is that way, and which line your work lands in.

$ npx synthesisui autopilot

Takes you out of the automation in this system. The rest of the team is untouched.

$ npx synthesisui autopilot off

Back in, even if the system default is off.

$ npx synthesisui autopilot on

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.
--fix [--dry]
Replace every hand-written value your system already names with the token, in place. Only those: a value the system has no name for is a design decision, not a fix. `--dry` says what it would do.
--format=github|sarif
Speak CI: annotations on the exact line of a PR, or SARIF for code-scanning and SonarQube. Suppresses the human report - a log with both is a log nobody reads.
--baseline [path]
The ratchet. Exit 1 only when drift went UP against the committed baseline, in total or in any single file. Without it, nothing ever fails on debt you inherited.
--write-baseline
Freeze today's numbers into _synthesisui/drift-baseline.json and commit it. Yesterday's debt stops hurting without going uncounted.
--strict
Exit 1 on ANY finding in this repo. Honest, and red on day one in a repo with history - prefer --baseline.
--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 [--force]

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. When this machine already has a session for the same host it says so and stops, instead of asking you to approve something you just approved - `--force` is how you sign in as somebody else without signing out first.

Options

--force
Start a new device flow even when this machine is already signed in - use it to switch accounts.

Examples

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

Signs in as a different account from the one this machine already has.

$ npx synthesisui@latest login --force

logout

Sign out of this machine (removes the saved token).

synthesisui logout

Deletes `~/.synthesisui/credentials.json`, the per-machine token the device flow wrote. It names the host it signed out of, because a token issued by a local registry is not the one production accepts - and running it twice says you were already out rather than pretending it did something.

Examples

$ npx synthesisui@latest logout
✓ Signed out of https://www.synthesisui.com on this machine.
  Removed ~/.synthesisui/credentials.json

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>
Forces every component into one language. By default each one comes back in the language it is already written in - pass this only if you are migrating TO css or TO tailwind.
--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]

Writes the system into _synthesisui/ds/<slug>/ as OUR reference - the compiled sheets, the recipe catalog, the doctrine and a GUIDE.md the agent reads. Your app imports none of it: the check, the doctor and the MCP server read it to interpret your design. 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 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

blueprint

Bring one blueprint of a system into the project, as your own component.

synthesisui bp <name>

The slug is optional: inside a project that has one system installed, the repository answers for it. Two arguments mean slug first, which is how a blueprint from ANOTHER system arrives. `bp` and `component` are the same command - `blueprint` is the name the platform uses in public. The CSS it writes speaks YOUR vocabulary: where your code names the value, the file uses your variable, and where it does not, it carries the value - so nothing in it points at our stylesheet.

Options

--version <n>
Pin a version (default: latest).
--interactive
The behaving .tsx for a component that needs state.

Examples

$ npx synthesisui bp card
$ npx synthesisui bp card
15 references now speak the name YOUR code gives the value
Nothing in this file points at our stylesheet

from another system, by slug.

$ npx synthesisui bp halogen pricing-tier

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. Use `component` to bring it into your own code, where it arrives speaking the names your project declares.

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

Bring everything installed here up to date - the system's version, the css, the rules, and the files this CLI writes.

synthesisui upgrade [slug] [options]

The command for staying current, and it acts on FOUR kinds of drift, not just a new version: a newer published version, css compiled differently for the version you already have, rules that changed on the platform, and files written by an older CLI. The last three do not move the version number, and until 07/08 nothing but `connect` reached them - which left the word that means update as the only one that did not update. The slug is optional when a single system is installed. On a new version it 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

gaps

What the pipeline did NOT read of your project, triaged into what is work and what is not.

synthesisui gaps [--census <path>]

`import` accounts for every fragment of your code that carries appearance - a class list, a template string, an inline style, a stylesheet declaration, an `sx` prop - and lists the ones it did not interpret with the file and line where each lives. This reads that accounting back out of `_synthesisui/census.json` and sorts it by what to do about it: a shape no reader understands yet (work on our side, and the module is named), a value outside the scales your project declares (a table, not a reader), and the largest group of all - things no reader would change, because the gate refused that component or the class is assembled while the page renders. In a real dashboard 78% of what looks unread falls in that last group, so a bare percentage points at the wrong work. It measures nothing: run `import` first, and this reads what that wrote.

Options

--census <path>
A census somewhere else (default: `_synthesisui/census.json`).

Examples

The triage of the census already on disk. Nothing leaves the machine.

$ npx synthesisui@latest gaps

Measure, then ask what is missing - the order that gives a current number.

$ npx synthesisui@latest import --dry && npx synthesisui@latest gaps

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

align

What is out of alignment in this environment - printed when a session opens, silent when there is nothing to say.

synthesisui align [--shell]

Installed by connect two ways: as a SessionStart hook, so it runs once when your editor opens and never during your work, and - if you accept when connect offers - as a shell hook, so entering this repo in a plain terminal answers the same question. The terminal one runs in the background and at most once an hour, because the check costs about four seconds through npx and no prompt should wait for it. It checks the things nothing else was checking: whether this machine has a session at all (a token belongs to the machine, not the repo, so a fresh clone always lands there), whether your token and this system came from the same host, whether the system records the folder it was measured from, whether checks are recorded here and never sent, and whether more than one design system is installed in the same repo. It prints nothing and exits 0 when everything lines up - a check that speaks every time is a check people stop reading - and it never fails, because an environment it cannot verify must not stop anybody from working.

Options

--shell
Say it as a terminal would rather than as a session opening. The shell hook passes this; you never need to.

Examples

Your editor runs this for you once a session. Running it by hand answers the same question at any moment.

$ npx synthesisui@latest align
Before this session starts, this environment is out of alignment with the design system that governs it:
  - No session on this machine. A token belongs to the machine, not to the repo, so a fresh clone always lands here.
      npx synthesisui login
  - "signalui" does not record where it was measured, so a re-measure would read this whole repo instead of the folder the system came from.
      npx synthesisui import --dry --scope <folder>

sync

Re-measure this repo with the current reader and send it, plus the local record.

synthesisui sync [--record-only] [--yes]

The one command on your side. It asks the platform for the decisions you already made - the scope, and the reading you authored - measures your repo again with today's reader, and sends the result to your system's DRAFT. The reading is reused rather than rewritten, so a 260-component system does not go through an interview again, and nothing published moves. Before overwriting anything, it names the recipes that were written on the screen and asks. It also ships the local ledger the hook writes: checks, fixes, open requests. Re-running is free.

Options

--record-only
Skip the measurement and send only the local record - the old behaviour.
--yes
Do not ask before overwriting a recipe that was written on the screen.

Examples

After we ship a new reader, or after a working session.

$ npx synthesisui@latest sync

From CI, where measuring the repo again buys nothing.

$ npx synthesisui@latest sync --record-only

absorb

The other direction: your system learns the design your code already writes by hand.

synthesisui absorb [--send]

Everything else here asks whether the code obeys the system. A project mid-migration asks the opposite, and that is most of its work: on a real monorepo, 4223 hand-written values had no name in the system - #fff in 274 files, #1394dc in 197 - and nothing could turn them into tokens. This writes a proposal to _synthesisui/absorb.json: each value with the path derived from the name YOU already use, empty when nobody names it, and marked when it sits within a hair of a token you already have (13 of the top 40 did, on that repo - those are the same decision written twice, not new names). You fill the blanks in one file, delete what you do not want, and send the batch. Naming is the one thing this refuses to do for you.

Options

--send
Send the batch you reviewed. Without it, nothing leaves the machine.

Examples

$ npx synthesisui@latest absorb

Then `upgrade` brings the tokens down and `doctor --fix` swaps the literals.

$ npx synthesisui@latest absorb --send

summary

The four lines about a system you just imported: what it holds, the two versions, and the one thing to do next.

synthesisui summary <slug> [--base N] [--draft N] [--fixes N]

The handoff screen of a first run, printed by a program instead of composed by an agent. It reads the counts from the census on disk and the installed version from the .lock, and takes the version numbers from the import response - the platform is what numbers a version, so nothing here invents one. It exists because that screen kept ending long: four hundred words, three of the four paragraphs about the agent's own work rather than the system, and warnings that were already out of date. A rule sixty lines earlier does not beat the pull to report your own work at the end of a long job; a command has nothing to compose.

Options

--base <n>
The frozen version - your code exactly as it is today.
--draft <n>
The open draft, where authorised optimisations landed.
--fixes <n>
How many deterministic fixes that draft carries.

Examples

$ npx synthesisui@latest summary signalui --base 1 --draft 2 --fixes 73

status

Where this project stands - installed version, last check, open requests, and anything that is behind the system governing it.

synthesisui status

The day-to-day answer, in the terminal. Local first: the installed version comes from the .lock, the last check and the coverage from the ledger the hook writes, the ratchet from the committed baseline, and the queue from the requests file - none of that needs a login or a network. When you are logged in it adds the one question the disk cannot answer: whether the platform holds a newer measurement than yours. It writes nothing at all.

Examples

$ npx synthesisui@latest status

ci

Put drift in your pull requests - annotations on the line, and a ratchet instead of a gate.

synthesisui ci [--write]

Two steps and no Action to install: GitHub reads annotations from any step's stdout, so `doctor --format=github` puts every finding on the exact line of the diff. The second step is the ratchet: `doctor --baseline` exits non-zero ONLY when drift went up - in total or in any single file - so the debt you already have never turns the check red, and a regression cannot land quietly. `--write` writes the workflow file, and never overwrites one that already exists.

Options

--write
Write .github/workflows/design-system.yml instead of printing it.

Examples

$ npx synthesisui@latest ci

Freeze today's line and commit it, so the first PR is not red for debt nobody in it wrote.

$ npx synthesisui@latest doctor --write-baseline

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.