Ask an AI coding agent to "add a video player" to your Expo app, and there's a good chance it reaches for expo-av. Ask for a login screen, and it may store the session token in plain AsyncStorage, wrap the screen in SafeAreaView from react-native, and install packages with npm install instead of npx expo install.
None of that is the agent being careless. It's the agent averaging over years of tutorials, most of which were written for older versions of React Native and Expo.
The fix is cheap: a project rules file. Claude Code reads CLAUDE.md at the start of every session, and other agents read similar files (AGENTS.md, Cursor rules). A rules file tells the agent how this project works, so it stops guessing.
Here's one built for Expo + Supabase apps, section by section, then the checks that catch what still slips through.
What makes a good rules file?
-
Specific over general. "Write clean code" changes nothing. "Use
expo-image, notImagefromreact-native" changes the output. - Short. It's loaded into every session. Keep it to things the agent actually gets wrong.
- Includes the commands. Tell the agent how to check its own work, and it will.
- Lives in the repo. Commit it, so every teammate and every agent gets the same rules.
The CLAUDE.md
Copy this into the root of your project and edit it to match your stack.
# Project rules
## Stack
- Expo (managed workflow, development builds) + TypeScript (strict)
- Expo Router for navigation (file-based, in /app). Do NOT add React Navigation directly.
- Supabase for auth, database, and storage. Client in /lib/supabase.ts.
## Packages
- Install with `npx expo install <pkg>`, never `npm install`, so versions match the SDK.
- Before adding a dependency, check if Expo already provides one.
- Use: expo-image (images), expo-video / expo-audio (media; NOT expo-av),
react-native-safe-area-context (NOT SafeAreaView from react-native),
react-native-reanimated (animations), expo-secure-store (tokens/secrets).
## Navigation
- Screens live in /app. Layouts in _layout.tsx.
- Auth gating uses Stack.Protected guards in app/_layout.tsx. No useEffect redirects.
- Navigate with <Link href> or router.push. Use typed routes.
## Supabase
- Never use the secret/service key in the app. Only the publishable key.
- Every new table: enable RLS in the same migration, with policies.
- Schema changes go in supabase/migrations/, never only in the dashboard.
- After a schema change, regenerate types: `npm run db:types`.
- Pass the generated Database type to createClient. No `any` for query results.
## Code style
- Function components and hooks only.
- Handle loading, empty, and error states for every screen that fetches data.
- Every user-facing string that requests a permission needs a clear reason.
- No inline secrets. Public config uses EXPO_PUBLIC_*; everything else stays on the server.
## Before you say you're done
Run these and fix any failures:
- `npx tsc --noEmit`
- `npx expo lint`
- `npx expo-doctor`
Why each section is there
Packages
npx expo install picks versions compatible with your Expo SDK. Plain npm install grabs the latest, which is how you end up with a native module that doesn't match your SDK and a build that fails in EAS.
The "use X, not Y" list is the highest-value part of the whole file. Each line replaces a deprecated or weaker default the agent would otherwise pick:
| Agents often write | Current choice |
|---|---|
expo-av |
expo-video and expo-audio (expo-av is deprecated) |
SafeAreaView from react-native
|
react-native-safe-area-context (the core one is deprecated) |
Image from react-native
|
expo-image (caching, placeholders, better formats) |
Animated API |
react-native-reanimated |
| Tokens in AsyncStorage |
expo-secure-store for anything sensitive |
Update this table when you upgrade SDKs. It's the part that ages fastest.
Navigation
Agents trained on years of React Navigation code will happily add a NavigationContainer to an Expo Router app. One line prevents it. The auth rule matters too: protected routes handle redirects and history correctly, while scattered useEffect redirects cause flashes and back-button bugs.
Supabase
These four rules prevent the mistakes that actually hurt:
- Secret key in the app: anyone can extract it from the bundle and bypass every security rule.
- A table without RLS: readable by anyone with your public key.
- Dashboard-only schema changes: they vanish on the next reset, and your teammates never get them.
- Stale types: the compiler can't catch a renamed column if the types are out of date.
"Before you say you're done"
This is the section that changes agent behavior the most. Claude Code runs commands, so when the rules say "run these and fix failures," it type-checks and lints its own work before handing it back. expo-doctor also catches dependency versions that don't match your SDK.
What should you still review by hand?
A rules file reduces mistakes; it doesn't remove them. When reviewing agent-written Expo code, check these first:
- Permissions: is every permission request explained, and only asked for when needed?
- Empty and error states: what does the screen show with no data, or no network?
-
Secrets: search the diff for
key,secret, andtoken. - New tables: does the migration enable RLS?
-
New dependencies: were they needed, and were they installed with
npx expo install? - Platform differences: did it test only iOS? Keyboard handling and back buttons often break on Android.
How do you keep the rules useful?
- Add a rule every time you correct the agent twice. If you fix the same mistake again, it belongs in the file.
- Delete rules the agent never breaks. Shorter files get followed better.
- Review it on every SDK upgrade. Deprecated packages are the fastest-changing part.
- Share it across tools. If your team uses several agents, keep one source of truth and point the other files at it.
Wrapping up
AI agents write React Native the way the internet wrote it, which is often a few versions behind. A one-page CLAUDE.md tells them how your project works today: which packages, which navigation, which security rules, and how to check their own work.
If you'd rather start from a project that already follows these conventions, AppLighter's Expo + Supabase templates come with Expo Router, Supabase auth, and RLS set up, so your agent builds on a clean base.
What's the one rule your agent keeps breaking? Drop it in the comments.
Top comments (0)