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 doctorIt 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
Hosted AI
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 --writeWhen the scan does not reach where your tokens live.
$ npx synthesisui@latest adopt --tokens src/styles/theme.cssinspect
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 connectimport
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 importA 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 itconnect
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 mcpStarted 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 connecthook
The check, run by your editor after every write rather than remembered.
synthesisui hookStarted 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 connectmode
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 consumeAnswers where you are without changing anything.
$ npx synthesisui modeBack to nothing being blocked.
$ npx synthesisui mode offautopilot
login requiredTurn 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 autopilotTakes you out of the automation in this system. The rest of the team is untouched.
$ npx synthesisui autopilot offBack in, even if the system default is off.
$ npx synthesisui autopilot ondoctor
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 --verboseExits 1 when this repo drifts. Drop it in CI.
$ npx synthesisui@latest doctor --strictlogin
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 --forcelogout
Sign out of this machine (removes the saved token).
synthesisui logoutDeletes `~/.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 tailwindbootstrap and bring a system in, one step.
$ npx synthesisui init --styles tailwind --ds halogenlist
List the published design systems.
synthesisui listExamples
$ npx synthesisui listember 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-sidebara second landing page that won't clobber the first.
$ npx synthesisui template halogen landing --as landing-homeblueprint
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 card15 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-tiercomponent
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 --forcegaps
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 gapsMeasure, then ask what is missing - the order that gives a current number.
$ npx synthesisui@latest import --dry && npx synthesisui@latest gapsrequest
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 1xhueoalign
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 alignBefore 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 syncFrom CI, where measuring the repo again buys nothing.
$ npx synthesisui@latest sync --record-onlyabsorb
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 absorbThen `upgrade` brings the tokens down and `doctor --fix` swaps the literals.
$ npx synthesisui@latest absorb --sendsummary
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 73status
Where this project stands - installed version, last check, open requests, and anything that is behind the system governing it.
synthesisui statusThe 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 statusci
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 ciFreeze today's line and commit it, so the first PR is not red for debt nobody in it wrote.
$ npx synthesisui@latest doctor --write-baselineHosted AI · login required, spends credits
generate
login requiredGenerate 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 requiredGet 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 requiredAdapt 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.tsxSeveral systems installed? Name the one to fit into.
$ npx synthesisui@latest refit app/hero.tsx --ds vesperGlobal 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.