Files
tabatago/AGENTS.md

9.7 KiB

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

# 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

# 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 <pkg>      # 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 <ScrollView contentInsetAdjustmentBehavior="automatic" /> instead of <SafeAreaView>
  • 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.

<View style={{ boxShadow: "0 1px 2px rgba(0, 0, 0, 0.05)" }} />

Text Styling

  • Add the selectable prop to every <Text/> 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

import { Stack } from 'expo-router/stack';

<Stack
  screenOptions={{
    headerTransparent: true,
    headerShadowVisible: false,
    headerLargeTitleShadowVisible: false,
    headerLargeStyle: { backgroundColor: "transparent" },
    headerTitleStyle: { color: PlatformColor("label") },
    headerLargeTitle: true,
    headerBlurEffect: "none",
    headerBackButtonDisplayMode: "minimal",
  }}
>
  <Stack.Screen name="index" options={{ title: "Home" }} />
</Stack>
import { Link } from 'expo-router';

<Link href="/settings">
  <Link.Trigger>
    <Pressable>
      <Card />
    </Pressable>
  </Link.Trigger>
  <Link.Preview />
  <Link.Menu>
    <Link.MenuAction title="Share" icon="square.and.arrow.up" />
    <Link.MenuAction title="Delete" icon="trash" destructive />
  </Link.Menu>
</Link>

Modal/Sheet Presentations

// Modal
<Stack.Screen name="modal" options={{ presentation: "modal" }} />

// Form Sheet
<Stack.Screen
  name="sheet"
  options={{
    presentation: "formSheet",
    sheetGrabberVisible: true,
    sheetAllowedDetents: [0.5, 1.0],
    contentStyle: { backgroundColor: "transparent" },
  }}
/>

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
# .env
EXPO_PUBLIC_API_URL=https://api.example.com
EXPO_PUBLIC_SUPABASE_URL=your-supabase-url

API Client Pattern

const BASE_URL = process.env.EXPO_PUBLIC_API_URL;

export const apiClient = {
  get: async <T,>(path: string): Promise<T> => {
    const response = await fetch(`${BASE_URL}${path}`);
    if (!response.ok) throw new Error(`HTTP ${response.status}`);
    return response.json();
  },
};

React Query Setup

// 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

{
  "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

# 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

BACKGROUND: '#000000'    // Pure black
SURFACE: '#1C1C1E'       // Charcoal
BRAND: '#FF6B35'         // Flame orange
REST: '#5AC8FA'          // Ice blue
SUCCESS: '#30D158'       // Energy green

Phase Colors (Critical)

PREP: '#FF9500'    // Orange-yellow
WORK: '#FF6B35'    // Flame orange
REST: '#5AC8FA'    // Ice blue
COMPLETE: '#30D158' // Green

Last updated: March 14, 2026