AI-Assisted Development

RapidRailsUI publishes four machine-readable surfaces so Cursor, Claude Code, ChatGPT, and any other agent can generate correct component code on the first try — no guessing at syntax.

AI-Facing Resources

Three static files, ranked by how much context budget they cost. Point an agent at whichever fits the task — all three are always current with the live docs site.

File Size Use it when...
llms.txt ~1,300 lines Default choice. One-line-per-component index, argument-order and color conventions, form builder pattern. Enough for most single-component requests.
llms-full.txt ~19,000 lines llms.txt's one-liner isn't enough detail — full params, slots, variants, and copy-paste examples per component, one ## ComponentName section each.
llms-mini.txt ~60 lines Tight context budget. A single table (complexity, param/slot counts, AI-friendliness score) for a first pass over "which component do I need" before loading detail.

Starting point for most prompts: "Using RapidRailsUI (read https://rapidrails.cc/llms.txt first), build a <thing>." That's the whole setup step — no MCP server, no config file, no copy-paste into a system prompt required for tools that can fetch a URL.

Content Negotiation

Every /docs/<component> page — all 37, including newer ones like /docs/carousel and /docs/kanban — serves three representations of the same content depending on the request's Accept header. No .json/.md extension needed; it's pure header negotiation.

Accept header Response
text/html The rendered docs page (default for browsers).
application/json (or */*) Structured schema for that one component: params, slots, gotchas, related components/compositions — the same data the schema YAMLs hold, pre-merged.
text/markdown (or text/plain) The matching ## ComponentName section of llms-full.txt, as plain Markdown.
curl examples
# Plain curl sends "Accept: */*" by default, which matches JSON first —
# no -H flag needed to get structured data:
curl -s https://rapidrails.cc/docs/card | jq

# Explicit JSON (same result as above, spelled out):
curl -s https://rapidrails.cc/docs/tabs -H "Accept: application/json" | jq

# Markdown — the llms-full.txt section for one component, nothing else:
curl -s https://rapidrails.cc/docs/carousel -H "Accept: text/markdown"

# HTML — the actual rendered page (what a browser gets):
curl -s https://rapidrails.cc/docs/kanban -H "Accept: text/html"

Two aggregate JSON endpoints sit alongside the per-component negotiation:

  • GET /api/schema.json — every component's schema in one response. Large; use it for a one-shot "load everything" pull, not per-request.
  • GET /api/schema/components/<name>.json — one component, same shape as the per-page JSON negotiation.

The Installed Gem: Your Version-True Fallback

This site always documents the latest gem release. If your app's Gemfile.lock pins an older rapid_rails_ui, the hosted docs can describe params or behavior your installed version doesn't have yet. Every component ships its own USAGE.md right next to component.rb inside the gem — that file is exact for whatever version is actually installed.

Find the installed USAGE.md files
# Locate every component's USAGE.md in the installed gem:
find "$(bundle show rapid_rails_ui)" -name USAGE.md

# Or jump straight to one component:
cat "$(bundle show rapid_rails_ui)/app/components/rapid_rails_ui/card/USAGE.md"

Tell your agent to prefer this when versions might disagree: "Before using rui_<component>, check $(bundle show rapid_rails_ui)/app/components/rapid_rails_ui/<component>/USAGE.md in this repo's installed gem — it's authoritative for our pinned version, even if it differs from rapidrails.cc."

Schema YAMLs for Advanced Agents

The JSON content negotiation above is a per-component merge of five machine-readable YAML files, shipped inside the gem at lib/rapid_rails_ui/schema/. An agent working directly in your codebase (rather than fetching from rapidrails.cc) can read these directly for the same data, offline:

File Purpose
manifest.yml Per-component metadata: helper name, complexity, param/slot counts, form-builder support, AI-usability score.
slots.yml Every renders_one/renders_many slot per component, with an example with_* call.
gotchas.yml Non-obvious param interactions that silently fail — e.g. rui_text(as: :h1, size: :xl) silently ignoring size:.
families.yml Decision trees for choosing between similar components — e.g. "filter table rows" points to rui_live_search, not rui_combobox.
compositions.yml Multi-component recipes no single component covers — e.g. "author byline" = rui_avatar + rui_text, with the exact ERB.

A sixth file, relationships.yml, is auto-derived from the five above (which components compose with which, which are commonly confused) and merged into the per-component JSON automatically — you don't need to read it separately.

Prompt Recipes

Four copy-paste starting points. Each is a full request you can hand to Cursor or Claude Code as-is — adjust the specifics, keep the "read llms.txt first" instruction and the component names.

1. Pricing section with rui_card

Prompt
Using RapidRailsUI (read https://rapidrails.cc/llms.txt first), build a pricing
section with 3 rui_card tiers: Starter, Pro, Enterprise. Each card needs:
- an icon slot (with_icon) matching the tier
- a header slot (with_header) with the tier name
- a checklist (with_list / with_item) of 4 features
- a footer CTA (with_footer) linking to /signup

Highlight the Pro tier with variant: :elevated and color: :primary; leave the
other two at their defaults.

Iterate: if the agent reaches for a plain <div> or invents a rui_pricing_card that doesn't exist, it didn't actually load llms.txt — re-paste the URL, or point it straight at https://rapidrails.cc/docs/card with Accept: text/markdown for the canonical slot API.

2. Tabbed section with rui_tabs

Prompt
Using RapidRailsUI (see https://rapidrails.cc/docs/tabs — fetch it with
Accept: text/markdown for the full spec), build a rui_tabs component with 3
tabs: Overview, Pricing, FAQ. Use variant: :spaced, deep_link: true so the
URL hash tracks the active tab, and give the Pricing tab a badge: "New".

Iterate: ask for changes in plain language — "make it vertical with tablist_position: :end" or "switch to :pills and make Overview active by default." A correctly-primed agent edits only the with_tab calls that changed, not the whole block.

3. Form with automatic server-error display

Prompt
Using RapidRailsUI form builder methods (f.rui_input, f.rui_select,
f.rui_textarea) inside form_with(model: @user), build a form for name, email,
and a bio textarea. Do not add manual error-checking code — f.rui_* methods
already detect @user.errors[:field] automatically and render the inline
error styling and message on their own.

Iterate: if the agent adds its own <% if @user.errors[:email].any? %> wrapper around a field, that's the tell it missed the automatic-detection convention. Point it at the "Errors" section of rui_input's USAGE.md and ask it to delete the manual check.

4. Dashboard with rui_stat + rui_table

Prompt
Using RapidRailsUI (read https://rapidrails.cc/llms.txt), build a dashboard
section: 3 rui_stat cards in a row (Total Sales, Active Listings, Conversion
Rate), each with a change: indicator (e.g. change: "+8%"), followed by a
rui_table(sortable: true) showing the 5 most recent listings with sortable
Name, Status, and Created columns.

Iterate: table and link are the two lowest AI-friendliness scores in llms-mini.txt — expect at least one follow-up round for column config. Ask the agent to check rui_table's USAGE.md before guessing at a column option a second time.

Using Your AI Tool

Setup is the same idea everywhere: get the tool to fetch or read llms.txt, then prompt as usual. Specifics per tool:

Cursor

@Add docs → paste https://rapidrails.cc/llms.txt. Cursor indexes it once; re-add the URL after a RapidRailsUI upgrade if @docs still generates old syntax (it caches).

Claude Code

No setup step — just reference the URL in your prompt (see the recipes above). Claude Code fetches it live on each session, so there's no stale-cache failure mode to debug.

ChatGPT and tools without URL fetching

Paste the file's contents directly into the first message instead of the URL:

Copy llms.txt to clipboard
curl -s https://rapidrails.cc/llms.txt | pbcopy
# Paste into the chat, then ask your question

Use llms-full.txt instead for a specific component's full detail — it's larger, so only paste it when llms.txt's one-liner genuinely isn't enough.

Claude Desktop, Windsurf, and other MCP-capable tools

Any client that speaks MCP can wire up an llms-txt-mcp server pointed at the same URLs (llms.txt, llms-full.txt) to auto-fetch context per conversation instead of re-pasting it — see that project's own setup docs for the exact config shape for your client.

Troubleshooting

Agent invents a component or wrong argument order

It's working from stale training data instead of the docs. Re-paste the llms.txt URL, or for a single stubborn component, fetch its exact section directly: curl -s https://rapidrails.cc/docs/<component> -H "Accept: text/markdown" and paste that instead — smaller, harder to ignore.

Cursor's @docs won't pick up a new release

Remove and re-add the llms.txt URL in @docs, or restart Cursor — it caches fetched docs content and doesn't re-poll on every message.

JSON/Markdown negotiation returns HTML or 404s

Double-check the Accept header spelling (application/json, not json) and that the component name matches the URL path exactly (e.g. /docs/button_to, not /docs/button-to). A 404 on the Markdown format for a real component means that component's section is missing from llms-full.txt — worth a bug report.

For Stimulus/JS-side issues (controllers not firing, esbuild collisions, etc.) — those aren't AI-specific; see the dedicated Troubleshooting page .