Expo + TanStack + Zustand rules for AI coding agents
Full stack: Expo (React Native) + TanStack Query + Zustand + Jest
Ready-to-commit rules for Expo (React Native) + TanStack Query + Zustand + Jest in every major format: AGENTS.md (Codex, Cursor, Copilot), CLAUDE.md (Claude Code), Cursor .mdc project rules, legacy .cursorrules, Copilot instructions, Windsurf rules and GEMINI.md. Expo with TanStack Query for server state and Zustand for UI state.
Last reviewed 2026-10-21 · Customise in the generator · Raw: AGENTS.md, CLAUDE.md
Server data gets duplicated into Zustand and goes stale.
Generated files
# AGENTS.md - this project
Instructions for AI coding agents working in this repository.
## Project
A Expo (React Native) + TanStack Query + Zustand + Jest project.
Stack: Expo (React Native), TanStack Query, Zustand, Jest.
## Commands
- Start dev server: `npx expo start`
- Add a native-compatible package: `npx expo install <package>`
- Check project health: `npx expo-doctor`
- Type-check: `npx tsc --noEmit`
- Unit tests: `npx jest`
## Project structure
- Screens are files in `app/` (Expo Router). Layouts are `_layout.tsx`.
- Reusable components in `components/`, hooks in `hooks/`.
## How to work in this repo
- Read the relevant files before editing. Follow the patterns already in the codebase over these generic rules.
- Make the smallest change that solves the task. Do not refactor or reformat unrelated code.
- Before saying a task is done, run the type-check, lint and tests listed under Commands and fix what you broke.
- If requirements are ambiguous, ask one clear question instead of guessing.
- Never commit secrets, API keys or `.env` files. Use env vars and keep `.env.example` up to date.
- Do not add a new dependency when the standard library or an existing dependency already covers it.
- Ask before adding, removing or upgrading any dependency.
- Ask before changing database schemas, auth, payments or CI configuration.
- Never delete files, drop data or run destructive commands (`rm -rf`, `git push --force`, `DROP TABLE`) without explicit approval.
- Keep each change under ~200 changed lines where possible; split larger work into steps.
## Expo (React Native)
- Install packages with `npx expo install` so versions match the Expo SDK.
- Use Expo Router for navigation (`<Link>`, `router.push`). Do not add React Navigation manually unless it is already in use.
- Use React Native primitives (`View`, `Text`, `Pressable`) only. No DOM elements.
- Use `FlatList` / `FlashList` for long lists, never `.map()` inside a `ScrollView`.
- Wrap screens in safe-area handling (`react-native-safe-area-context`).
- Env vars must start with `EXPO_PUBLIC_` to reach the app, so they are public. Keep secrets on a server.
- Store tokens with `expo-secure-store`, not AsyncStorage.
- Do not edit `ios/` or `android/` by hand when using Continuous Native Generation; use config plugins in `app.json` / `app.config.ts`.
## TanStack Query
- All server data goes through `useQuery` / `useMutation`; do not copy query results into `useState`.
- Use array query keys built by a small key factory (e.g. `todoKeys.detail(id)`).
- Invalidate or update affected queries in `onSuccess` of every mutation.
- Wrap queries in custom hooks (`useTodos()`) instead of calling `useQuery` inline everywhere.
## Zustand
- Keep stores small and split by domain.
- Select only what a component needs (`useStore((s) => s.count)`) to avoid unnecessary re-renders.
- Use Zustand for client/UI state only. Server data belongs in the data-fetching layer.
## Jest
- Co-locate tests as `*.test.ts(x)` or in `__tests__/`, matching the existing convention.
- Use React Native Testing Library or Testing Library queries by role/text, not implementation details.
- Reset mocks between tests; no shared mutable state across tests.
## Reference docs
- [Expo docs](https://docs.expo.dev)
- [TanStack Query docs](https://tanstack.com/query/latest)
- [Zustand docs](https://zustand.docs.pmnd.rs)
- [Jest docs](https://jestjs.io/docs/getting-started)
# CLAUDE.md - this project
Project instructions for Claude Code.
## Project
A Expo (React Native) + TanStack Query + Zustand + Jest project.
Stack: Expo (React Native), TanStack Query, Zustand, Jest.
## Commands
- Start dev server: `npx expo start`
- Add a native-compatible package: `npx expo install <package>`
- Check project health: `npx expo-doctor`
- Type-check: `npx tsc --noEmit`
- Unit tests: `npx jest`
## Project structure
- Screens are files in `app/` (Expo Router). Layouts are `_layout.tsx`.
- Reusable components in `components/`, hooks in `hooks/`.
## How to work in this repo
- Read the relevant files before editing. Follow the patterns already in the codebase over these generic rules.
- Make the smallest change that solves the task. Do not refactor or reformat unrelated code.
- Before saying a task is done, run the type-check, lint and tests listed under Commands and fix what you broke.
- If requirements are ambiguous, ask one clear question instead of guessing.
- Never commit secrets, API keys or `.env` files. Use env vars and keep `.env.example` up to date.
- Do not add a new dependency when the standard library or an existing dependency already covers it.
- Ask before adding, removing or upgrading any dependency.
- Ask before changing database schemas, auth, payments or CI configuration.
- Never delete files, drop data or run destructive commands (`rm -rf`, `git push --force`, `DROP TABLE`) without explicit approval.
- Keep each change under ~200 changed lines where possible; split larger work into steps.
## Expo (React Native)
- Install packages with `npx expo install` so versions match the Expo SDK.
- Use Expo Router for navigation (`<Link>`, `router.push`). Do not add React Navigation manually unless it is already in use.
- Use React Native primitives (`View`, `Text`, `Pressable`) only. No DOM elements.
- Use `FlatList` / `FlashList` for long lists, never `.map()` inside a `ScrollView`.
- Wrap screens in safe-area handling (`react-native-safe-area-context`).
- Env vars must start with `EXPO_PUBLIC_` to reach the app, so they are public. Keep secrets on a server.
- Store tokens with `expo-secure-store`, not AsyncStorage.
- Do not edit `ios/` or `android/` by hand when using Continuous Native Generation; use config plugins in `app.json` / `app.config.ts`.
## TanStack Query
- All server data goes through `useQuery` / `useMutation`; do not copy query results into `useState`.
- Use array query keys built by a small key factory (e.g. `todoKeys.detail(id)`).
- Invalidate or update affected queries in `onSuccess` of every mutation.
- Wrap queries in custom hooks (`useTodos()`) instead of calling `useQuery` inline everywhere.
## Zustand
- Keep stores small and split by domain.
- Select only what a component needs (`useStore((s) => s.count)`) to avoid unnecessary re-renders.
- Use Zustand for client/UI state only. Server data belongs in the data-fetching layer.
## Jest
- Co-locate tests as `*.test.ts(x)` or in `__tests__/`, matching the existing convention.
- Use React Native Testing Library or Testing Library queries by role/text, not implementation details.
- Reset mocks between tests; no shared mutable state across tests.
## Reference docs
- [Expo docs](https://docs.expo.dev)
- [TanStack Query docs](https://tanstack.com/query/latest)
- [Zustand docs](https://zustand.docs.pmnd.rs)
- [Jest docs](https://jestjs.io/docs/getting-started)
---
description: "Core rules for this project"
alwaysApply: true
---
# this project
A Expo (React Native) + TanStack Query + Zustand + Jest project.
Stack: Expo (React Native), TanStack Query, Zustand, Jest.
## Commands
- Start dev server: `npx expo start`
- Add a native-compatible package: `npx expo install <package>`
- Check project health: `npx expo-doctor`
- Type-check: `npx tsc --noEmit`
- Unit tests: `npx jest`
## How to work in this repo
- Read the relevant files before editing. Follow the patterns already in the codebase over these generic rules.
- Make the smallest change that solves the task. Do not refactor or reformat unrelated code.
- Before saying a task is done, run the type-check, lint and tests listed under Commands and fix what you broke.
- If requirements are ambiguous, ask one clear question instead of guessing.
- Never commit secrets, API keys or `.env` files. Use env vars and keep `.env.example` up to date.
- Do not add a new dependency when the standard library or an existing dependency already covers it.
- Ask before adding, removing or upgrading any dependency.
- Ask before changing database schemas, auth, payments or CI configuration.
- Never delete files, drop data or run destructive commands (`rm -rf`, `git push --force`, `DROP TABLE`) without explicit approval.
- Keep each change under ~200 changed lines where possible; split larger work into steps.
---
description: "Expo (React Native) conventions: Expo + React Native app with Expo Router and TypeScript."
globs: app/**/*.tsx, src/**/*.tsx, src/**/*.ts, components/**/*.tsx
alwaysApply: false
---
# Expo (React Native)
- Install packages with `npx expo install` so versions match the Expo SDK.
- Use Expo Router for navigation (`<Link>`, `router.push`). Do not add React Navigation manually unless it is already in use.
- Use React Native primitives (`View`, `Text`, `Pressable`) only. No DOM elements.
- Use `FlatList` / `FlashList` for long lists, never `.map()` inside a `ScrollView`.
- Wrap screens in safe-area handling (`react-native-safe-area-context`).
- Env vars must start with `EXPO_PUBLIC_` to reach the app, so they are public. Keep secrets on a server.
- Store tokens with `expo-secure-store`, not AsyncStorage.
- Do not edit `ios/` or `android/` by hand when using Continuous Native Generation; use config plugins in `app.json` / `app.config.ts`.
Docs: https://docs.expo.dev
---
description: "TanStack Query conventions: Server-state caching with TanStack Query."
globs: **/*.tsx, **/hooks/**/*.ts
alwaysApply: false
---
# TanStack Query
- All server data goes through `useQuery` / `useMutation`; do not copy query results into `useState`.
- Use array query keys built by a small key factory (e.g. `todoKeys.detail(id)`).
- Invalidate or update affected queries in `onSuccess` of every mutation.
- Wrap queries in custom hooks (`useTodos()`) instead of calling `useQuery` inline everywhere.
Docs: https://tanstack.com/query/latest
---
description: "Zustand conventions: Lightweight client state with Zustand."
globs: **/store/**/*.ts, **/stores/**/*.ts
alwaysApply: false
---
# Zustand
- Keep stores small and split by domain.
- Select only what a component needs (`useStore((s) => s.count)`) to avoid unnecessary re-renders.
- Use Zustand for client/UI state only. Server data belongs in the data-fetching layer.
Docs: https://zustand.docs.pmnd.rs
---
description: "Jest conventions: Unit tests with Jest."
globs: **/*.test.ts, **/*.test.tsx, **/__tests__/**
alwaysApply: false
---
# Jest
- Co-locate tests as `*.test.ts(x)` or in `__tests__/`, matching the existing convention.
- Use React Native Testing Library or Testing Library queries by role/text, not implementation details.
- Reset mocks between tests; no shared mutable state across tests.
Docs: https://jestjs.io/docs/getting-started
# Cursor rules - this project
You are an expert Expo (React Native), TanStack Query, Zustand, Jest engineer working on this codebase. Follow these rules.
## Project
A Expo (React Native) + TanStack Query + Zustand + Jest project.
Stack: Expo (React Native), TanStack Query, Zustand, Jest.
## Commands
- Start dev server: `npx expo start`
- Add a native-compatible package: `npx expo install <package>`
- Check project health: `npx expo-doctor`
- Type-check: `npx tsc --noEmit`
- Unit tests: `npx jest`
## Project structure
- Screens are files in `app/` (Expo Router). Layouts are `_layout.tsx`.
- Reusable components in `components/`, hooks in `hooks/`.
## How to work in this repo
- Read the relevant files before editing. Follow the patterns already in the codebase over these generic rules.
- Make the smallest change that solves the task. Do not refactor or reformat unrelated code.
- Before saying a task is done, run the type-check, lint and tests listed under Commands and fix what you broke.
- If requirements are ambiguous, ask one clear question instead of guessing.
- Never commit secrets, API keys or `.env` files. Use env vars and keep `.env.example` up to date.
- Do not add a new dependency when the standard library or an existing dependency already covers it.
- Ask before adding, removing or upgrading any dependency.
- Ask before changing database schemas, auth, payments or CI configuration.
- Never delete files, drop data or run destructive commands (`rm -rf`, `git push --force`, `DROP TABLE`) without explicit approval.
- Keep each change under ~200 changed lines where possible; split larger work into steps.
## Expo (React Native)
- Install packages with `npx expo install` so versions match the Expo SDK.
- Use Expo Router for navigation (`<Link>`, `router.push`). Do not add React Navigation manually unless it is already in use.
- Use React Native primitives (`View`, `Text`, `Pressable`) only. No DOM elements.
- Use `FlatList` / `FlashList` for long lists, never `.map()` inside a `ScrollView`.
- Wrap screens in safe-area handling (`react-native-safe-area-context`).
- Env vars must start with `EXPO_PUBLIC_` to reach the app, so they are public. Keep secrets on a server.
- Store tokens with `expo-secure-store`, not AsyncStorage.
- Do not edit `ios/` or `android/` by hand when using Continuous Native Generation; use config plugins in `app.json` / `app.config.ts`.
## TanStack Query
- All server data goes through `useQuery` / `useMutation`; do not copy query results into `useState`.
- Use array query keys built by a small key factory (e.g. `todoKeys.detail(id)`).
- Invalidate or update affected queries in `onSuccess` of every mutation.
- Wrap queries in custom hooks (`useTodos()`) instead of calling `useQuery` inline everywhere.
## Zustand
- Keep stores small and split by domain.
- Select only what a component needs (`useStore((s) => s.count)`) to avoid unnecessary re-renders.
- Use Zustand for client/UI state only. Server data belongs in the data-fetching layer.
## Jest
- Co-locate tests as `*.test.ts(x)` or in `__tests__/`, matching the existing convention.
- Use React Native Testing Library or Testing Library queries by role/text, not implementation details.
- Reset mocks between tests; no shared mutable state across tests.
## Reference docs
- [Expo docs](https://docs.expo.dev)
- [TanStack Query docs](https://tanstack.com/query/latest)
- [Zustand docs](https://zustand.docs.pmnd.rs)
- [Jest docs](https://jestjs.io/docs/getting-started)
# Copilot instructions - this project
A Expo (React Native) + TanStack Query + Zustand + Jest project.
Stack: Expo (React Native), TanStack Query, Zustand, Jest.
## Commands
- Start dev server: `npx expo start`
- Add a native-compatible package: `npx expo install <package>`
- Check project health: `npx expo-doctor`
- Type-check: `npx tsc --noEmit`
- Unit tests: `npx jest`
## How to work in this repo
- Read the relevant files before editing. Follow the patterns already in the codebase over these generic rules.
- Make the smallest change that solves the task. Do not refactor or reformat unrelated code.
- Before saying a task is done, run the type-check, lint and tests listed under Commands and fix what you broke.
- If requirements are ambiguous, ask one clear question instead of guessing.
- Never commit secrets, API keys or `.env` files. Use env vars and keep `.env.example` up to date.
- Do not add a new dependency when the standard library or an existing dependency already covers it.
- Ask before adding, removing or upgrading any dependency.
- Ask before changing database schemas, auth, payments or CI configuration.
- Never delete files, drop data or run destructive commands (`rm -rf`, `git push --force`, `DROP TABLE`) without explicit approval.
- Keep each change under ~200 changed lines where possible; split larger work into steps.
---
applyTo: "app/**/*.tsx,src/**/*.tsx,src/**/*.ts,components/**/*.tsx"
---
# Expo (React Native)
- Install packages with `npx expo install` so versions match the Expo SDK.
- Use Expo Router for navigation (`<Link>`, `router.push`). Do not add React Navigation manually unless it is already in use.
- Use React Native primitives (`View`, `Text`, `Pressable`) only. No DOM elements.
- Use `FlatList` / `FlashList` for long lists, never `.map()` inside a `ScrollView`.
- Wrap screens in safe-area handling (`react-native-safe-area-context`).
- Env vars must start with `EXPO_PUBLIC_` to reach the app, so they are public. Keep secrets on a server.
- Store tokens with `expo-secure-store`, not AsyncStorage.
- Do not edit `ios/` or `android/` by hand when using Continuous Native Generation; use config plugins in `app.json` / `app.config.ts`.
---
applyTo: "**/*.tsx,**/hooks/**/*.ts"
---
# TanStack Query
- All server data goes through `useQuery` / `useMutation`; do not copy query results into `useState`.
- Use array query keys built by a small key factory (e.g. `todoKeys.detail(id)`).
- Invalidate or update affected queries in `onSuccess` of every mutation.
- Wrap queries in custom hooks (`useTodos()`) instead of calling `useQuery` inline everywhere.
---
applyTo: "**/store/**/*.ts,**/stores/**/*.ts"
---
# Zustand
- Keep stores small and split by domain.
- Select only what a component needs (`useStore((s) => s.count)`) to avoid unnecessary re-renders.
- Use Zustand for client/UI state only. Server data belongs in the data-fetching layer.
---
applyTo: "**/*.test.ts,**/*.test.tsx,**/__tests__/**"
---
# Jest
- Co-locate tests as `*.test.ts(x)` or in `__tests__/`, matching the existing convention.
- Use React Native Testing Library or Testing Library queries by role/text, not implementation details.
- Reset mocks between tests; no shared mutable state across tests.
---
trigger: always_on
---
# this project
A Expo (React Native) + TanStack Query + Zustand + Jest project.
Stack: Expo (React Native), TanStack Query, Zustand, Jest.
## Commands
- Start dev server: `npx expo start`
- Add a native-compatible package: `npx expo install <package>`
- Check project health: `npx expo-doctor`
- Type-check: `npx tsc --noEmit`
- Unit tests: `npx jest`
## How to work in this repo
- Read the relevant files before editing. Follow the patterns already in the codebase over these generic rules.
- Make the smallest change that solves the task. Do not refactor or reformat unrelated code.
- Before saying a task is done, run the type-check, lint and tests listed under Commands and fix what you broke.
- If requirements are ambiguous, ask one clear question instead of guessing.
- Never commit secrets, API keys or `.env` files. Use env vars and keep `.env.example` up to date.
- Do not add a new dependency when the standard library or an existing dependency already covers it.
- Ask before adding, removing or upgrading any dependency.
- Ask before changing database schemas, auth, payments or CI configuration.
- Never delete files, drop data or run destructive commands (`rm -rf`, `git push --force`, `DROP TABLE`) without explicit approval.
- Keep each change under ~200 changed lines where possible; split larger work into steps.
---
trigger: glob
globs: app/**/*.tsx, src/**/*.tsx, src/**/*.ts, components/**/*.tsx
---
# Expo (React Native)
- Install packages with `npx expo install` so versions match the Expo SDK.
- Use Expo Router for navigation (`<Link>`, `router.push`). Do not add React Navigation manually unless it is already in use.
- Use React Native primitives (`View`, `Text`, `Pressable`) only. No DOM elements.
- Use `FlatList` / `FlashList` for long lists, never `.map()` inside a `ScrollView`.
- Wrap screens in safe-area handling (`react-native-safe-area-context`).
- Env vars must start with `EXPO_PUBLIC_` to reach the app, so they are public. Keep secrets on a server.
- Store tokens with `expo-secure-store`, not AsyncStorage.
- Do not edit `ios/` or `android/` by hand when using Continuous Native Generation; use config plugins in `app.json` / `app.config.ts`.
---
trigger: glob
globs: **/*.tsx, **/hooks/**/*.ts
---
# TanStack Query
- All server data goes through `useQuery` / `useMutation`; do not copy query results into `useState`.
- Use array query keys built by a small key factory (e.g. `todoKeys.detail(id)`).
- Invalidate or update affected queries in `onSuccess` of every mutation.
- Wrap queries in custom hooks (`useTodos()`) instead of calling `useQuery` inline everywhere.
---
trigger: glob
globs: **/store/**/*.ts, **/stores/**/*.ts
---
# Zustand
- Keep stores small and split by domain.
- Select only what a component needs (`useStore((s) => s.count)`) to avoid unnecessary re-renders.
- Use Zustand for client/UI state only. Server data belongs in the data-fetching layer.
---
trigger: glob
globs: **/*.test.ts, **/*.test.tsx, **/__tests__/**
---
# Jest
- Co-locate tests as `*.test.ts(x)` or in `__tests__/`, matching the existing convention.
- Use React Native Testing Library or Testing Library queries by role/text, not implementation details.
- Reset mocks between tests; no shared mutable state across tests.
# GEMINI.md - this project
Project context for Gemini CLI.
## Project
A Expo (React Native) + TanStack Query + Zustand + Jest project.
Stack: Expo (React Native), TanStack Query, Zustand, Jest.
## Commands
- Start dev server: `npx expo start`
- Add a native-compatible package: `npx expo install <package>`
- Check project health: `npx expo-doctor`
- Type-check: `npx tsc --noEmit`
- Unit tests: `npx jest`
## Project structure
- Screens are files in `app/` (Expo Router). Layouts are `_layout.tsx`.
- Reusable components in `components/`, hooks in `hooks/`.
## How to work in this repo
- Read the relevant files before editing. Follow the patterns already in the codebase over these generic rules.
- Make the smallest change that solves the task. Do not refactor or reformat unrelated code.
- Before saying a task is done, run the type-check, lint and tests listed under Commands and fix what you broke.
- If requirements are ambiguous, ask one clear question instead of guessing.
- Never commit secrets, API keys or `.env` files. Use env vars and keep `.env.example` up to date.
- Do not add a new dependency when the standard library or an existing dependency already covers it.
- Ask before adding, removing or upgrading any dependency.
- Ask before changing database schemas, auth, payments or CI configuration.
- Never delete files, drop data or run destructive commands (`rm -rf`, `git push --force`, `DROP TABLE`) without explicit approval.
- Keep each change under ~200 changed lines where possible; split larger work into steps.
## Expo (React Native)
- Install packages with `npx expo install` so versions match the Expo SDK.
- Use Expo Router for navigation (`<Link>`, `router.push`). Do not add React Navigation manually unless it is already in use.
- Use React Native primitives (`View`, `Text`, `Pressable`) only. No DOM elements.
- Use `FlatList` / `FlashList` for long lists, never `.map()` inside a `ScrollView`.
- Wrap screens in safe-area handling (`react-native-safe-area-context`).
- Env vars must start with `EXPO_PUBLIC_` to reach the app, so they are public. Keep secrets on a server.
- Store tokens with `expo-secure-store`, not AsyncStorage.
- Do not edit `ios/` or `android/` by hand when using Continuous Native Generation; use config plugins in `app.json` / `app.config.ts`.
## TanStack Query
- All server data goes through `useQuery` / `useMutation`; do not copy query results into `useState`.
- Use array query keys built by a small key factory (e.g. `todoKeys.detail(id)`).
- Invalidate or update affected queries in `onSuccess` of every mutation.
- Wrap queries in custom hooks (`useTodos()`) instead of calling `useQuery` inline everywhere.
## Zustand
- Keep stores small and split by domain.
- Select only what a component needs (`useStore((s) => s.count)`) to avoid unnecessary re-renders.
- Use Zustand for client/UI state only. Server data belongs in the data-fetching layer.
## Jest
- Co-locate tests as `*.test.ts(x)` or in `__tests__/`, matching the existing convention.
- Use React Native Testing Library or Testing Library queries by role/text, not implementation details.
- Reset mocks between tests; no shared mutable state across tests.
## Reference docs
- [Expo docs](https://docs.expo.dev)
- [TanStack Query docs](https://tanstack.com/query/latest)
- [Zustand docs](https://zustand.docs.pmnd.rs)
- [Jest docs](https://jestjs.io/docs/getting-started)
Commands your agent should run
| Task | Command |
|---|---|
| Start dev server | npx expo start |
| Add a native-compatible package | npx expo install <package> |
| Check project health | npx expo-doctor |
| Type-check | npx tsc --noEmit |
| Unit tests | npx jest |
What the rules cover
Expo (React Native)
Expo + React Native app with Expo Router and TypeScript. Scoped to app/**/*.tsx, src/**/*.tsx, src/**/*.ts, components/**/*.tsx in Cursor, Copilot and Windsurf.
- Install packages with
npx expo installso versions match the Expo SDK. - Use Expo Router for navigation (
<Link>,router.push). Do not add React Navigation manually unless it is already in use. - Use React Native primitives (
View,Text,Pressable) only. No DOM elements. - Use
FlatList/FlashListfor long lists, never.map()inside aScrollView. - Wrap screens in safe-area handling (
react-native-safe-area-context). - Env vars must start with
EXPO_PUBLIC_to reach the app, so they are public. Keep secrets on a server. - Store tokens with
expo-secure-store, not AsyncStorage. - Do not edit
ios/orandroid/by hand when using Continuous Native Generation; use config plugins inapp.json/app.config.ts.
Source docs: Expo docs
TanStack Query
Server-state caching with TanStack Query. Scoped to **/*.tsx, **/hooks/**/*.ts in Cursor, Copilot and Windsurf.
- All server data goes through
useQuery/useMutation; do not copy query results intouseState. - Use array query keys built by a small key factory (e.g.
todoKeys.detail(id)). - Invalidate or update affected queries in
onSuccessof every mutation. - Wrap queries in custom hooks (
useTodos()) instead of callinguseQueryinline everywhere.
Source docs: TanStack Query docs
Zustand
Lightweight client state with Zustand. Scoped to **/store/**/*.ts, **/stores/**/*.ts in Cursor, Copilot and Windsurf.
- Keep stores small and split by domain.
- Select only what a component needs (
useStore((s) => s.count)) to avoid unnecessary re-renders. - Use Zustand for client/UI state only. Server data belongs in the data-fetching layer.
Source docs: Zustand docs
Jest
Unit tests with Jest. Scoped to **/*.test.ts, **/*.test.tsx, **/__tests__/** in Cursor, Copilot and Windsurf.
- Co-locate tests as
*.test.ts(x)or in__tests__/, matching the existing convention. - Use React Native Testing Library or Testing Library queries by role/text, not implementation details.
- Reset mocks between tests; no shared mutable state across tests.
Source docs: Jest docs
How to install
- Copy
AGENTS.mdto your repo root. That covers Codex, Cursor, GitHub Copilot and most other agents. - Using Claude Code? Add a
CLAUDE.mdwith the single line@AGENTS.md, or use the standalone CLAUDE.md tab above. - Want rules that only load for certain files in Cursor? Add the
.cursor/rules/*.mdcfiles. - Commit the files so your whole team (and every agent) shares them.
FAQ
Where do I put the AGENTS.md for Expo (React Native) + TanStack Query + Zustand + Jest?
Save it as AGENTS.md in the root of your repository, next to your main config file. Codex, Cursor and GitHub Copilot pick it up automatically. For Claude Code, add a CLAUDE.md containing @AGENTS.md (or use the standalone CLAUDE.md on this page).
What is the most common mistake AI agents make with Expo (React Native)?
Server data gets duplicated into Zustand and goes stale.
Which commands should the agent run to check its work?
For this stack: npx expo start, npx expo install <package>, npx expo-doctor, npx tsc --noEmit. They are listed in the generated files so the agent runs them before finishing a task.
Do these Expo (React Native) + TanStack Query + Zustand + Jest rules work with Cursor and Claude Code?
Yes. This page includes the same rules as AGENTS.md, CLAUDE.md, Cursor .mdc project rules, a legacy .cursorrules file, GitHub Copilot instructions, Windsurf rules and GEMINI.md.
Can I customise these rules?
Yes. Open this stack in the generator to add or remove libraries, set your project name and package manager, switch beginner explanations on, and download everything as a zip.
Related stacks
Expo (React Native) + Supabase + Zod validation + Jest
A mobile app with Expo Router and Supabase.
React + Vite + Tailwind CSS v4 + TanStack Query + Vitest + Zod validation
A classic single-page app: React + Vite with TanStack Query for server data.
React + Vite + Tailwind CSS v4 + Supabase + Zustand
A client-only React app talking straight to Supabase, popular for quick prototypes and internal tools.
Chrome Extension (MV3) + Tailwind CSS v4 + Zustand + Vitest
A Manifest V3 Chrome extension with a React popup.
Next.js (App Router) + Tailwind CSS v4 + shadcn/ui + Supabase + Zod validation
The default vibe-coding SaaS stack: Next.js App Router, Supabase for auth and Postgres, Tailwind and shadcn/ui for the interface.
Next.js (App Router) + Tailwind CSS v4
A plain Next.js + TypeScript + Tailwind v4 starter, the most common front-end setup in 2026.