# synthesisui

The CLI for [SynthesisUI](https://www.synthesisui.com) - where your design
system is born, scored against the classic design canon, and delivered to any
coding agent.

Your AI writes UI. This gives it a design system to write it in: tokens, typed
components, whole pages and a `CLAUDE.md` manifest that Claude Code, Cursor,
Copilot or any coding agent reads before writing a single line.

> This repository is a **read-only mirror** of `packages/cli` in the SynthesisUI
> monorepo, published so you can audit exactly what runs in your repo.
> Issues and bug reports are very welcome here; pull requests can't land on a
> mirror - open an issue instead.

## Quickstart

```bash
npx synthesisui@latest init --styles tailwind --ds <slug>
```

Pick any system from the [gallery](https://www.synthesisui.com) - or create
your own in two minutes.

## Commands

| Command | What it does |
| --- | --- |
| `init` | One-shot setup: materialize a system + wire your project for it |
| `login` | Connect to your account (device-flow in the browser) |
| `list` | List the design systems available to you |
| `add <slug>` | Materialize a system into `_synthesisui/ds/<slug>/` |
| `use <slug>` | Generate the agent prompt to apply the system to your app |
| `component <slug> <name>` | Bring one typed component into your components dir |
| `template <slug> <name>` | Generate a whole page (landing, dashboard, onboarding…) |
| `generate` | Generate a page from a saved guide structure |
| `advise` | Grounded design advice for this repo, from your system's rules |
| `refit <file>` | Send an app component back into your design system |
| `upgrade <slug>` | Diff your `.lock` against the latest version and migrate |
| `clean` | Remove materialized files and the managed CLAUDE.md block |
| `doctor` | Audit the repo for drift: every design value written by hand, and the token your system already has for it |

## `doctor`

Every tool in this space promises output that is brand consistent and free of
drift. None of them checks. This checks, in the only place it can be true -
the code that shipped.

```
npx synthesisui@latest doctor
```

```
── Doctor ────────────────────────────────────────────────────────

  Aluna v1 - 91 tokens, 53 files read

  Token coverage  ████████████████████████   98%
                  2019 from the system, 34 by hand

── Drift ─────────────────────────────────────────────────────────

  26  colour
   8  spacing

  app/welcome2/_components/signature.tsx
        19  #8b8bf1  → --ds-color-blue-500
        21  #f1f3fa  → --ds-color-gray-100
```

### Overruled

With a system installed it runs a second pass that nothing else can:

```
── Overruled ─────────────────────────────────────────────────────

  3 places where the code takes a component
  the system defines, and then overrules it locally.

  components/Hero.tsx
        12  ds-button · border-radius: 4
            the recipe binds {radius.md}
        18  ds-button · padding: px-8
            the recipe binds {spacing.2xs} {spacing.md}
```

It only flags a property the recipe **actually binds**. `w-full` beside a
button is layout; `px-8` is drift, because the recipe already decided the
padding. A rule reading `var(--ds-…)` back is the opposite of overruling and
is left alone. This needs the recipes, which are only in the project because
`add` put them there - a linter has no idea what `ds-button` promised.

The last column is the point: not "you hardcoded a colour", but **the name
your own system already has for it**. Exact matches only - a tool that guesses
a near colour invites a silent visual change, and a diagnosis nobody trusts is
worse than none.

With no system installed it still finds every hand-written value and counts
the distinct ones. Runs offline, needs no account, writes nothing.

### What your system says

```
── What your system says about what you use ──────────────────────

  ds-badge  ·  3 places
      Badges whisper status in periwinkle; danger appears only for money at risk.

  ds-button  ·  3 places
      One indigo action per view; gold is reserved for moments of ceremony, never buttons.
      Buttons speak quietly - sentence case, no exclamation.
```

The usage laws your team wrote, for the components this project actually uses,
ordered by how much you use them. They are prose, so nothing verifies them -
the value is putting them in front of whoever is touching the component. No
other tool is positioned to do it, because no other tool knows these laws
exist.

`--strict` exits 1 when drift is found, for CI. `--all` lists every finding
instead of the loudest files. `--laws` shows every law instead of the busiest
components.

## What `add` materializes

Inside `_synthesisui/ds/<slug>/`:

- `design-system.json` - the canonical source of truth
- `tokens.css` - CSS custom properties scoped by `data-ds`
- `theme.css` - optional Tailwind v4 `@theme` adapter (`bg-primary`, `p-md`, …)
- `GUIDE.md` - agent instructions: semantic roles, mood, recipes
- `rules.md` - the governance your agent must follow
- `.lock` - pinned slug + version (reproducible upgrades)

Plus an idempotent `<!-- synthesisui:start/end -->` block in your root
`CLAUDE.md` listing every installed system and its component manifest.

## Authentication

`synthesisui login` uses device-flow (RFC 8628): it opens the browser, you
confirm a code, and the token lands in `~/.synthesisui/credentials.json`
(per machine, chmod 600). Logout = delete that file.

## Registry

Defaults to `https://www.synthesisui.com`. Override with:

```bash
synthesisui list --registry http://localhost:3000
# or
SYNTHESISUI_REGISTRY_URL=http://localhost:3000 synthesisui list
```

## License

MIT
