# CLI

> The lattice CLI scaffolds rbxts/react projects and manages @lattice-ui packages, their peers, and providers.

Source: https://docs.astra-void.xyz/lattice-ui/reference/cli/

`lattice-ui` · Stable direction · import `lattice`

The `lattice` CLI is a Node tool for Lattice UI projects. It scaffolds new `rbxts/react` games, installs primitive packages together with their required peers and providers, and audits an existing project for missing dependencies. It is published to npm as `lattice-ui` and exposes two equivalent binaries: `lattice` and `lattice-ui`.

Use the CLI when you want package selection, peer resolution, and project health checks handled for you instead of editing `package.json` by hand.

## Running the CLI

The CLI requires **Node 20+**. Run it on demand with `npx` — no install needed:

```bash
npx lattice-ui <command> [options]
```

Or install it globally to get the shorter `lattice` binary:

```bash
pnpm add lattice-ui
```

```bash
npm i -g lattice-ui
lattice <command> [options]
```

Both binaries (`lattice` and `lattice-ui`) run the same program. Run `lattice help` for the built-in usage summary or `lattice version` to print the installed version.

> **With npx, use the package name**
>
> `npx lattice` does not work — `npx` resolves the published **package** name, not the shorthand binary alias, so it fails to find anything to run. Always write `npx lattice-ui`. The short `lattice` form is for an installed CLI, global or local.

## Help

Every command has its own help page as of 0.7.0, and three spellings reach it:

```bash
lattice add --help
```

```bash
lattice help add
```

A malformed run reaches it too — `lattice add --bogus --help` prints the `add` page rather than complaining about the unknown option first. `-h` works everywhere `--help` does.

A command's page lists its usage, its own options, and its examples. For `add`, `remove`, and `upgrade` it also lists **every available component and preset** — previously the only way to see that list was to start an interactive run and read the prompt.

## Global options

| Prop | Type | Description |
| --- | --- | --- |
| `--help, -h` | `flag` | Print usage. As the first argument it short-circuits any command; after a command name it prints that command's page. |
| `--version, -v` | `flag` | Print the installed CLI version. |
| `--verbose` | `flag` | Stream debug logging, per-file copy output, and the package manager's own output live instead of buffering it. |
| `--yes, -y` | `flag` | Accept defaults and skip prompts. Accepted by every command that prompts. |

An unknown option is a usage error, but not a bare one: the CLI suggests the closest valid name and points at the relevant help page.

```
Unknown option for add: --prest
  Did you mean --preset?
  Run `lattice add --help` to see the supported options.
```

The same suggestion machinery covers command names, component names, and preset names, so `lattice add dialogg` proposes `dialog` rather than failing blankly. Component and preset names are validated *before* a package manager is resolved — previously a typo could surface an unrelated package-manager error first whenever more than one manager was installed.

## Terminal behavior

| Variable | Effect |
| --- | --- |
| `NO_COLOR` | Disables colored output when set to any non-empty value. Wins over `FORCE_COLOR`. |
| `FORCE_COLOR` | Forces color through a pipe. Any value except `0` enables it. |
| `NO_HYPERLINK` | Disables OSC 8 hyperlinks. |
| `FORCE_HYPERLINK` | Forces hyperlinks on. Any value except `0` enables it. |

Color previously keyed off TTY detection alone. It now honors the `NO_COLOR`/`FORCE_COLOR` contract first, then falls back to TTY detection, and `TERM=dumb` always disables it.

Project paths and package names are printed as **OSC 8 hyperlinks** so they are clickable in terminals that support them. Paths are shortened against the working directory and `~`. Hyperlinks are off automatically under `CI` and outside a terminal, since a few terminals print the raw escape sequence rather than ignoring it.

> **Piped output stays flat**
>
> When output is not a terminal, the CLI drops to a flat ASCII layout so logs and CI transcripts stay readable. Everything below describing the connected-run layout applies to interactive terminals.

## Output

Each run prints as one connected flow: a vertical gutter threads the header, each titled block, and the closing verdict together, with tree branches for the rows inside a block and the elapsed time on the last line. This replaced the five ceremonial sections every command used to print — counts now live in the heading of the block they describe, so `doctor` no longer states its warning count three times, and the `?` glyph is gone from informational lines where it read as a question.

Commands also report which package manager they resolved and why.

While a progress spinner is running, the package manager's own output is buffered and surfaced only if the command fails. Inherited output used to interleave with the animation, scattering spinner frames through the install log. Pass `--verbose` to stream it live instead.

