Resources / LLM context
LLM context
One persistent pointer that lets a coding assistant read Alpha's own documentation at the version your application installed. Add it to a repository once, then describe the work normally rather than preparing a mapping by hand.
- Install AlphaFollow Getting started. The package includes documentation for exactly the version the application installed.
- Add the instructions oncePaste this block into the repository's
AGENTS.md,CLAUDE.md, Cursor rule or Copilot instructions. Keep it with the codebase; it is not a prompt to repeat in every conversation.## Alpha design system (`@growth-protocol-ai/alpha`) This project uses Alpha. - **The installed package documents itself.** Read `node_modules/@growth-protocol-ai/alpha/dist/llms.txt` — it indexes one document per published surface and the cross-cutting foundation documents, generated and checked with the package, so it describes the version this project has installed. Read `node_modules/@growth-protocol-ai/alpha/dist/llms/building.md` before creating new UI, `node_modules/@growth-protocol-ai/alpha/dist/llms/adopting.md` before replacing existing UI and `node_modules/@growth-protocol-ai/alpha/dist/llms/setup.md` before changing application-level setup. - **For new UI, start with the required capability and semantics.** Read the building guide and the candidate surface documents before choosing a component. If Alpha has no match, use semantic HTML or an application-owned component rather than inventing an Alpha API or approximating the design with an unrelated surface. - **Discover before replacing.** Resolve imports, re-exports, aliases and local wrappers, then read the implementation and its call sites. Match an Alpha surface by capability and behaviour, never by a shared name or by which library the source came from. - **Prefer the narrowest safe seam.** If a local wrapper can keep its public contract while using Alpha inside, migrate the wrapper once. If its callers depend on behaviour Alpha cannot preserve there, migrate those callers individually and leave the wrapper in place for the rest. - **Preserve semantics and state.** Check the rendered element, accessible name, focus and keyboard behaviour, event arguments, controlled and uncontrolled state, defaults, disabled and pending behaviour, content placement, layout and visual intent. A compiling rename is not proof of equivalence. - **Track a migration that spans files.** Create or update the ledger described in the adoption document; do not rely on conversation memory for remaining call sites, blockers or validation. - **Import components from the package root**: `import { Button } from '@growth-protocol-ai/alpha'`. - **Import icons from the `/icons` subpath**, by name, one static import per glyph: `import { SearchIcon } from '@growth-protocol-ai/alpha/icons'`. There are no icons on the package root and there is no name-based `<DynamicIcon />` — the static import per glyph is what lets a bundler drop the rest. - **An icon slot takes the element, not the component**: `<Button iconLeft={<SearchIcon />}>`. Leave `size` off and the surrounding component sizes and colours it. - **Icon sizes are `sm | md | lg`, never numbers.** `sm` and `lg` overrule the surrounding component; `md` and omitting it both defer to it. - **Icons are `aria-hidden` by default.** Label the control, not the glyph — an icon-only button takes the `aria-label`. - **The stylesheet is imported once**, in the root layout. Never import it again. - **Set `data-mode` on `<html>`** — `dark` or `light`. Alpha's `:root` block is its dark set, so a surface that sets neither renders dark. - **Never import from `@growth-protocol-ai/alpha/dist/**`** as a module path; it is not a public entry point. The documented subpaths are listed in `node_modules/@growth-protocol-ai/alpha/dist/llms/entry-points.md`. - **Never target the hashed class names** (`alpha-Button-root-…`). They are content-addressed and change between builds. - **Theme by overriding Alpha's custom properties** — `--primary`, `--text-typical`, `--surface-depth-0`. They are not namespaced, so they are ordinary globals: if this application already declares one of those names, one of the two will lose. Override in the same two-block shape the package uses, or a bare `:root` rule lands on both modes at once. - **For a contextual override, scope a rule to `[data-slot="…"]`** — the one supported selector into a component. A published module may add `[data-module="…"]` beside the slot to identify its fixed arrangement. `className` on a root is for layout only. - **Never pass a style object or an `sx` prop.** Neither exists. - **Combine class names with the exported `cn()` helper.** - **Alpha ships no layout or typography primitives** — no `Box`, `Stack`, `Grid`, `Typography` — and no spacing scale. Layout and running text stay in this application's own stylesheets. - **Where a mapping is ambiguous, leave the existing code and mark it** `// TODO(alpha): <what a person has to decide>`. Do not substitute the closest thing. - **Programmatic metadata**: `import { COMPONENT_REGISTRY, iconMeta } from '@growth-protocol-ai/alpha/registry'` — runtime-pure, so it is safe in server components and in Node scripts. A surface's documentation hangs off `.documentation`: `.axes` for the props whose values enumerate, `.stateCases` for its named states, `.api` for every prop, slot and published part with its owner. - Ask for the outcomeYou do not need to identify the current component library or prepare a mapping. The assistant discovers imports, wrappers and capabilities before deciding what can change.Existing UI
Audit this feature and migrate every eligible UI surface to Alpha. Preserve behaviour, accessibility, state and layout. Keep unmatched capabilities application-owned and report blockers.
New UIBuild this feature with Alpha wherever its published capabilities match. Keep layout, running text and missing capabilities application-owned, then validate the result.
Explore the task-specific instructions before adding them to a tool. These cards render the same package-generated Markdown served by the raw agent routes.
Adopting Alpha
Read this before replacing an existing component with an Alpha one, whatever it is being replaced with — a third-party library, an in-house component folder, or markup written by hand. Alpha does not know how your application is built, so this document states Alpha's own boundaries and the checks a substitution needs. It never guesses at an equivalence, and neither should you.
Alpha publishes exactly what llms.txt lists
That index is generated from the package's own registry at build time, so it is complete for the version you have installed. A component that is not in it is not Alpha's, and no amount of prop-guessing will make it exist.
What Alpha does not ship
The rule is total and never goes stale: Alpha exports exactly the surfaces
llms.txt lists. If what you need is not one of them, Alpha does not ship it
— leave the existing implementation in place, mark it, and do not approximate
it out of other Alpha components.
The ones below are called out because they are the ones most often reached for, not because the list is complete. It cannot be: the set of things Alpha does not export is unbounded.
- No layout or typography primitives. There is no
Box,Stack,Flex,Grid,TypographyorText. Layout and running text belong to the application, in its own stylesheets. Leave them alone. - No spacing scale and no breakpoint scale. Alpha's tokens cover colour, radius, elevation, type and one motion curve. Control heights live inside the components. Spacing between things is yours.
- No style escape hatch. There is no
sx, no style-object prop and nostyled(). See "The style path" below for what to do instead. - No theme provider and no reset. Theming is a CSS custom property override
plus
data-modeon<html>; there is no React context to wrap anything in. Alpha emits no element selectors, so removing a reset from your app changes your app, not Alpha. - No table, data grid or menu. A
Dropdownis a value picker and aPopoveris a panel holding whatever you put in it; neither is a menu of commands carrying its own keyboard contract, and neither is a table. - No dynamic icon lookup. There is no name-keyed map from string to glyph, because that map is exactly what would stop a bundler dropping the glyphs an application does not use.
The substitution procedure
- Inventory the application before changing it. Search imports, re-exports, path aliases, JSX, local component directories, theme providers and styling APIs. Follow each candidate to the module that implements it. The source may be a package, a wrapper around one, or markup written directly in the app; its import graph, not its folder name, tells you which it is.
- Identify the source component by its import, and read it. One name is
routinely several components: a
Tooltipfrom a third-party library, aTooltipin the application's own component folder, and a wrapper around the first that exists only to show a hint when text overflows are three different things with three different answers — and the third has no Alpha equivalent at all. Resolve the import specifier, open the implementation, and decide per specifier, never per name. - Choose the migration seam. When an application-owned wrapper can keep the API its callers use while rendering Alpha inside, change that wrapper and validate its callers as one contract. When preserving the wrapper would hide a behavioural mismatch or keep source-specific props alive, migrate the affected call sites instead. Do not bypass an application abstraction merely to make the Alpha import visible at every use.
- Match on capability, not on name. A tooltip is a tooltip whichever library drew it. A component that shares a name with an Alpha one but does something else — a "Dropdown" that is really a positioned panel, a "Card" that is really a layout grid — is not a match, and a rename would be a regression dressed as a migration.
- Read that surface's own document —
llms.txtlists one per surface — before writing a line of it. Every prop, every accepted value and every default is there. Where that table and the package's emitted.d.tsever disagree, the.d.tsis the contract. - Check the shape hazards. This is where a mechanical rename compiles and
then misbehaves, so check every one of these each time:
- A prop Alpha does not own becomes a DOM attribute. Alpha components
spread the native props of the element they render, so an unrecognised
prop is not an error — it lands on the element. The costly case is a name
that collides with a real HTML attribute: if the source component used
typefor its visual variant, thentype="primary"on an Alpha button is a valid React prop, renders no variant, and gives the element an invalidtype— which a browser treats assubmit, so the button now submits the form it sits in. Rename by attribute name, never by value, and include the computed ones (type={x ? 'a' : 'b'}). - A value outside a closed union fails silently. The variant tables are exhaustive, and a value that is not in one produces no class: the component renders unstyled, with the attribute set to your bad value. In TypeScript that is a compile error. In plain JavaScript nothing tells you.
- The handler's name and its argument. A field that called
onChange(nextValue)with a bare string does not survive being pointed at a handler that receives a DOM event, and nothing will tell you: the code compiles and the value arrives as[object Object]orundefined. - Controlled versus uncontrolled. An explicitly passed
falseis a controlled closed component, which is not the same thing as an uncontrolled one that happens to be closed. - Defaults differ, so dropping a prop is not a no-op. Omitting a prop takes Alpha's default, which is rarely the source's — a size that was implicit before can come out visibly smaller. Spell out what the old default gave you rather than letting both defaults apply.
- Two source booleans may be one Alpha axis. Where the source expressed something with independent flags and Alpha expresses it as a single union, some combinations are not expressible at all. The source resolved them by CSS rule order; Alpha makes you choose, and that choice is a decision to record rather than to guess.
- Where the content goes. Whether the label is the children, a prop, or nothing at all because the element is void.
- A prop Alpha does not own becomes a DOM attribute. Alpha components
spread the native props of the element they render, so an unrecognised
prop is not an error — it lands on the element. The costly case is a name
that collides with a real HTML attribute: if the source component used
- Geometry is Alpha's. Sizes are fixed axes with named values, and there is nothing between them or below the smallest. If the surrounding layout cannot absorb the size Alpha offers, that is a design decision for a person to take — adjust the container, or leave the existing control in place. Re-specifying a height through CSS is re-implementing the axis Alpha deliberately withheld.
- Take the style path. In order of preference:
- A token override for anything about appearance. Alpha's custom
properties are unprefixed, so they are ordinary globals — if your
application already declares one of these names, one of you will lose.
Override in the same two-block shape the package uses, or a bare
:rootrule will land on both modes at once. classNameon a component root, for layout only — width, flex, grid position, margin. Never for appearance.[data-slot="…"]for a contextual override that belongs to one place in your layout. Seeslots.md: it is the only selector into a component that Alpha supports, and overlays are portalled, which defeats the descendant selector everyone reaches for first.- Never the hashed class names. They are content-addressed and change between builds.
- A token override for anything about appearance. Alpha's custom
properties are unprefixed, so they are ordinary globals — if your
application already declares one of these names, one of you will lose.
Override in the same two-block shape the package uses, or a bare
- Icons are one static import per glyph, by name, from the
/iconssubpath. If no Alpha glyph matches the drawing you are replacing, keep the existing icon — an approximate glyph is a silent visual change. Sizes are the named steps only, never a number, and an icon is never a control: the handler and the accessible name belong to the thing around it. - Leave what you cannot resolve, and say so. Where the mapping is genuinely ambiguous — a size with no counterpart, a prop with no equivalent, a layout that would have to change — do not pick the closest thing. Leave the existing code in place and mark it:
// TODO(alpha): <what is ambiguous, and what a person has to decide>
A file that migrates eight of ten call sites and flags two is a good result. A file that migrates ten by guessing at two is a bad one, and the guesses are the expensive part to find later.
Keep a migration ledger
For work that spans files or sessions, create alpha-migration.md in the
consuming application's root and update it as part of every batch. Use one row
per resolved source export or application-owned wrapper, not one row per name:
| Source | Resolved implementation | Call sites | Capability | Alpha target | Status | Blocker | Validation |
|---|---|---|---|---|---|---|---|
specifier#export | path | paths or search | what it does | surface or none | unreviewed, ready, migrated, blocked or keep | decision required | checks run |
The ledger is discovery state, not permission to broaden the migration. Add newly found call sites before editing them, record why an item stays, and mark a row migrated only after its validation passes. A source dependency, provider, reset or stylesheet can be removed only when searches show no remaining code or configuration that needs it.
Validate in batches
Use the consuming application's own gates: typecheck, lint, tests and its visual harness where one exists. Also search for the source import and wrapper after each batch. TypeScript cannot prove that focus returns to the trigger, that an event still carries the same value, that a portal is styled in its new location, or that a default size did not change; exercise those behaviours directly.
The instructions point first to the installed package's dist/llms.txt index. The request decides which guide comes next; the guide then sends the assistant to only the component and foundation documents needed for that work.
| Request | First guide | Then |
|---|---|---|
| Replace existing UI | adopting.md | Candidate surfaces and the foundations they depend on |
| Create new UI | building.md | Candidate surfaces and their composition contracts |
| Install, theme or change fonts | setup.md | Tokens, entry points or selectors when relevant |
An llms.txt route is a discovery convention, not a guarantee that every tool reads it automatically. Use the smallest delivery that tool can follow.
| Assistant | Provide | When |
|---|---|---|
| Repository agent | The instructions block above, once | Recommended; it reads the installed package |
| Chat that can open links | The llms.txt URL with the request | One-off work outside the repository |
| Chat that cannot open links or local files | Attach llms-full.txt | Fallback only; it is the same documentation inline |
COMPONENT_REGISTRY is runtime-pure — the meta files import their components with import type only, so it carries no "use client" and is safe in server components and Node scripts. An assistant can read the real axes, state cases and API from it instead of guessing.
import { COMPONENT_REGISTRY } from '@growth-protocol-ai/alpha/registry';
const { documentation } = COMPONENT_REGISTRY.button;
documentation.profile; // what kind of thing it is: 'action', 'field', 'overlay', …
documentation.usage; // whenToUse / whenNotToUse, as prose
documentation.axes; // every prop whose values enumerate, exhaustively:
// [{ id, part, prop, title, rows: { primary: '…' } }, …]
documentation.stateCases; // named valid states, not a list of boolean props
documentation.api; // every prop, slot and published part, with its owner
documentation.apiCoverage; // where each of those is demonstrated, or why it is notThis site's own navigation, prop tables and ⌘K index are all built from it, which is why they cannot list a component the package does not export. iconMeta.catalog is the same thing for the glyph set: export name to one line on what the drawing is for, and it is checked against the icon barrel at compile time.