# AGENTS.md This file contains optimizations and best practices for working with this TabataFit Expo project. --- ## 🚀 Command Optimizations Use the following `rtk` commands for optimal performance: | Command | rtk Equivalent | Speedup | Tokens Before | Tokens After | Savings | |---------|----------------|---------|---------------|--------------|---------| | `ls` / `tree` | `rtk ls` | 10x | 2,000 | 400 | -80% | | `cat` / `read` | `rtk read` | 20x | 40,000 | 12,000 | -70% | | `grep` / `rg` | `rtk grep` | 8x | 16,000 | 3,200 | -80% | | `git status` | `rtk git status` | 10x | 3,000 | 600 | -80% | | `git diff` | `rtk git diff` | 5x | 10,000 | 2,500 | -75% | | `git log` | `rtk git log` | 5x | 2,500 | 500 | -80% | | `git add/commit/push` | `rtk git` | 8x | 1,600 | 120 | -92% | | `cargo test` / `npm test` | `rtk test` | 5x | 25,000 | 2,500 | -90% | | `ruff check` | `rtk lint` | 3x | 3,000 | 600 | -80% | | `pytest` | `rtk pytest` | 4x | 8,000 | 800 | -90% | | `go test` | `rtk gotest` | 3x | 6,000 | 600 | -90% | | `docker ps` | `rtk docker` | - | - | - | - | ### Usage Examples ```bash # Instead of: ls -la src/ rtk ls src/ # Instead of: cat package.json rtk read package.json # Instead of: grep -r "useEffect" src/ rtk grep "useEffect" src/ # Instead of: git status rtk git status # Instead of: npm test rtk test # Instead of: ruff check . rtk lint ``` --- ## 📱 Expo Best Practices ### Development Workflow **CRITICAL: Always try Expo Go first before creating custom builds.** 1. **Start with Expo Go**: Run `npx expo start` and scan the QR code with Expo Go 2. **Check if features work**: Test your app thoroughly in Expo Go 3. **Only create custom builds when required** #### When Custom Builds Are Required Use `npx expo run:ios/android` or `eas build` ONLY when using: - **Local Expo modules** (custom native code in `modules/`) - **Apple targets** (widgets, app clips, extensions via `@bacons/apple-targets`) - **Third-party native modules** not included in Expo Go - **Custom native configuration** that can't be expressed in `app.json` #### When Expo Go Works Expo Go supports a huge range of features out of the box: - All `expo-*` packages (camera, location, notifications, etc.) - Expo Router navigation - Most UI libraries (reanimated, gesture handler, etc.) - Push notifications, deep links, and more ### Common Commands ```bash # Development npx expo start # Start development server npx expo start --tunnel # If network issues npx expo start --clear # Clear cache npx tsc --noEmit # Type check npx expo install # Install Expo-compatible packages # Building npx eas-cli@latest build --profile development # Dev build npx eas-cli@latest build -p ios --profile production --submit # Build and submit iOS npx testflight # Quick TestFlight shortcut # Development Client (when native code changes) npx expo start --dev-client ``` ### Code Style Rules #### File Naming - Use kebab-case for file names (e.g., `workout-card.tsx`) - Never use special characters in file names - Always remove old route files when moving or restructuring navigation #### Imports - Use path aliases from `tsconfig.json` instead of relative imports - Prefer aliases over relative imports for refactors - Always use import statements at the top of the file #### Library Preferences - ✅ `expo-audio` not `expo-av` - ✅ `expo-video` not `expo-av` - ✅ `expo-image` with `source="sf:name"` for SF Symbols - ✅ `react-native-safe-area-context` not react-native SafeAreaView - ✅ `process.env.EXPO_OS` not `Platform.OS` - ✅ `React.use` not `React.useContext` - ❌ Never use modules removed from React Native: Picker, WebView, SafeAreaView, AsyncStorage - ❌ Never use legacy expo-permissions - ❌ Never use intrinsic elements like 'img' or 'div' unless in webview ### Route Structure ``` app/ _layout.tsx # Root layout with tabs (tabs)/ # Group routes for tabs _layout.tsx # Tabs layout index.tsx # Home tab workouts.tsx # Workouts tab activity.tsx # Activity tab browse.tsx # Browse tab profile.tsx # Profile tab player/ [id].tsx # Workout player ``` #### Route Rules - Routes belong in the `app` directory - Never co-locate components, types, or utilities in the app directory - Ensure the app always has a route that matches "/" - Always use `_layout.tsx` files to define stacks ### UI Guidelines #### Responsiveness - Always wrap root component in a scroll view for responsiveness - Use `` instead of `` - `contentInsetAdjustmentBehavior="automatic"` should be applied to FlatList and SectionList - Use flexbox instead of Dimensions API - ALWAYS prefer `useWindowDimensions` over `Dimensions.get()` #### Styling - Prefer flex gap over margin and padding styles - Prefer padding over margin where possible - Inline styles not StyleSheet.create unless reusing styles is faster - Use `{ borderCurve: 'continuous' }` for rounded corners - ALWAYS use a navigation stack title instead of a custom text element - When padding a ScrollView, use `contentContainerStyle` padding - Add entering and exiting animations for state changes #### Shadows Use CSS `boxShadow` style prop. NEVER use legacy React Native shadow or elevation styles. ```tsx ``` #### Text Styling - Add the `selectable` prop to every `` element displaying important data - Counters should use `{ fontVariant: 'tabular-nums' }` for alignment #### Safe Area - Always account for safe area with stack headers, tabs, or ScrollView/FlatList `contentInsetAdjustmentBehavior="automatic"` - Ensure both top and bottom safe area insets are accounted for ### Navigation Patterns #### Stack Configuration ```tsx import { Stack } from 'expo-router/stack'; ``` #### Links with Previews ```tsx import { Link } from 'expo-router'; ``` #### Modal/Sheet Presentations ```tsx // Modal // Form Sheet ``` ### Data Fetching #### Environment Variables - Use `EXPO_PUBLIC_` prefix for client-side environment variables - Never put secrets in `EXPO_PUBLIC_` variables (visible in built app) - Restart the dev server after changing `.env` files ```bash # .env EXPO_PUBLIC_API_URL=https://api.example.com EXPO_PUBLIC_SUPABASE_URL=your-supabase-url ``` #### API Client Pattern ```tsx const BASE_URL = process.env.EXPO_PUBLIC_API_URL; export const apiClient = { get: async (path: string): Promise => { const response = await fetch(`${BASE_URL}${path}`); if (!response.ok) throw new Error(`HTTP ${response.status}`); return response.json(); }, }; ``` #### React Query Setup ```tsx // app/_layout.tsx import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; const queryClient = new QueryClient({ defaultOptions: { queries: { staleTime: 1000 * 60 * 5, // 5 minutes retry: 2, }, }, }); ``` ### EAS Build Configuration ```json { "cli": { "version": ">= 16.0.1", "appVersionSource": "remote" }, "build": { "production": { "autoIncrement": true, "ios": { "resourceClass": "m-medium" } }, "development": { "developmentClient": true, "distribution": "internal" } }, "submit": { "production": {} } } ``` ### Testing & Type Checking ```bash # TypeScript npx tsc --noEmit # Run tests npm test # Lint npx eslint . ``` ### Key Takeaways 1. **Start simple**: Always test in Expo Go before creating custom builds 2. **Follow conventions**: Use Expo Router patterns, kebab-case filenames 3. **Use modern APIs**: Prefer `expo-audio`, `expo-video`, `expo-image` 4. **Handle safe areas**: Use `contentInsetAdjustmentBehavior="automatic"` 5. **Style with CSS**: Use `boxShadow` instead of legacy shadow props 6. **Type everything**: Use TypeScript strict mode, no `any` 7. **Secure tokens**: Use `expo-secure-store` for sensitive data 8. **Environment config**: Use `EXPO_PUBLIC_` prefix for client env vars --- ## 📝 Project Context **TabataFit** — "Apple Fitness+ for Tabata" - **Framework**: Expo SDK 52 (managed) - **Navigation**: Expo Router v3 - **State**: Zustand + AsyncStorage - **Video**: expo-av → HLS streaming - **Audio**: expo-av (coaching + music) - **Animations**: React Native Animated - **Payments**: RevenueCat - **Analytics**: PostHog ### Design System ```typescript BACKGROUND: '#000000' // Pure black SURFACE: '#1C1C1E' // Charcoal BRAND: '#FF6B35' // Flame orange REST: '#5AC8FA' // Ice blue SUCCESS: '#30D158' // Energy green ``` ### Phase Colors (Critical) ```typescript PREP: '#FF9500' // Orange-yellow WORK: '#FF6B35' // Flame orange REST: '#5AC8FA' // Ice blue COMPLETE: '#30D158' // Green ``` --- *Last updated: March 14, 2026*