# @godxjp/ui — for AI agents

You are about to write code against a design system you did not author. This file is the whole
contract. Read it before you write JSX.

**This catalog describes `@godxjp/ui` 33.12.4.** If the project you are editing has a different
version in its `package.json`, read the pinned catalog for THAT version instead
(`…/v<their-version>/agent/…`). A catalog newer than the installed package describes props that do
not exist yet; older, and it hides props that do. Neither failure announces itself.

Pinned catalogs only exist for releases whose tag actually contains `agent/`. If `…/v<version>/agent/index.json` returns 404, that release predates this catalog: read `…/main/…` instead and compare `index.json` → `version` against the package you have, so you at least know which way it drifted.

---

## Which lane are you in

## Where to read these files

Three places carry this catalog, and they are not equivalent:

| source | URL / path | use it when |
| --- | --- | --- |
| docs site | `https://godx-jp.github.io/godxjp-ui/agent/…` | you are an assistant in a browser and can only fetch a URL |
| npm package | `node_modules/@godxjp/ui/agent/…` | the project is on disk — this copy is **version-locked to the installed package by construction** |
| raw GitHub | `https://raw.githubusercontent.com/godx-jp/godxjp-ui/v<version>/agent/…` | you need a version the other two cannot give you |

Prefer the package copy when a project is in front of you: it cannot drift from what is installed,
which is exactly the failure the version note above describes. The docs-site copy always describes
the LATEST release, so pair it with the raw `v<version>` URL if the project is pinned to an older
one.

**You can run a process** (Claude Code · Codex CLI · Cursor · any client with MCP)
→ Do not use these files. Run the MCP server; it is searchable, version-locked to the package on
disk, and costs far fewer tokens than fetching a 1 MB JSON.

```jsonc
// .mcp.json — or let `npx @godxjp/ui sync-rules` write it for you
{ "mcpServers": { "godx-ui": { "command": "npx", "args": ["@godxjp/ui-mcp@<installed version>"] } } }
```

Then, before any JSX: `get_design` (the visual target), `route_consumer_task`, `get_exemplar` for
the closest screen, `search_components` → `get_component`. After building, run
`npx @godxjp/ui visual-audit` at 320 / 390 / 768 / 1024 / 1280 / 844×390 to zero failures,
inspect every screenshot at every width region by region (no top-N cap), and hand over as
"probes passed; independent acceptance pending" — the builder does not accept its own screen.

**You cannot run a process** (ChatGPT web · Claude.ai · anything fetching URLs)
→ These files are for you. Read `DESIGN.md` (in this folder) first: tokens, scarcity rules and
screen anatomy, the visual target the rules below do not give you. Then fetch in this order:

0. `patterns-index.json` — 28 whole-task patterns as name + tagline + tags. **If your
   task is a task** — "build a settings page", "confirm a destructive delete", "a list page with
   filters" — start HERE, not at the components. Then fetch `patterns/<name>.json` for complete,
   copy-paste-ready code. A component index answers "does X exist"; it cannot answer "build Y".
1. `components-index.json` — 53 KB, all 169 components as name + group +
   tagline. Read this when you already know the SHAPE you need. Each entry may carry `absorbed`:
   names that **do not exist** and map to it — `Combobox`, `Autocomplete`, `CountrySelect` and
   `SearchSelect` are all `Select`. If you are about to hand-roll something, search this field
   first; it exists because that is the mistake.
2. `components/<Name>.json` — one file per component (1 KB–37 KB, median 6 KB), carrying its props,
   its `importPath`, and its examples. Fetch only the handful you picked in step 1.
3. `rules.json` — 44 cardinal rules. The ones about raw HTML and hardcoded colour are not
   style advice.
4. `tokens.json` — 2241 design tokens, each tagged with its `tier`. **If you were handed a
   brand, read the 218 `foundation` entries first** — `--primary`, `--background`,
   `--radius`, `--font-size-base` are the handful everything else derives from. The
   1910 `component` entries are per-part knobs; reach for one only when a role is
   right everywhere except one component.
5. `anti-ai-tells.json` — 35 shapes that make generated UI look generated, each with the
   fix. Read before you reach for a gradient hero or a wall of coloured chips.

**Do not fetch `components.json`.** It is 1.3 MB, and most URL fetchers truncate a
response that size and return the head without telling you. You get the first few entries, believe
you read the catalog, and answer the rest from memory — which is the failure this file exists to
prevent. The per-component files say the same thing without the cliff.

---

## The four rules that decide whether your output is usable

Everything else is detail. These four are why generated code gets rejected here.

### 1. Never a raw HTML control

No `<button>`, `<input>`, `<select>`, `<textarea>`, hand-rolled `<table>`. Use `Button`, `Input`,
`Select`, `Textarea`, `DataTable`. A raw control has no focus ring, no size ladder, no RTL, and no
dark mode — it *looks* fine in a screenshot and fails every gate this package ships.

### 2. Never a colour, size or spacing literal

Not `#6400D4`, not `color: rgb(...)`, not `p-[13px]`, not `height: 36px`. Reference the **role**:

```tsx
<Alert tone="warning">      {/* not: style={{ borderColor: "#B45309" }} */}
<Button size="sm">          {/* not: className="h-8" */}
<CardContent>               {/* not: <Card className="p-4"> */}
```