> **--verbose actually works now**
>
> The flag was documented by the logger but never parsed, so `logger.debug` and the verbose file-copy logging were unreachable before 0.7.0.

## Interactive prompts

Selection prompts are keyboard-driven as of 0.7.0. They previously took a comma-separated list of numbers, and an answer that failed to parse aborted the whole command instead of re-asking.

| Key | Action |
| --- | --- |
| `↑` / `↓`, or `k` / `j` | Move the cursor |
| `Space` | Toggle the highlighted option |
| `a` | Select all |
| `n` | Select none |
| `Enter` | Confirm |
| `Ctrl-C` or `Esc` | Cancel |

The list scrolls when it is taller than the terminal, keeping the cursor in view. Cancelling restores the cursor and takes the terminal out of raw mode — Ctrl-C previously exited before the restore could run, leaving the cursor hidden.

## Commands

| Command | Purpose |
| --- | --- |
| `create` | Scaffold a new project from the rbxts template. |
| `init` | Add Lattice to an existing project. |
| `add` | Install component packages plus their peers and required providers. |
| `remove` | Remove selected component packages. |
| `upgrade` | Upgrade installed `@lattice-ui/*` packages. |
| `doctor` | Audit lockfiles, peers, and provider expectations. |
| `help` / `version` | Print usage or the CLI version. |

### create

Scaffolds a new project into an optional `[project-path]` (defaults to the current directory) from the `rbxts` template.

```bash
npx lattice-ui create my-game --pm npm --git --no-lint
```

| Prop | Type | Description |
| --- | --- | --- |
| `[project-path]` | `positional` | Target directory for the new project. At most one is accepted; defaults to the current directory. |
| `--yes, -y` | `flag` | Accept defaults and skip interactive prompts. |
| `--pm` | `<pnpm \| npm \| yarn>` | Force a package manager instead of auto-detecting one. |
| `--git` | `flag` | Initialize a git repository in the new project. |
| `--template` | `<rbxts>` | Project template to scaffold from. Currently rbxts. |
| `--lint` | `flag` | Include the lint setup. Conflicts with --no-lint. |
| `--no-lint` | `flag` | Skip the lint setup. Conflicts with --lint. |

### init

Initializes Lattice inside an existing project. Unlike `create`, it accepts no positional path and no `--git`/`--no-lint` flags, and it supports `--dry-run`.

```bash
npx lattice-ui init --dry-run
```

`init` is also the migration path off the 0.6.1 rename. Before merging the template it rewrites any pre-0.6.1 package names in `dependencies`/`devDependencies` to their `react-` replacements (`@lattice-ui/dialog` → `@lattice-ui/react-dialog`, `@lattice-ui/core` → `@lattice-ui/react-runtime`), resolving a version for each replacement it has to add. Dropping the old name matters: leaving both in the manifest makes the old and new copies resolve side by side, which npm then rejects on peer resolution.

If the install fails, `init` and `create` roll their file changes back rather than leaving a half-written scaffold for the next run to merge on top of.

| Prop | Type | Description |
| --- | --- | --- |
| `--yes, -y` | `flag` | Accept defaults and skip prompts. |
| `--dry-run` | `flag` | Show what would change without writing files. |
| `--pm` | `<pnpm \| npm \| yarn>` | Force a package manager instead of auto-detecting one. |
| `--template` | `<rbxts>` | Template to initialize from. |
| `--lint` | `flag` | Include the lint setup. |

### add

Installs one or more component packages along with everything they need. Pass component names directly (comma- or space-separated) and/or `--preset` groups. With no names or presets and without `--yes`, `add` prompts you to pick presets and components interactively. Run `lattice add --help` to see every available component and preset without starting a run.

```bash
npx lattice-ui add dialog,toast --preset overlay
```

For each selected component the CLI gathers its npm package, its **peers** (`@rbxts/react`, `@rbxts/react-roblox`), and any **required providers**, then installs the set minus whatever is already present. **Optional providers** are reported as suggestions but not installed. After a real run it points you at `doctor`.

`context-menu` and `motion` were missing from the registry before 0.7.0, so `lattice add context-menu` and `lattice add motion` failed with "Unknown component". Both resolve now.

| Prop | Type | Description |
| --- | --- | --- |
| `[name...]` | `positional` | Component names to add. Comma-separated lists are split (e.g. dialog,toast). |
| `--preset` | `<preset...>` | Add every component in a preset. Repeatable and comma-separated. |
| `--pm` | `<pnpm \| npm \| yarn>` | Force a package manager instead of auto-detecting one. |
| `--yes, -y` | `flag` | Skip the install confirmation prompt. |
| `--dry-run` | `flag` | Print the planned install command without changing anything. |

