From rn-dev-agent
Provides React Native and Expo best practices via 118 rules for code reviews, component architecture, performance optimization, animations, navigation, UI audits, state management, and production readiness.
npx claudepluginhub lykhoyda/rn-dev-agent --plugin rn-dev-agent**/*.{ts,tsx,js,jsx}**/package.jsonThis skill uses the workspace's default tool permissions.
This skill is the **routing surface** between Claude and the vendored
Suggests manual /compact at logical task boundaries in long Claude Code sessions and multi-phase tasks to avoid arbitrary auto-compaction losses.
Share bugs, ideas, or general feedback.
This skill is the routing surface between Claude and the vendored
vercel-labs/agent-skills
content under third_party/vercel-labs/agent-skills/. Don't read the 118
rule files upfront. Use the procedures below to look up only the rules
that apply to the code you're about to write or review.
The routing surface is skills/rn-best-practices/rules.index.json. Each entry:
{ "id": "react-native-skills/list-performance-virtualize",
"title": "Use a list virtualizer for any list",
"category": "react-native-skills",
"platform": "RN",
"severity": "CRITICAL" | "HIGH" | "MEDIUM" | "LOW",
"triggers": ["FlatList", "FlashList", "ScrollView"],
"upstream_path": "third_party/vercel-labs/agent-skills/skills/.../list-performance-virtualize.md",
"checkable": true | false,
"checkerRule": "no-touchable-new-code" | null
}
Query with jq or read directly. Filter by platform: "RN" for React Native
work; platform: "both" for composition rules; platform: "web" only for
web React when applicable.
These cause runtime crashes. Check on every review pass. Do not delegate.
&& rendering crash{x && <Comp />} where x could be 0, "", or NaN renders the falsy
value as a string in RN. Bad: {count && <Badge />} (renders "0").
Good: {count > 0 && <Badge />} or ternary. Full rule:
third_party/vercel-labs/agent-skills/skills/react-native-skills/rules/rendering-no-falsy-and.md
<Text>A string as a direct child of <View> is a runtime crash on RN.
Bad: <View>Hello</View>. Good: <View><Text>Hello</Text></View>.
Full rule: .../rules/rendering-text-in-text-component.md
Defining const Child = () => … inside function Parent() creates a new
component type every render. RN remounts it, destroying state, native views,
animations, scroll position, focus. Bad: inline function components inside
parents. Good: define outside, pass data via props. Full rule (web/RN):
.../skills/react-best-practices/rules/rerender-no-inline-components.md
Use these procedures whenever you're about to write or review code in the
listed scope. The procedure tells you which rules.index.json entries to
load; you then read only the matched upstream_path files.
rules.index.json, select entries where id starts with
react-native-skills/list-performance- (8 rules).severity: CRITICAL or HIGH (typically 5-6 rules).keyExtractor returns a non-id field).Most common applicable rules: list-performance-virtualize,
list-performance-inline-objects, list-performance-callbacks,
list-performance-item-memo.
id starts with react-native-skills/animation-
(3 rules) OR react-native-skills/react-compiler-reanimated-.width, height, top) instead
of GPU-friendly transform/opacity; useAnimatedReaction for derived
values where useDerivedValue is faster.id starts with react-best-practices/async- OR
contains query-cache (custom rule).await on independent calls (use
Promise.all); imperative cache reads (use reactive query hooks).category: "composition-patterns" (8 rules) OR
id ends with compound-components (1 RN rule).forwardRef in React 19 code (just receive ref as a prop);
render-props where children composition would work.id starts with react-native-skills/navigation- OR
matches rn-dev-agent/navigation-*.presentation: 'transparentModal' causes routing failures — see
references/rn-dev-agent/navigation-transparent-modal.md.id starts with react-native-skills/ui- (9 rules).ui-pressable even when LOW (it's a
convention enforcement, not a perf issue).Image from react-native (use expo-image); JS-rendered
bottom sheets (use native modals); Touchable* in new code.These four rules are NOT in the upstream Vercel set — they were discovered
through rn-dev-agent story testing on Bridgeless RN 0.76.x. They survive
every upstream sync at references/rn-dev-agent/:
| File | Trigger context |
|---|---|
references/rn-dev-agent/navigation-transparent-modal.md | Bridgeless + react-native-screens routing |
references/rn-dev-agent/query-cache-reactive.md | React Query — imperative reads |
references/rn-dev-agent/reanimated-in-lists.md | Reanimated layout animations inside virtualized lists |
references/rn-dev-agent/theme-memoization-lists.md | Theme hooks consumed inside renderItem |
These also appear in rules.index.json under category: "rn-dev-agent".
A subset of rules has automated grep checking via scripts/check-vercel-rules.mjs
running as a PostToolUse hook on every Edit | MultiEdit | Write against
.tsx/.jsx/.ts/.js files. Currently 3 rules are checkable: true in
the index:
react-native-skills/ui-pressable → no-touchable-new-codereact-native-skills/list-performance-inline-objects → no-inline-renderitem-literalsreact-native-skills/rendering-no-falsy-and → no-falsy-jsx-andViolations surface as additionalContext injected after the edit — Claude
sees them but they don't block the edit. Block-on-violation behavior lives
in --ci mode (used by the pre-ship-checker integration), not the live
edit loop.
For manual full-project audits: /check-vercel-rules slash command.
| Excuse | Reality |
|---|---|
| "It's just a 10-item list, I don't need FlashList" | Apps grow. Today's 10 items become tomorrow's 1000. Use FlashList from the start — cost is near-zero, upgrade later is painful. |
| "Inline arrow functions in renderItem are fine for this case" | Every parent re-render produces a new function reference; every list item re-renders. Use useCallback — one extra line. |
"The && pattern is clear enough here" | items.length && <Content/> renders "0" when items is []. Always use items.length > 0 ? … : null. Crash vector. |
| "I'll handle SafeAreaView later" | Later never comes. Every screen needs safe-area handling from day one — affects hit targets, not just visuals. |
| "User asked for a simple feature — skip the rule review" | Simple features ship. Bad patterns become codebase conventions. Always review at Phase 4 (Architecture) and Phase 6 (Review). |
"I'll use Touchable* everywhere — it's familiar" | Touchable* is deprecated. Use Pressable — it's the supported API and has built-in pressed/hovered states. |
| "I need to migrate the whole codebase to follow rule X" | Scope discipline. Apply rules to NEW code and code you're already touching. Don't refactor adjacent files. |
&& falsy-value patternsFlashList or FlatList with proper memoizationrenderItemSafeAreaView or edges propTouchable* in new code (should be Pressable)Intl.DateTimeFormat called inside render (hoist to module level)