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.

On this page

  1. Install Alpha
    Follow Getting started. The package includes documentation for exactly the version the application installed.
  2. Add the instructions once
    Paste 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.
  3. Ask for the outcome
    You 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 UI
    Build 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, Typography or Text. 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 no styled(). 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-mode on <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 Dropdown is a value picker and a Popover is 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

  1. 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.
  2. Identify the source component by its import, and read it. One name is routinely several components: a Tooltip from a third-party library, a Tooltip in 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.
  3. 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.
  4. 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.
  5. Read that surface's own document — llms.txt lists 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.ts ever disagree, the .d.ts is the contract.
  6. 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 type for its visual variant, then type="primary" on an Alpha button is a valid React prop, renders no variant, and gives the element an invalid type — which a browser treats as submit, 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] or undefined.
    • Controlled versus uncontrolled. An explicitly passed false is 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.
  7. 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.
  8. 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 :root rule will land on both modes at once.
    • className on 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. See slots.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.
  9. Icons are one static import per glyph, by name, from the /icons subpath. 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.
  10. 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:

SourceResolved implementationCall sitesCapabilityAlpha targetStatusBlockerValidation
specifier#exportpathpaths or searchwhat it doessurface or noneunreviewed, ready, migrated, blocked or keepdecision requiredchecks 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.