In CSS, reference the token by NAME so it re-resolves per theme and per tenant:

```css
color: var(--code-block-token-keyword-color, hsl(var(--primary)));   /* yes */
color: #6400D4;                                                       /* no  */
```

### 3. Compose primitives fully

Padding comes from `CardContent`, not from `p-4` on a bare `Card`. An empty table state comes from
`DataTable`'s own empty, not from a `<div>` you wrote. If you find yourself styling a `<div>` to
look like a component, the component exists — search the index.

### 4. It is one control, not a family

There is no `Combobox`, `Autocomplete`, `CountrySelect`, `SearchSelect`. There is `Select`, with
`showSearch` and `loadOptions`. The i18n pickers are one `AppSettingPicker kind=…`. Components were
deleted for being duplicates; do not add another by hand-rolling.

This is not advice you have to remember — it is **data**. Every one of those names is in the
`absorbed` field of the component that replaced it, in `components-index.json`, and
`check:absorbed-names` fails the build if any of them ever becomes real. Search the name you were
about to invent.

---

## Tokens: how to stay flexible

The common failure is treating tokens as a **closed menu of approved layouts**. They are not.
Tokens carry VALUES; composition, responsive behaviour and interaction are still yours.

What keeps a token-first page flexible is the **scoped override contract** — the same knob, settable
at three levels, each beating the one above:

| level | how | reaches |
|---|---|---|
| theme | `:root { --card-radius: 0; }` | every Card in the product |
| region / tenant | `[data-tenant="acme"] { --card-radius: 0; }` | one tenant, one section |
| instance | `<Card className="…">` or the documented prop | this one Card |

So: **build any layout you like out of primitives, and express every visual decision as a token or
a documented prop.** You keep full freedom of composition and lose none of the theming. The moment
you write a literal, that pixel stops following the theme and the tenant override silently skips it.

### Which token do you actually set — the `tier` field answers it

Every entry in `tokens.json` carries a `tier`, and the tier tells you whether you are invited to set
it. Start at the top and **stop at the first tier that does the job**; each step down is a value that
has stopped following the brand.

| `tier` | count | what it is | set it? |
|---|---|---|---|
| `foundation` | 218 | the seeds — `--primary`, `--background`, `--foreground`, `--radius`, `--font-size-base`, `--shadow-color`. Everything below is derived from these | **yes — this is the main road.** The default `--primary` is a neutral placeholder: set it (`:root { --primary: <H> <S>% <L>%; }`, HSL components, no `hsl()` wrapper) or import a theme preset such as `@godxjp/ui/themes/godx.css` |
| `semantic` | 113 | named roles that follow the seeds — `--ring`, `--text-link`, `--primary-hover`, `--overlay-background` | only when the seed is right and ONE role must differ. That role then stops following a later brand change |
| `component` | 1910 | per-part knobs, `--{component}-{part}-{property}` | rarely. Most are declared `initial` with the real default at the call site — deliberate, so a scoped override re-resolves instead of freezing at `:root` |

A token whose `value` is `initial` is not empty and not broken: `initial` is the guaranteed-invalid
value, so the real default is computed where the element paints it. Set it and yours wins.

**There is no fourth option.** If a colour, radius or size you need is not in this file, the answer
is not a hand-written CSS rule — say the token is missing and ask. A literal is invisible to every
theme, every tenant scope and every audit in this package.

---

## A page that would pass review

```tsx
import { PageContainer, Flex } from "@godxjp/ui/layout";
import { Card, CardContent, DataTable } from "@godxjp/ui/data-display";
import { Button } from "@godxjp/ui/general";
import { FilterBar } from "@godxjp/ui/navigation";

export default function InvoicesPage() {
  return (
    <PageContainer title="請求一覧" extra={<Button>請求を作成</Button>}>
      <Flex direction="col" gap="sm">
        {/* filters sit ABOVE the table they filter, in ONE FilterBar that wraps — never a
            sideways-scrolling strip (rule #51); many filters → patterns/list-filters.json */}
        <FilterBar
          search={{ ariaLabel: "請求を検索", placeholder: "請求を検索" }}
          filters={[{ value: "status", label: "状態", options: statuses, defaultSelected: "unpaid" }]}
          actions={<Button variant="outline">CSV</Button>}
        />

        {/* `flush` because DataTable draws its own edges — a padded body double-insets it */}
        <Card>
          <CardContent flush>
            <DataTable data={rows} columns={columns} getRowId={(r) => r.id} />
          </CardContent>
        </Card>
      </Flex>
    </PageContainer>
  );
}
```

Note what is absent: no colour, no pixel, no raw control, no `<div className="flex gap-4">` where
`Flex` exists — and no subtitle restating the title, no KPI row above the list, no banner, no Card
header repeating the page title. The page answers one question: which invoice next.

**Take the import path from the catalog, not from the group.** Every entry in
`components/<Name>.json` carries an `importPath`; it is the only one guaranteed to resolve. The
group is a docs heading and does not always match a subpath — `AppProvider` is in group
`providers`, and `@godxjp/ui/providers` does not exist (it is `@godxjp/ui/app`).

---

## Before you answer

Say which catalog version you read and which files you actually fetched. If you could not fetch
one, say so rather than filling the gap from memory — a prop invented from another library is the
single most common failure here, and it looks exactly like a correct answer.
