Instruction file for AI coding agents (Windsurf, OpenAI Codex CLI, Gemini CLI, and similar tools). Read this before making any changes.
A production-ready React Native + TypeScript boilerplate. Everything is pre-wired: navigation, dark/light theming, localization, HTTP hooks, animations, and a provider-agnostic AI service layer supporting OpenAI, Anthropic, and Google Gemini.
Stack: React Native 0.84 Β· React 19 Β· TypeScript 5 (strict) Β· react-navigation v7 Β· reanimated v4 Β· axios Β· i18next
src/
βββ hooks/ # useAIChat, useAICompletion
βββ navigation/ # Stack + Bottom Tab wiring
βββ screens/ # One folder per screen (Screen.tsx + Screen.style.ts)
βββ services/
β βββ ai/ # AI service layer (providers/, AIService.ts, types.ts)
β βββ event-emitter/ # Shared event bus
β βββ models/ # Shared TypeScript interfaces
βββ shared/
β βββ components/ # RN-prefixed shared components + barrel index.ts
β βββ constants/ # SCREENS enum
β βββ localization/ # i18next (en + tr-TR)
β βββ theme/ # palette, LightTheme, DarkTheme, fonts, font-size
βββ utils/
- Always use path aliases, never deep relative paths (
../../..) - Common aliases:
@shared-components,@services/*,@screens/*,@hooks,@theme/*,@fonts,@utils - Import from
@services/aibarrel β never from individual provider files
- Call
useMemo(() => createStyles(theme), [theme])in every component that needs styles createStyles(theme: ExtendedTheme)returns aStyleSheet.create({...})- Colors always come from
const { colors } = useTheme()β never hardcoded
- Text: always
TextWrapperfrom@shared-components/text-wrapper/TextWrapper - Touchables: always
RNBounceablefrom@freakycoder/react-native-bounceable - Safe area:
SafeAreaViewfromreact-native-safe-area-context - Shared component files go in
src/shared/components/<name>/RN<Name>.tsx+RN<Name>.style.ts - Export new components from
src/shared/components/index.ts
- Props interfaces use
Iprefix:IMyComponentProps noUnusedLocalsandnoUnusedParametersare enforced β every declared identifier must be used- Use
export type { Foo }for type-only re-exports - Exhaustive switch default:
const x: never = val; throw new Error(...)
- Screen names live only in
SCREENS(src/shared/constants/index.ts) - Register screens in
src/navigation/index.tsx
AIConfig.modelis a plain string β the developer supplies it; the service never hardcodes model names- To add a new AI provider: implement
IAIProvider, add acaseincreateProvider()inAIService.ts - Streaming: use
streamAIMessage()oruseAIChat().streamMessage()β tokens arrive viaonTokencallback - API keys stay in component state only β never in source files
| Command | Description |
|---|---|
npm start |
Start Metro bundler |
npm run start:fresh |
Metro with cache reset (use after adding path aliases) |
npm run ios |
iOS simulator |
npm run android |
Android emulator |
npm run lint |
ESLint |
npm test |
Jest |
| Task | Files to touch |
|---|---|
| Add a screen | SCREENS const β navigation/index.tsx β new screens/<name>/ folder |
| Add a shared component | shared/components/<name>/RN<Name>.tsx + style + barrel export |
| Add an AI provider | services/ai/providers/<name>.ts β AIService.ts β types.ts |
| Add a path alias | babel.config.js + tsconfig.json β run npm run start:fresh |
| Add a translation key | shared/localization/index.ts (en + tr-TR objects) |