### remove

Removes the selected component packages. Accepts the same selection inputs and flags as `add`.

```bash
npx lattice-ui remove dialog --dry-run
```

| Prop | Type | Description |
| --- | --- | --- |
| `[name...]` | `positional` | Component names to remove (comma- or space-separated). |
| `--preset` | `<preset...>` | Remove every component in a preset. |
| `--pm` | `<pnpm \| npm \| yarn>` | Force a package manager. |
| `--yes, -y` | `flag` | Skip the confirmation prompt. |
| `--dry-run` | `flag` | Preview the changes without applying them. |

### upgrade

Upgrades installed `@lattice-ui/*` packages. Same selection inputs and flags as `add` and `remove`. Pre-0.6.1 package names are skipped rather than upgraded — their dist-tags no longer move, so run `init` to rewrite them to their `react-` replacements first.

```bash
npx lattice-ui upgrade --dry-run
```

| Prop | Type | Description |
| --- | --- | --- |
| `[name...]` | `positional` | Specific packages to upgrade. Omit to consider all installed @lattice-ui packages. |
| `--preset` | `<preset...>` | Upgrade every component in a preset. |
| `--pm` | `<pnpm \| npm \| yarn>` | Force a package manager. |
| `--yes, -y` | `flag` | Skip the confirmation prompt. |
| `--dry-run` | `flag` | Preview the upgrade without applying it. |

### doctor

Audits the project and reports issues without changing anything, then finishes with recommended commands. It checks for:

| Check | Level |
| --- | --- |
| Missing or duplicated lockfile | warn |
| A `packageManager` field that disagrees with the resolved manager | warn |
| No `@lattice-ui` component packages installed at all | warn |
| A pre-0.6.1 package name that no longer receives releases | **error** |
| A `typescript` major other than the one roblox-ts compiles with | warn |
| An `@lattice-ui` package that is installed but not in the CLI registry | warn |
| A missing peer, or a missing optional provider | warn |
| A missing **required** provider | **error** |

Errors exit non-zero; warnings do not.

```bash
npx lattice-ui doctor
```

| Prop | Type | Description |
| --- | --- | --- |
| `--pm` | `<pnpm \| npm \| yarn>` | Force the package manager used for the audit instead of auto-detecting. |

## Presets

Presets are named bundles of components so you can install a related set in one go with `--preset`.

| Preset | Components |
| --- | --- |
| `overlay` | `popover`, `tooltip`, `dialog`, `toast` |
| `form` | `checkbox`, `radio-group`, `switch`, `text-field`, `textarea` |

## Package manager resolution

When `--pm` is omitted, the CLI resolves a package manager automatically from the project lockfile or installed managers; pass `--pm <pnpm|npm|yarn>` to override that choice. `doctor` surfaces resolution problems: a missing lockfile, multiple lockfiles, or a `packageManager` field that does not match the resolved manager.

The resolved manager is also **pinned** into the project. `create` and `init` record it as a `devEngines.packageManager` entry, and `add`, `remove`, and `upgrade` reapply the pin before they touch dependencies — if the pin names a different manager than the one this run uses, the CLI warns and repins. The pin is what keeps a project scaffolded with pnpm from being quietly installed with npm: both managers refuse to install when the pin names the other one.

> **Peers and providers**
>
> Every component declares the peers it needs (`@rbxts/react`, `@rbxts/react-roblox`) and, for layered primitives, optional providers such as `@lattice-ui/react-layer`'s `PortalProvider`. `add` installs peers and required providers automatically but only *suggests* optional providers — wire those up yourself when you want the behavior they enable (for example, portal-mounted dialog or menu content).

## Dry runs

`init`, `add`, `remove`, and `upgrade` all accept `--dry-run`. A dry run prints the exact package-manager command it would run and reports what it *would* do, which is the safest way to preview a change before committing to it.

Before 0.7.0 a dry run closed by claiming work it had not done — `lattice add --dry-run` reported "Added components: …" and "Installed packages: 4" despite changing nothing, and `remove` and `upgrade` did the same.

## Related

- [Installation](https://docs.astra-void.xyz/lattice-ui/getting-started/installation.md)
- [Migration](https://docs.astra-void.xyz/lattice-ui/reference/migration.md)
- [Package stability](https://docs.astra-void.xyz/lattice-ui/getting-started/package-stability.md)
- [Portals and layers](https://docs.astra-void.xyz/lattice-ui/guides/portals-and-layers.md)
