---
title: "Using with AI"
description: "A copy-paste registry suits an agent well: the component source is already in the repository it is editing, and every value it may reach for is a named token."
---

## Why this works [#why]

An agent writing against a package it cannot see guesses at prop names and
invents CSS. Neither is possible here. The component is a file in the
repository, so the agent can read the props rather than recall them, and every
colour, radius, shadow and duration resolves through a `--newt-*` custom
property, so there is nothing to invent a value for.

- The source is local. `npx newtui@latest add` writes it under your ui alias,
  and the agent reads it from there.
- The vocabulary is closed. 55 components and one token layer — anything
  outside them is a mistake worth catching in review.
- The same markup exists three times over, so a prompt written for React holds
  for Vue and for the plain HTML build with only the import line changed.

## The house rules [#house-rules]

Paste this into the system message. It is the whole contract: what to use, what
never to hardcode, and what not to touch.

```text
You are building a Discord-inspired interface with newt/ui.

Rules:
- Use only the components already installed under @/components/ui.
  If one is missing, stop and say which `npx newtui add <name>` to run.
- Never hardcode a colour, radius, shadow or duration. Every value comes
  from a --newt-* custom property:
    surfaces  --newt-bg-base, --newt-bg-surface, --newt-bg-elevated,
              --newt-bg-floating, --newt-bg-input, --newt-bg-hover,
              --newt-bg-active, --newt-border
    text      --newt-text-primary, --newt-text-secondary,
              --newt-text-muted, --newt-text-link
    brand     --newt-brand, --newt-brand-hover, --newt-brand-active
    status    --newt-online, --newt-idle, --newt-dnd, --newt-offline,
              --newt-danger
    shape     --newt-radius-sm|md|lg|full
    motion    --newt-duration-fast|base, --newt-ease
- Do not add transitions, animations or keyframes. State is carried by
  colour, border and shape.
- Do not restyle a component by editing its file. Pass className, or
  override a token on a wrapper.
- Every icon-only control takes an aria-label. Presence is announced in
  text, not by colour alone.
```

## Install the skill [#skill]

If your agent supports skills, that is the shortest path of all — it carries
everything on this page plus the review checklist:

```bash
npx skills add wolfstar-project/newt-ui
```

See [Skills](/docs/skills).

## Give it the registry over MCP [#mcp]

The shortest path is not a prompt at all: run
[the MCP server](/docs/mcp) and the agent can list, search and read the registry
itself, and ask for the install command rather than inventing one.

```bash
npx newtui@latest mcp init --client claude
```

Everything below still applies — the house rules are what keep it inside the
token system once it knows what exists.

## Let the agent drive the CLI [#cli]

The registry is discoverable from the terminal, which is the one place an agent
can check itself rather than guess.

```text
Before writing any UI, list what is available and install what you need:

  npx newtui@latest list --json      # every component, machine readable
  npx newtui@latest add embed member-list status-indicator

`add` pulls a component's registry dependencies with it, so asking for
`chat` also writes `message-list`, `message-group` and `scrollbar`.
Never invent a component name: if `list` does not print it, it does not
exist, and the closest real one should be used instead.
```

> **Info**
>
> `list --json` is the cheapest grounding you can give a model: it is the
> registry, in full, in a form it can parse — and it is generated from the same
> metadata these pages read.

## Wire real data to a component [#wiring]

The components carry no data model. An integration is a map from what your bot
knows onto the props a component takes.

<div data-framework="react">

```tsx
// The data your bot already has, mapped onto the component's props.
// The component holds no colour, so the mapping is the whole integration.
const PRESENCE = {
  healthy: "online",
  degraded: "idle",
  unreachable: "dnd",
  unknown: "offline",
} as const

export function ShardRow({ shard }: { shard: Shard }) {
  return (
    <MemberListItem>
      <StatusIndicator status={PRESENCE[shard.health]} />
      <MemberListName>Shard {shard.id}</MemberListName>
      <MemberListActivity>{shard.guilds} guilds</MemberListActivity>
    </MemberListItem>
  )
}
```

</div>

<div data-framework="vue">

```vue
<script setup lang="ts">
// The data your bot already has, mapped onto the component's props.
// The component holds no colour, so the mapping is the whole integration.
const PRESENCE = {
  healthy: "online",
  degraded: "idle",
  unreachable: "dnd",
  unknown: "offline",
} as const

const props = defineProps<{ shard: Shard }>()
</script>

<template>
  <MemberListItem>
    <StatusIndicator :status="PRESENCE[props.shard.health]" />
    <MemberListName>Shard {{ props.shard.id }}</MemberListName>
    <MemberListActivity>{{ props.shard.guilds }} guilds</MemberListActivity>
  </MemberListItem>
</template>
```

</div>

Presence is the clearest case: four health values, four statuses, and the
component decides what green means. An agent asked to "show the shard as
offline" has one correct edit to make, and no colour to choose.

## Generating plain HTML [#html]

When the target has no bundler, the same rules hold against the class names
instead of the components.

```text
Generate plain HTML using only .newt-* class names from newt/ui.

Root classes available:
  .newt-btn, .newt-embed, .newt-member, .newt-message, .newt-mention,
  .newt-modal, .newt-status, .newt-timeline, .newt-card, …

Rules:
- No inline styles, except to set a --newt-* custom property.
- No new CSS class names.
- Element modifiers use the BEM form the library already uses:
  .newt-btn--primary, .newt-status__dot--online.
- Load the stylesheets rather than restating the CSS:
  <link rel="stylesheet" href="…/registry/html/tokens.css">
  <link rel="stylesheet" href="…/registry/html/components/button.css">
```

Every component page prints its root class beside the preview, and
[the installation guide](/docs/installation#html) lists the stylesheets to load.
Those two together are enough context for a model to write correct markup
without seeing the CSS.

## Review what it wrote [#review]

```text
Review this diff against the newt/ui house rules and report only breaches:

1. A hex, rgb() or oklch() literal where a --newt-* token exists.
2. A transition, animation or keyframe added to a component.
3. A component file edited to restyle it rather than wrapped.
4. An icon-only control with no accessible name.
5. A status or presence conveyed by colour with no text equivalent.
6. An import from a component that is not in the registry.

For each, quote the line and name the token or component that should
have been used. Report nothing else.
```

## What not to ask for [#limits]

Three requests that produce plausible code and a component that no longer
belongs to the system.

- **A new component in the library's style.** A model will produce one that
  looks right and shares none of the structure. Compose the existing parts, or
  open an issue.
- **A theme.** Overriding twenty tokens by hand yields a palette with no
  relationships in it. Start from the `.newt-light` block and change what you
  actually need.
- **Discord's own assets.** No logo, wordmark or icon from the client ships
  here, and none should be generated. Every glyph in the registry is drawn
  for it.
