- All React components live in
src/components/with PascalCase filenames matching the component export:src/components/UserProfile.tsxexportsUserProfile - All screens live in
src/screens/with PascalCase filenames:src/screens/HomeScreen.tsx - All navigation configuration lives in
src/navigation/— never define navigation stacks inside screen files - All hooks live in
src/hooks/with camelCase filenames prefixed withuse:src/hooks/useUserData.ts - All utilities live in
src/utils/with camelCase filenames by function:src/utils/dateFormatting.ts,src/utils/validation.ts - All theme and styling constants live in
src/theme/— never create astyles.tsfile in component directories - All API calls live in
src/api/with resource-based filenames:src/api/users.ts,src/api/posts.ts - All types live in
src/types/with camelCase filenames:src/types/user.ts,src/types/navigation.ts - Test files must live adjacent to source with
.test.tsor.test.tsxsuffix:src/utils/dateFormatting.test.ts
- Every file exports exactly one default export if it's a component or hook:
export default UserProfile - Named exports are forbidden for components and hooks — use default export only
- Utility files may have multiple named exports:
export const formatDate = ...andexport const parseDate = ... - Never use
export *— always name what you export - Re-export patterns are forbidden — if
src/index.tsexists, it must not re-export from other files
- All colors must come from
src/theme/colors.ts— never use hardcoded color strings like#FF5733or'red' - All spacing values must come from
src/theme/spacing.ts— never use hardcoded pixel values like16or'20px' - All font sizes must come from
src/theme/typography.ts— never use hardcoded sizes - StyleSheet.create() calls must only reference theme tokens:
color: colors.primary,marginTop: spacing.md - Platform-specific styles must use
Platform.select()inside StyleSheet.create:Platform.select({ ios: {...}, android: {...} }) - Never create inline styles with
style={{}}— always use StyleSheet.create - Dark mode support requires conditional theme selection:
const theme = isDarkMode ? darkTheme : lightTheme— never hardcode light-only colors
- Every component that accepts props must define a TypeScript interface named
{ComponentName}Props:interface UserProfileProps { userId: string } - Components must not directly call navigation functions — pass navigation as a prop or use
useNavigation()hook only in screen components - Components must not fetch data directly — data must be passed as props or fetched in parent screen component
- Every component with conditional rendering must use early returns, never ternary operators in JSX:
if (!user) return null;then render - Components must not use
anytype — useunknownand type guard, or define explicit interface - Ref forwarding requires
forwardRefwrapper:const Button = forwardRef<...>((props, ref) => ...)
- All server data fetching must use React Query with
useQuery()— never useuseStatefor server data - Query keys must be defined in
src/api/queryKeys.tsas constants:export const userKeys = { all: ['users'], byId: (id: string) => ['users', id] } - Every
useQuery()call must specifystaleTimeandgcTimeexplicitly — never rely on defaults - Mutations must use
useMutation()withonSuccessandonErrorcallbacks — never chain.then()on mutation - Optimistic updates must use
setQueryData()before mutation — never assume mutation will succeed - Cache invalidation must use
queryClient.invalidateQueries()with specific query keys — never userefetchQueries: 'all'
- Every screen with
TextInputmust wrap content inKeyboardAvoidingViewwithbehavior={Platform.OS === 'ios' ? 'padding' : 'height'} - Every
TextInputmust havereturnKeyTypeset explicitly:returnKeyType="next"orreturnKeyType="done" - Every
TextInputmust haveonSubmitEditinghandler — never leave it undefined - Form inputs must use controlled components:
value={state}andonChangeText={setState}— never use uncontrolled inputs - Input validation must happen on blur, not on every keystroke — use
onBlurhandler for validation - Password inputs must have
secureTextEntry={true}— never display passwords in plain text
- All navigation stacks must be defined in
src/navigation/RootNavigator.tsx— never define stacks in screen files - Navigation params must be typed in
src/types/navigation.tswithRootStackParamListinterface - Navigation must use
useNavigation<NativeStackNavigationProp<RootStackParamList>>()— never use untyped navigation - Deep linking configuration must live in
src/navigation/linking.ts— never inline linking config - Screen options must be defined in
src/navigation/screenOptions.ts— never pass options inline toScreencomponents - Back button handling must use
useFocusEffect()withBackHandler.addEventListener()— never useuseEffect()
- All async functions must have try/catch blocks — never leave promises unhandled
- Caught errors must be typed:
catch (err) { if (err instanceof AppError) {...} else if (err instanceof NetworkError) {...} }— never usecatch (e: any) - All API calls must throw typed errors from
src/types/errors.ts:class AppError extends Error { code: string } - Network errors must be caught and transformed to
NetworkErrortype — never expose raw fetch/axios errors - Error messages shown to users must come from
src/utils/errorMessages.ts— never show raw error.message - Every screen must have error boundary or error state — never let errors crash the app silently
- All API endpoints must be defined in
src/api/endpoints.tsas constants:export const ENDPOINTS = { users: '/users', userById: (id) =>/users/${id}} - All API calls must include timeout:
fetch(url, { timeout: 10000 })— never make requests without timeout - All request/response bodies must be validated with Zod schemas in
src/api/schemas/— never trust API responses - API base URL must come from environment variables:
process.env.EXPO_PUBLIC_API_URL— never hardcode URLs - All API calls must include retry logic with exponential backoff — use React Query's
retryandretryDelayoptions - Sensitive data like auth tokens must never be logged — use
console.log()only in development with__DEV__guard
- All environment variables must be prefixed with
EXPO_PUBLIC_for client-side access — never use unprefixed variables - Secrets must never be stored in code — use
.env.local(gitignored) for development - All user input must be validated at component boundary using Zod:
const parsed = userSchema.parse(input)— never skip validation - Authentication tokens must be stored in secure storage:
SecureStore.setItemAsync()— never store in AsyncStorage - All API requests to protected endpoints must include auth token in header:
Authorization: Bearer ${token}— never send tokens in query params - CORS headers must be validated on backend — never disable CORS checks in production
- Every utility function must have a
.test.tsfile with 100% line coverage — no exceptions - Every hook must have a
.test.tsxfile usingrenderHook()from@testing-library/react-native— never test hooks in component tests - Every screen must have a
.test.tsxfile testing navigation and error states — never skip screen tests - Test files must use
describe()blocks organized by function:describe('UserProfile', () => { describe('rendering', () => {...}); describe('interactions', () => {...}); }) - Mock API calls with
jest.mock('src/api/users')— never make real API calls in tests - Mock navigation with
jest.mock('@react-navigation/native')— never test actual navigation in component tests - All async tests must use
waitFor()from@testing-library/react-native— never usesetTimeout()in tests
- Every platform-specific implementation must use
Platform.OS === 'ios'orPlatform.OS === 'android'— never usePlatform.select()for logic, only for styles - iOS-specific code must live in
src/utils/ios/and Android-specific insrc/utils/android/— never mix platform code in shared files - Platform-specific components must use
.ios.tsxand.android.tsxfile extensions:Button.ios.tsxandButton.android.tsx - Every platform-specific feature must have a fallback for unsupported platforms — never crash on unsupported platforms
- Permissions must be checked before use:
const { status } = await Permissions.askAsync(Permissions.CAMERA)— never assume permissions are granted
- All lists must use
FlatListwithkeyExtractorandmaxToRenderPerBatch— never useScrollViewwith map() - Every
FlatListmust haveremoveClippedSubviews={true}on Android — never render all items - Images must use
Imagecomponent with explicit width and height — never useresizeMode="contain"without dimensions - Heavy computations must use
useMemo()with explicit dependency array — never compute in render - Event handlers must use
useCallback()with explicit dependency array — never define functions inline in JSX
- All logging must be wrapped in
if (__DEV__)guard — never log in production builds - Sensitive data must never be logged — no tokens, passwords, or PII in logs
- Error logging must use structured format:
{ code: string, message: string, context: object }— never log raw errors - Console methods must be typed:
console.error()for errors,console.warn()for warnings,console.log()for info — never useconsole.log()for errors
Source: Codelibrium — the marketplace for AI behaviour files. Browse multiple rulesets at codelibrium.com or install via CLI:
npx codelibrium-cli install <ruleset-name>