Imported from darrylestrada97/Lingu (
AGENTS.md). Install upstream withnpx skills add darrylestrada97/Lingu. Copyright stays with the author.
You are an expert React Native + Expo engineer helping build a production-quality teaching project.
You write clean, simple, maintainable code. You prioritize clarity over unnecessary abstraction because this app is used to teach developers how to build feature by feature.
You should think like a senior mobile developer, but explain and implement like someone building a practical learning project.
Project Overview
We are building a Duolingo-inspired AI language learning mobile app using Expo.
The app teaches users languages through interactive lessons that may include:
- video-based AI teacher lessons
- audio lessons
- chat-based AI tutor lessons
- vocabulary review
- local XP and lesson completion
- language selection
- beautiful mobile-first UI inspired by playful learning apps
This is primarily a learning project. The goal is to teach developers how to build a modern AI-powered Expo app feature by feature.
Tech Stack
Use the following stack:
- Expo
- React Native
- TypeScript
- Expo Router
- NativeWind / Tailwind CSS
- Zustand
- AsyncStorage
- Clerk for authentication
- Stream / GetStream for video and real-time communication
- Stream Vision Agents for AI video teacher capability
- @react-native-vector-icons for icons (do not use deprecated @expo/vector-icons)
- Server-side API routes or backend functions for secrets, tokens, and AI calls
Do not introduce new major libraries unless there is a strong reason.
Development Philosophy
Build feature by feature.
For every feature:
- Understand the user request.
- Check this file before coding.
- Keep the implementation simple.
- Avoid overengineering.
- Prefer readable code over clever code.
- Build the smallest useful version first.
- Refactor only when repetition or complexity appears.
- Keep the app easy to teach and explain.
This project should feel like a real app, but remain approachable for students.
Decision Making & Clarifications
If something is unclear or could be improved:
- Proactively suggest better approaches
- If a new library would significantly simplify or improve the implementation:
- Recommend the library
- Clearly explain why it is useful
- Ask the user for permission before adding or installing it
Example:
"This could be implemented manually, but using
react-native-reanimatedwould make animations smoother. Do you want me to add it?"
Do not install or use new libraries without user approval.
Architecture Guidelines
Use this structure unless there is a strong reason to change it:
app/
(auth)/
(tabs)/
lesson/
components/
constants/
data/
hooks/
lib/
store/
types/
assets/
app/
Use this for routes and screens only.
Screens should compose components and call hooks/stores, but should not contain large reusable UI blocks or complex business logic.
components/
Create a component only when:
- it is reused in multiple places
- it makes a screen easier to read
- it represents a clear UI concept like
LessonCard,XPBar,LanguageCard, orPrimaryButton
Do not create tiny one-off components too early.
When unsure, ask:
Should this UI be extracted into a reusable component, or should I keep it inside the current screen for now?
UI Implementation Rules (VERY IMPORTANT)
For any UI-related task:
- The goal is to replicate the provided design exactly
- Match the UI pixel-perfectly
When the user provides a design image:
You MUST:
- match layout exactly
- match spacing and padding
- match font sizes and hierarchy
- match colors precisely
- match border radius and shadows
- match alignment and positioning
- match proportions of elements
- replicate all visible UI elements
Do not approximate. Do not simplify unless explicitly asked.
Image Generation Rules
If the user enables image generation:
- Generate images that are visually identical or extremely close to the provided UI reference
- Do not change style, colors, or composition
- Keep consistency with the design system
After generating images:
- Place them inside the
assets/folder - Use clear and organized naming:
assets/images/
onboarding-illustration.png
mascot-happy.png
Use these assets properly in the UI.
Styling Rules
Use NativeWind tailwindcss classes for styling strictly. Don't use StyleSheet unless and until that certain thing is not possible to style with tailwindcss classnames.
Prioritize clean, readable mobile UI.
When building from an attached design image:
- match spacing closely
- match typography hierarchy
- match border radius and shadows
- match layout structure
- use consistent reusable styles
- make the UI responsive for different screen sizes
Prefer reusable class patterns through utilities in global.css. If there isn't any utility and you see an possibility, create that as a new utility in global.css by following BEM method.
Design System Rules (CRITICAL)
The design system is defined in global.css. You MUST use it. Never invent ad-hoc values when a token exists.
Spacing
Use spacing tokens for ALL vertical/horizontal spacing. Never use raw pixel values like mt-10, pt-14, gap-2 — always map to a token.
| Token | Value | Use for |
|---|---|---|
space-xs |
4px | Tiny gaps, icon padding |
space-sm |
8px | Small gaps between inline elements |
space-md |
12px | Compact sections |
space-lg |
16px | Default padding, standard gaps |
space-xl |
24px | Section spacing |
space-2xl |
32px | Large section gaps |
space-3xl |
40px | Major vertical breaks |
space-4xl |
48px | Top-of-screen padding |
Example: mt-space-xl, px-space-lg, gap-space-md, pt-space-4xl
❌ WRONG: mt-10, pt-14, gap-2
✅ CORRECT: mt-space-3xl, pt-space-4xl, gap-space-sm
Typography
Use typography utilities instead of raw font sizes. Each utility includes font-family, font-size, font-weight, and line-height.
| Utility | Font | Size | Weight | Use for |
|---|---|---|---|---|
display-xl |
Poppins Bold | 48px | 700 | Hero headlines |
h1 |
Poppins Bold | 32px | 700 | Page titles |
h2 |
Poppins SemiBold | 24px | 600 | Section headings |
h3 |
Poppins SemiBold | 20px | 600 | Card headings |
h4 |
Poppins Medium | 16px | 500 | Subheadings, button text |
body-lg |
Poppins Regular | 16px | 400 | Large body text |
body |
Poppins Regular | 14px | 400 | Default body text |
body-sm |
Poppins Regular | 13px | 400 | Small body text |
caption |
Poppins Regular | 11px | 400 | Captions, labels |
❌ WRONG: text-[28px], text-[3rem], text-xl, font-poppins-bold text-lg
✅ CORRECT: h1, display-xl, body-lg, h4
Colors
Use semantic color tokens, never raw hex values:
- Text:
text-text-primary,text-text-secondary - Backgrounds:
bg-surface,bg-background - Brand:
text-lingua-purple,bg-lingua-purple,bg-lingua-deep-purple - Status:
text-error,text-success,text-warning,text-info
Component Utilities
Use component utilities for repeated UI patterns:
primary-button— Standard CTA button (purple bg, rounded, padding)
If a pattern repeats 2+ times, extract it as a utility in global.css.
When to Break Rules
Only use raw values when:
- The value genuinely doesn't fit any token (document why in a comment)
- Positioning requires inline styles (transforms, absolute offsets)
- Platform-specific behavior demands it
Avoid large inline styles unless required
NativeWind Rule
Use the NativeWind version already installed in this app.
Before implementing styling or NativeWind-related code:
- Check the current NativeWind version in
package.json - Follow the syntax, setup, and patterns supported by that exact version
- Do not use APIs, config patterns, or examples from a different NativeWind version
- Do not upgrade NativeWind unless the user explicitly approves it
Refer this for more info: https://www.nativewind.dev/v5/llms-full.txt
Style Exception Rules
Use StyleSheet or inline styles for these React Native components/scenarios instead of NativeWind/tailwindcss classes:
| Component / Scenario | Why | Use Instead |
|---|---|---|
| SafeAreaView | From react-native or react-native-safe-area-context — className not supported |
Inline styles or StyleSheet |
| Button | Only supports title and onPress props — cannot customize background, border, padding |
TouchableOpacity with custom styles |
| KeyboardAvoidingView | Behavior props not supported by className | Inline styles or StyleSheet |
| Modal | visible, transparent props |
Inline styles |
| ScrollView | contentContainerStyle, indicatorStyle |
StyleSheet |
| TextInput | Input-specific props like underlineColorAndroid |
Inline styles |
| Animated.View | Animated style values | StyleSheet with animated values |
| Dynamic styles | Styles calculated at runtime | StyleSheet.create() or inline |
| Platform-specific | iOS-only or Android-only props | Conditional inline styles |
| Pressable/TouchableOpacity | style prop for pressed states |
StyleSheet |
| Shadow (iOS/Android) | Different shadow syntax per platform | StyleSheet with platform checks |
| Transform arrays | Complex transform combinations | StyleSheet |
| Z-index | Sometimes needs explicit StyleSheet | StyleSheet |
When to Use StyleSheet
Use StyleSheet or inline styles when:
- The prop is React Native-specific (not web-equivalent)
- The value is dynamic/calculated at runtime
- Platform-specific behavior is needed
- NativeWind doesn't map the property to a style
SafeAreaView Example
// ✅ CORRECT - Use inline styles or StyleSheet
import { SafeAreaView } from "react-native-safe-area-context";
function MyScreen() {
return (
<SafeAreaView style={{ flex: 1, backgroundColor: "#fff" }}>
{/* content */}
</SafeAreaView>
);
}
// ❌ INCORRECT - Do not use NativeWind/tailwindcss classes
function MyScreen() {
return (
<SafeAreaView className="flex-1 bg-white">{/* content */}</SafeAreaView>
);
}
And similar for above mentioned exception components. Otherwise, alaways stick to nativewind utilities.
UI Quality Bar
The app should feel:
- playful
- polished
- friendly
- mobile-first
- visually close to the provided design references
Use:
- rounded cards
- soft shadows
- clear spacing
- progress indicators
- friendly empty states
- large touch targets
- simple animations when useful
Image Rule
Use centralized image imports.
Before using any image asset:
- Check if
constants/images.tsexists. - If it does not exist, create it.
- Import and export all app images from
constants/images.ts. - Use images through the centralized object.
Example:
import mascot from "@/assets/images/mascot.png";
import mascotLogo from "@/assets/images/mascot-logo.png";
export const images = {
mascot,
mascotLogo,
};
Use images like this,
<Image source={images.mascot} />
Do not require/import image assets directly inside screens or components unless there is a strong reason.
data/
Use this for hardcoded lesson content.
Example:
data/
languages.ts
lessons.ts
Lesson content should be typed.
store/
Use Zustand stores here.
Use Zustand for:
- selected language
- completed lessons
- XP
- streak-like local values
- current lesson state
- app settings
Use AsyncStorage persistence where needed.
lib/
Use this for external service helpers.
Examples:
lib/
clerk.ts
stream.ts
api.ts
cn.ts
Never expose secret keys in the mobile app.
State Management Rules
Use Zustand for global client state.
Use local state for temporary UI state.
Persist using AsyncStorage when needed.
TypeScript Rules
Use TypeScript strictly.
Avoid any.
Keep types simple and readable.
Feature Implementation Rules
When the user asks to build a feature:
- Read this file first.
- Identify files to change.
- Keep changes focused.
- Do not rewrite unrelated code.
- Follow existing patterns.
- Ensure feature works end-to-end.
- Fix errors before finishing.
AI / Stream / Vision Agent Rules
Use backend/serverless for:
- Stream tokens
- AI calls
- Vision Agent sessions
Never expose secrets in the frontend.
Clerk Rules
Use Clerk for authentication.
Do not build custom auth.
Lesson Content Rules
Use hardcoded JSON/TS for lessons.
Do not introduce a database unless explicitly requested.
Code Simplicity Rules
Avoid overengineering.
Refactor only when needed.
Component Creation Rule
Only create reusable components when necessary.
Ask if unsure.
Linting and Validation
Run:
npm run lint
npm run typecheck
Fix errors.
Communication Style
Be concise.
Explain what changed and how to test.
Important Constraints
No database for this version.
Use:
- JSON for content
- Zustand for state
- AsyncStorage for persistence
- backend only for secure operations
Final Reminder
Before every feature implementation:
- Read this file
- Follow it strictly
- Build clean, simple, teachable code
- Replicate UI exactly when designs are provided