AI Coding Agents Don't Understand Mobile. Here's How to Fix That.
You hand Claude or ChatGPT a React Native feature spec. It generates clean code. You copy it into your IDE. You run the app. It crashes. Or worse — it builds, but navigates wrong, ignores platform conventions, or breaks under iOS and Android separately.
This isn't because the AI is stupid. It's because the AI was trained primarily on web code. Mobile development is a different beast, with different constraints, different APIs, different affordances. When you ask a web-trained AI to write mobile code without context about those differences, it defaults to web patterns — which often don't exist on mobile, or exist as anti-patterns.
The fix isn't a better model (that's coming). The fix is to teach your AI agent about mobile constraints upfront. Here's what it gets wrong, why, and how you fix it.
The Gap: AI Agents Are Trained on Web, Not Mobile
GitHub, Stack Overflow, and open-source repos have far more web code than mobile code. React, Vue, Svelte codebases are orders of magnitude more common than React Native codebases. When training data skews heavily toward web, the model learns web patterns as defaults.
Add to this: mobile has platform-specific code (iOS vs Android) that requires understanding two different frameworks simultaneously. Web code is mostly browser-agnostic (or close enough). Mobile code requires active, deliberate platform awareness.
The result: AI agents write React Native code that looks like React web code. Which sometimes works. Often doesn't.
5 Things AI Agents Get Wrong in React Native
1. Navigation (Web Routing vs Stack Navigation)
Web apps use URL-based routing. Mobile apps use imperative navigation stacks. An AI trained on React Router thinks it should use URLs for state. It doesn't understand that React Navigation is imperative, stack-based, and deeply nested.
What it writes:
// ❌ Web routing pattern (doesn't work in RN)
function App() {
return (
<Router>
<Routes>
<Route path="/details/:userId" component={DetailsScreen} />
</Routes>
</Router>
);
}
// Wrong: passing props through nesting
<Stack.Screen
name="Details"
component={() => <DetailsScreen userId={userId} />}
/>What it should write:
// ✓ Mobile navigation pattern
<Stack.Screen
name="Details"
component={DetailsScreen}
initialParams={{ userId: '123' }}
/>
// Component receives params, not props
function DetailsScreen({ route }: RootStackScreenProps<'Details'>) {
const { userId } = route.params;
}Get all 16 free CLAUDE.md templates + cheat sheets
Enterprise-grade conventions for every major stack, plus Claude Code and prompt engineering guides. No account needed.
2. Styling (CSS vs StyleSheet)
Mobile doesn't have CSS. It has StyleSheet and a subset of CSS-like properties. Tailwind doesn't work in React Native (or requires a wrapper). Flexbox is the default but some properties work differently than web.
What it writes:
// ❌ Web CSS patterns
<View style={{ margin: '0 auto', display: 'flex' }}>
<Text className="text-blue-600">Hello</Text>
</View>What it should write:
// ✓ Mobile styling
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
},
});
<View style={styles.container}>
<Text style={{ color: '#2563EB' }}>Hello</Text>
</View>3. State Management (Server State That Doesn't Work Offline)
Web apps assume the server is always reachable. Mobile apps go offline constantly. An AI trained on web patterns fetches data synchronously, doesn't retry, doesn't cache, doesn't queue mutations for when the network comes back.
What it writes:
// ❌ Web state pattern (fails offline)
const [data, setData] = useState(null);
useEffect(() => {
fetch('/api/users')
.then(r => r.json())
.then(setData)
.catch(() => {}); // silent fail
}, []);What it should write:
// ✓ Mobile state pattern (handles offline)
const [data, setData] = useState(null);
const [error, setError] = useState(null);
const [isOffline, setIsOffline] = useState(false);
useEffect(() => {
const netInfo = await getNetworkStateAsync();
if (!netInfo.isConnected) {
setIsOffline(true);
const cached = await AsyncStorage.getItem('users');
setData(cached ? JSON.parse(cached) : null);
return;
}
fetch('/api/users')
.then(r => r.json())
.then(data => {
setData(data);
AsyncStorage.setItem('users', JSON.stringify(data));
})
.catch(e => setError(e));
}, []);4. Platform Code (Ignoring iOS/Android Differences)
Two platforms. Different APIs, different permission systems, different UI conventions. An AI that doesn't know about Platform.select() or platform-specific files writes code that works on one platform and breaks on the other.
What it writes:
// ❌ Non-portable code
import { NativeModules } from 'react-native';
const biometric = NativeModules.BiometricPrompt.authenticate();
// ❌ Doesn't exist on iOS, throws immediatelyWhat it should write:
// ✓ Platform-aware code
import * as LocalAuthentication from 'expo-local-authentication';
import { Platform } from 'react-native';
const authenticate = async () => {
const compatible = await LocalAuthentication.hasHardwareAsync();
if (!compatible) return false;
try {
const result = await LocalAuthentication.authenticateAsync({
disableDeviceFallback: false,
});
return result.success;
} catch (e) {
return false;
}
};5. Build & Deployment (No Understanding of EAS/Xcode/Gradle)
Web has npm run build. Mobile has EAS, Xcode, Gradle, app.json, eas.json, native config plugins. An AI trained on web doesn't understand signing, provisioning profiles, build variants, or app store submission requirements.
What it writes: Ignores app.json entirely, doesn't consider app permissions, doesn't think about native config.
What it should do: Update app.json permissions, install native packages correctly, add expo plugins, generate proper build configs.
Why Generic CLAUDE.md Files Don't Cut It For Mobile
A CLAUDE.md file tells an AI agent the rules of your project. What your folder structure is. What patterns you use. What conventions you follow. What technologies you've chosen.
A generic web CLAUDE.md tells the agent about routes, components, styling, API clients. None of that translates to mobile.
A mobile CLAUDE.md tells the agent:
- This project uses React Navigation with typed params
- Platform-specific code goes in *.ios.ts and *.android.ts files
- StyleSheet is how we style (not CSS, not Tailwind)
- This project's auth hook is useAuth() — use it everywhere
- We use Expo, so native modules must be Expo-compatible
- All data fetches must handle offline mode
- Safe area insets are managed by SafeAreaView
- Permissions are declared in app.json and checked at runtime
Without this, the AI defaults to web patterns. With it, the AI writes mobile code from the start.
CLAUDE.md sets the rules. Archie runs the workflow.
Persistent memory, role-based skills, and approval gates. From idea to merged PR.
The Solution: Mobile-Aware Memory + Platform-Smart Skills
The real fix combines two things:
1. A mobile-specific CLAUDE.md that documents your RN project's structure, patterns, conventions, and constraints.
2. Mobile-aware skills that understand navigation design, platform constraints, native module capabilities, and app store rules.
A web-trained AI equipped with both of these can actually write mobile code that works.
How Archie Mobile Addresses Each of the 5 Problems
Navigation
Archie's /architect skill understands React Navigation stacks. It designs features with typed params, considers nested navigation, handles deep links. /tech-lead breaks down navigation requirements separately. /dev-agent implements screens with proper typing.
Styling
Archie reads your theme configuration and enforces StyleSheet patterns from your CLAUDE.md. It never generates CSS or Tailwind for mobile.
State Management
Archie's memory documents your state library (Zustand, Redux, Jotai) and how to handle offline. Dev agents always implement offline-first data fetching.
Platform Code
Archie knows which native modules are installed and their platform support. It generates platform-specific files. It checks platform availability before using native APIs.
Build & Deployment
Archie reads app.json and eas.json. When it adds features requiring permissions or native config, it updates these files automatically.
Real Example: Building a Feature With and Without Mobile Context
Feature spec: Add fingerprint auth with PIN fallback
Without Mobile Context
A generic AI reads this and generates:
// ❌ Not mobile-aware
function AuthScreen() {
const [pin, setPin] = useState('');
const authenticate = async () => {
// No biometric check
// No platform detection
// No offline handling
const res = await fetch('/api/auth', {
method: 'POST',
body: JSON.stringify({ pin }),
});
console.log(await res.json());
};
return (
<View>
<TextInput onChangeText={setPin} value={pin} />
<Button onPress={authenticate} />
</View>
);
}With Mobile Context
Archie Mobile with your CLAUDE.md generates:
// ✓ Mobile-aware
import * as LocalAuthentication from 'expo-local-authentication';
import { useAuth } from '@/hooks/useAuth';
import { useSafeAreaInsets } from 'react-native-safe-area-context';
function AuthScreen() {
const { login } = useAuth();
const [pin, setPin] = useState('');
const [usingPin, setUsingPin] = useState(false);
const insets = useSafeAreaInsets();
const tryBiometric = async () => {
try {
const compatible = await LocalAuthentication.hasHardwareAsync();
if (!compatible) {
setUsingPin(true);
return;
}
const result = await LocalAuthentication.authenticateAsync({
reason: 'Authenticate to access your account',
disableDeviceFallback: false,
});
if (result.success) {
await login({ method: 'biometric' });
}
} catch (e) {
setUsingPin(true);
}
};
const handlePinSubmit = async () => {
if (pin.length !== 4) return;
try {
await login({ method: 'pin', pin });
} catch (e) {
Alert.alert('Invalid PIN');
}
};
useEffect(() => {
tryBiometric();
}, []);
return (
<SafeAreaView style={{ flex: 1, paddingHorizontal: 16 }}>
{usingPin ? (
<>
<Text style={{ fontSize: 18, fontWeight: 'bold' }}>
Enter Your PIN
</Text>
<TextInput
value={pin}
onChangeText={setPin}
maxLength={4}
keyboardType="numeric"
secureTextEntry
/>
<Button title="Submit" onPress={handlePinSubmit} />
</>
) : (
<ActivityIndicator />
)}
</SafeAreaView>
);
}The second version: checks biometric hardware, handles the fallback, respects safe area insets, uses the auth hook, validates PIN length, shows loading state. It's production-ready because the AI understood mobile constraints from the start.
Get all 16 free CLAUDE.md templates + cheat sheets
Enterprise-grade conventions for every major stack, plus Claude Code and prompt engineering guides. No account needed.
The Path Forward
AI agents won't magically understand mobile. But you can teach them. A proper CLAUDE.md + mobile-aware tooling + platform context = AI agents that write production mobile code.
The investment is small. The return is huge. You get:
- 3x faster feature development
- Fewer app store rejections
- Cleaner, more consistent PRs
- Less context-switching for your team
- Platform-aware code from day one
CLAUDE.md sets the rules. Archie runs the workflow.
Persistent memory, role-based skills, and approval gates. From idea to merged PR.