inertia-rails-architecture
Server-driven architecture patterns for Inertia Rails + React. Load this FIRST when building any Inertia page or feature — it routes to the right skill. Decision matrix for data loading, forms, navigation, state management. NEVER useEffect+fetch, NEVER redirect_to for external URLs (use inertia_location), NEVER react-hook-form (use Form component). MUST invoke when adding pages, models with views, CRUD, or displaying data in an Inertia Rails app. ALWAYS `render inertia: { key: value }` to pass data — `@ivars` are NOT auto-passed as props.
What this skill does
# Inertia Rails Architecture
Server-driven architecture for Rails + Inertia.js + React when building pages,
forms, navigation, or data refresh. Inertia is NOT a traditional SPA — the
server owns routing, data, and auth. React handles rendering only.
## The Core Mental Model
The server is the source of truth. React receives data as props and renders UI.
There is no client-side router, no global state store, no API layer.
**Before building any feature, ask:**
- **Where does the data come from?** → If server: controller prop. If user interaction: `useState`.
- **Who owns this state?** → If it's in the URL or DB: server owns it (use props). If it's ephemeral UI: React owns it.
- **Am I reaching for a React/SPA pattern?** → Check the decision matrix below first — Inertia likely has a server-driven equivalent.
## Decision Matrix
| Need | Solution | NOT This |
|------|----------|----------|
| Page data from server | Controller props | useEffect + fetch |
| Global data (auth, config) | `inertia_share` + `usePage()` | React Context / Redux |
| Flash messages / toasts | Rails `flash` + `usePage().flash` | inertia_share / React state |
| Form submission | `<Form>` component | fetch/axios + useState |
| Navigate between pages | `<Link>` / `router.visit` | react-router / window.location |
| Refresh specific data | `router.reload({ only: [...] })` | React Query / SWR |
| Expensive server data | `InertiaRails.defer` | useEffect + loading state |
| Infinite scroll | `InertiaRails.scroll` + `<InfiniteScroll>` | Client-side pagination |
| Stable reference data | `InertiaRails.once` | Cache in React state |
| Real-time updates (core) | ActionCable + `router.reload` | Polling with setInterval |
| Simple polling (MVP/prototyping) | `usePoll` (auto-throttles in background tabs) | setInterval + router.reload |
| URL-driven UI state (dialogs, tabs) | Controller reads `params` → prop, `router.get` to update | useEffect + window.location |
| Ephemeral UI state | `useState` / `useReducer` | Server props |
| External API calls | Dedicated API endpoint | Mixing with Inertia props |
## Rules (by impact)
| # | Impact | Rule | WHY |
|---|--------|------|-----|
| 1 | CRITICAL | Never useEffect+fetch for page data | Inertia re-renders the full component on navigation; a useEffect fetch creates a second data lifecycle that drifts from props and causes stale UI |
| 2 | CRITICAL | Never check auth client-side | Auth state in React can be spoofed; server-side checks are the only real gate. Client-side "guards" give false security |
| 3 | CRITICAL | Use `<Form>`, not fetch/axios | `<Form>` handles CSRF, redirect-following, error mapping, file detection, and history state — fetch duplicates or breaks all of this |
| 4 | HIGH | Use `<Link>` and `router`, not `<a>` or window.location | `<a>` triggers a full page reload, destroying all React state and layout persistence |
| 5 | HIGH | Use partial reloads, not React Query/SWR | React Query adds a second cache layer that conflicts with Inertia's page-based caching and versioning |
| 5b | HIGH | Use `usePoll` only for MVPs; prefer ActionCable for production real-time | `usePoll` is convenient but wastes bandwidth — every interval hits the server even when nothing changed. ActionCable pushes only on actual changes |
| 6 | HIGH | Use `inertia_share` for global data, not React Context | Context re-renders consumers on every change; shared props are per-request and integrated with partial reloads |
| 7 | HIGH | Use Rails flash for notifications, not shared props | Flash auto-clears after one response; shared props persist until explicitly changed, causing stale toasts |
| 8 | MEDIUM | Use deferred/optional props for expensive queries | Blocks initial render otherwise — user sees blank page until slow query finishes |
| 9 | MEDIUM | Use persistent layouts for state preservation | Without persistent layout, layout remounts on every navigation — scroll position, audio playback, and component state are lost |
| 10 | MEDIUM | Keep React components as renderers, not data fetchers | Mixing data-fetching into components makes them untestable and breaks Inertia's server-driven model |
## Skill Map
Common workflows span multiple skills — load all listed for complete coverage:
| Workflow | Load these skills |
|----------|-------------------|
| New page with props | `inertia-rails-controllers` + `inertia-rails-pages` + `inertia-rails-typescript` |
| Form with validation | `inertia-rails-forms` + `inertia-rails-controllers` |
| shadcn form inputs | `inertia-rails-forms` + `shadcn-inertia` |
| Flash toasts | `inertia-rails-controllers` + `inertia-rails-pages` + `shadcn-inertia` |
| Deferred/lazy data | `inertia-rails-controllers` + `inertia-rails-pages` |
| URL-driven dialog/tabs | `inertia-rails-controllers` + `inertia-rails-pages` |
| Alba serialization | `alba-inertia` + `inertia-rails-typescript` |
| Testing controllers | `inertia-rails-testing` + `inertia-rails-controllers` |
## References
**MANDATORY — READ ENTIRE FILE** before building a new Inertia page or feature:
[`references/AGENTS.md`](references/AGENTS.md) (~430 lines) — full-stack examples for
each pattern in the decision matrix above.
**MANDATORY — READ ENTIRE FILE** when unsure which Inertia pattern to use:
[`references/decision-trees.md`](references/decision-trees.md) (~70 lines) — flowcharts
for choosing between prop types, navigation methods, and data strategies.
**Do NOT load** references for quick questions about a single pattern already
covered in the decision matrix above.
## When You DO Need a Separate API
Not everything belongs in Inertia's request cycle. Use a traditional API endpoint when:
| Signal | Why | Example |
|--------|-----|---------|
| Non-browser consumer | Inertia's JSON envelope (component, props, url, version) is designed for the frontend adapter — other consumers can't use it | Mobile API, CLI tools, payment webhooks |
| Large-dataset search | Dataset is too big to load as a prop; each input needs per-keystroke server filtering. Use raw fetch for the search, let Inertia handle post-selection side effects via props. | City/address autocomplete, postal code lookup |
| Binary/streaming response | Inertia can only deliver JSON props. Use a separate route with a standard download response. | PDF/CSV export, file downloads |
Related in Design
contribute
IncludedLocal-only OSS contribution command center. Auto-refreshes the user's in-flight PR and issue state on invoke so conversations start with full context — no need to brief Claude on what's in flight. Helps the user find issues to contribute to on GitHub, builds per-repo dossiers of what each upstream expects (CLA, DCO, branch convention, AI policy, draft-first, review bots, issue templates), runs deterministic gates before any external action so AI-assisted contributions don't reach maintainers as slop. State is markdown-only: candidate files at ~/.contribute-system/candidates/, repo dossiers at ~/.contribute-system/research/, append-only event log at ~/.contribute-system/log.jsonl. No database, no cloud calls. Use when the user asks about their PRs / issues / contributions, wants to find new work to take on, claim an issue, build/refresh a repo's dossier, or draft a Design Issue or PR. Trigger with "/contribute", "what's my PR status", "find a contribution", "claim issue X", "draft a Design Issue for Y", "refresh dossier for Z".
architectural-analysis
IncludedUser-triggered deep architectural analysis of a codebase or scoped subtree across eight modes — information architecture, data flow, integration points, UI surfaces, interaction patterns, data model, control flow, and failure modes. This skill should be used when the user asks to "diagram this codebase," "map the architecture," "show the data flow," "give me an ERD," "trace control flow," "find the integration points," "verify the layout pattern," "audit the UX architecture," or any similar request whose primary deliverable is mermaid diagrams plus cited reports under docs/architecture/. Dispatches haiku/sonnet sub-agents in parallel for per-mode exploration, then verifies every citation mechanically before any node lands in a diagram. Not for one-off prose explanations of code (use code-explanation) or for high-level system design from scratch (use system-design).
mcp
IncludedModel Context Protocol (MCP) server development and tool management. Languages: Python, TypeScript. Capabilities: build MCP servers, integrate external APIs, discover/execute MCP tools, manage multi-server configs, design agent-centric tools. Actions: create, build, integrate, discover, execute, configure MCP servers/tools. Keywords: MCP, Model Context Protocol, MCP server, MCP tool, stdio transport, SSE transport, tool discovery, resource provider, prompt template, external API integration, Gemini CLI MCP, Claude MCP, agent tools, tool execution, server config. Use when: building MCP servers, integrating external APIs as MCP tools, discovering available MCP tools, executing MCP capabilities, configuring multi-server setups, designing tools for AI agents.
react-native-skia
IncludedDesign, build, debug, and optimise high-polish animated graphics in React Native or Expo using @shopify/react-native-skia, Reanimated, and Gesture Handler. Use when the user wants canvas-driven UI, shaders, paths, rich text, image filters, sprite fields, Skottie, video frames, snapshots, web CanvasKit setup, or performance tuning for custom motion-heavy elements such as loaders, hero art, cards, charts, progress indicators, particle systems, or gesture-driven surfaces. Also use when the user asks for fluid, glow, glass, blob, parallax, 60fps/120fps, or GPU-friendly animated effects in React Native, even if they do not explicitly say "Skia". Do not use for ordinary form/layout work with standard views.
plaid
IncludedProduct Led AI Development — guides founders from idea to launched product. Six capabilities: Idea (discover a product idea), Validate (pressure-test the idea against fatal flaws, problem reality, competition, and 2-week MVP feasibility), Plan (vision intake + document generation), Design (translate image references into a design.md spec), Launch (go-to-market strategy), and Build (roadmap execution). Use when someone says "PLAID", "plaid idea", "help me find an idea", "product idea", "idea from my business", "idea from my expertise", "plaid validate", "validate my idea", "pressure-test", "is this idea good", "find fatal flaws", "validate the problem", "plan a product", "define my vision", "generate a PRD", "product strategy", "plaid design", "design from image", "translate image to design", "create design.md", "extract design tokens", "plaid launch", "go-to-market", "launch plan", "GTM strategy", "launch playbook", "plaid build", "build the app", "start building", or "execute the roadmap".
nextjs-framer-motion-animations
IncludedAdds production-safe Motion for React or Framer Motion animations to Next.js apps, including reveal, hover and tap micro-interactions, whileInView, stagger, AnimatePresence, layout and layoutId transitions, reorder, scroll-linked UI, and lightweight route-content transitions. Use when the user asks to add, refactor, or debug Motion or Framer Motion in App Router or Pages Router codebases, especially around server/client boundaries, reduced motion, LazyMotion, bundle size, hydration, or route transitions. Avoid for GSAP-style timelines, WebGL or 3D scenes, heavy scroll storytelling, or CSS-only effects unless Motion is explicitly requested.