React + Vite + TanStack + Tailwind rules for AI coding agents
Full stack: React + Vite + Tailwind CSS v4 + TanStack Query + Vitest + Zod validation
Ready-to-commit rules for React + Vite + Tailwind CSS v4 + TanStack Query + Vitest + Zod validation 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. A classic single-page app: React + Vite with TanStack Query for server data.
Last reviewed 2026-10-21 · Customise in the generator · Raw: AGENTS.md, CLAUDE.md
Agents copy query results into useState and forget to invalidate queries after mutations.
Generated files
# AGENTS.md - this project
Instructions for AI coding agents working in this repository.
## Project
A React + Vite + Tailwind CSS v4 + TanStack Query + Vitest + Zod validation project.
Stack: React + Vite, Tailwind CSS v4, TanStack Query, Vitest, Zod validation.
## Commands
- Dev server: `npm run dev`
- Build: `npm run build`
- Type-check: `npx tsc --noEmit`
- Lint: `npm run lint`
- Unit tests: `npx vitest run`
## Project structure
- Features live in `src/features/<name>/` with their components, hooks and tests together.
- Shared UI in `src/components/`, hooks in `src/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.
## React + Vite
- Function components and hooks only. No class components.
- Follow the Rules of Hooks: call hooks at the top level, never inside conditions or loops.
- Derive values during render instead of syncing them into state with `useEffect`.
- Every list item needs a stable `key` from the data, never the array index if the list can change order.
- Type component props with an exported `Props` type or interface. No `any`.
- Env vars must start with `VITE_` to reach the client, which also means they are public. Never put secrets in them.
- Lazy-load heavy routes with `React.lazy` and `Suspense`.
## Tailwind CSS v4
- Tailwind v4 is configured in CSS: `@import "tailwindcss";` plus `@theme { ... }` for design tokens. Do not create a `tailwind.config.js` unless the project already has one.
- Use theme tokens (colors, spacing) instead of arbitrary values like `w-[37px]`.
- Build responsive layouts mobile-first with `sm:`, `md:`, `lg:` prefixes.
- Extract repeated class lists into components, not `@apply` chains.
- Support dark mode with the `dark:` variant when the project uses it.
## 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.
## Vitest
- Co-locate tests next to the code as `*.test.ts(x)`.
- Test behaviour through public APIs; for components use Testing Library queries by role/label.
- Mock network calls at the boundary (e.g. MSW) rather than mocking internal modules.
- Every bug fix adds a test that fails without the fix.
## Zod validation
- Validate all untrusted input (request bodies, form data, env vars, third-party API responses) with a Zod schema at the boundary.
- Derive TypeScript types from schemas with `z.infer<typeof schema>`; do not hand-write duplicate types.
- Use `safeParse` where you need to return validation errors to the user.
## Avoid
- Do not reach for global state for data that only one component tree uses.
## Reference docs
- [React docs](https://react.dev)
- [Vite docs](https://vite.dev/guide/)
- [Tailwind CSS docs](https://tailwindcss.com/docs)
- [TanStack Query docs](https://tanstack.com/query/latest)
- [Vitest docs](https://vitest.dev)
- [Zod docs](https://zod.dev)
# CLAUDE.md - this project
Project instructions for Claude Code.
## Project
A React + Vite + Tailwind CSS v4 + TanStack Query + Vitest + Zod validation project.
Stack: React + Vite, Tailwind CSS v4, TanStack Query, Vitest, Zod validation.
## Commands
- Dev server: `npm run dev`
- Build: `npm run build`
- Type-check: `npx tsc --noEmit`
- Lint: `npm run lint`
- Unit tests: `npx vitest run`
## Project structure
- Features live in `src/features/<name>/` with their components, hooks and tests together.
- Shared UI in `src/components/`, hooks in `src/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.
## React + Vite
- Function components and hooks only. No class components.
- Follow the Rules of Hooks: call hooks at the top level, never inside conditions or loops.
- Derive values during render instead of syncing them into state with `useEffect`.
- Every list item needs a stable `key` from the data, never the array index if the list can change order.
- Type component props with an exported `Props` type or interface. No `any`.
- Env vars must start with `VITE_` to reach the client, which also means they are public. Never put secrets in them.
- Lazy-load heavy routes with `React.lazy` and `Suspense`.
## Tailwind CSS v4
- Tailwind v4 is configured in CSS: `@import "tailwindcss";` plus `@theme { ... }` for design tokens. Do not create a `tailwind.config.js` unless the project already has one.
- Use theme tokens (colors, spacing) instead of arbitrary values like `w-[37px]`.
- Build responsive layouts mobile-first with `sm:`, `md:`, `lg:` prefixes.
- Extract repeated class lists into components, not `@apply` chains.
- Support dark mode with the `dark:` variant when the project uses it.
## 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.
## Vitest
- Co-locate tests next to the code as `*.test.ts(x)`.
- Test behaviour through public APIs; for components use Testing Library queries by role/label.
- Mock network calls at the boundary (e.g. MSW) rather than mocking internal modules.
- Every bug fix adds a test that fails without the fix.
## Zod validation
- Validate all untrusted input (request bodies, form data, env vars, third-party API responses) with a Zod schema at the boundary.
- Derive TypeScript types from schemas with `z.infer<typeof schema>`; do not hand-write duplicate types.
- Use `safeParse` where you need to return validation errors to the user.
## Avoid
- Do not reach for global state for data that only one component tree uses.
## Reference docs
- [React docs](https://react.dev)
- [Vite docs](https://vite.dev/guide/)
- [Tailwind CSS docs](https://tailwindcss.com/docs)
- [TanStack Query docs](https://tanstack.com/query/latest)
- [Vitest docs](https://vitest.dev)
- [Zod docs](https://zod.dev)
---
description: "Core rules for this project"
alwaysApply: true
---
# this project
A React + Vite + Tailwind CSS v4 + TanStack Query + Vitest + Zod validation project.
Stack: React + Vite, Tailwind CSS v4, TanStack Query, Vitest, Zod validation.
## Commands
- Dev server: `npm run dev`
- Build: `npm run build`
- Type-check: `npx tsc --noEmit`
- Lint: `npm run lint`
- Unit tests: `npx vitest run`
## 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: "React + Vite conventions: Single-page React app built with Vite and TypeScript."
globs: src/**/*.tsx, src/**/*.ts
alwaysApply: false
---
# React + Vite
- Function components and hooks only. No class components.
- Follow the Rules of Hooks: call hooks at the top level, never inside conditions or loops.
- Derive values during render instead of syncing them into state with `useEffect`.
- Every list item needs a stable `key` from the data, never the array index if the list can change order.
- Type component props with an exported `Props` type or interface. No `any`.
- Env vars must start with `VITE_` to reach the client, which also means they are public. Never put secrets in them.
- Lazy-load heavy routes with `React.lazy` and `Suspense`.
## Avoid
- Do not reach for global state for data that only one component tree uses.
Docs: https://react.dev, https://vite.dev/guide/
---
description: "Tailwind CSS v4 conventions: Utility-first styling with Tailwind CSS v4."
globs: **/*.css, **/*.tsx, **/*.vue, **/*.svelte, **/*.astro, **/*.html, **/*.blade.php, **/*.erb
alwaysApply: false
---
# Tailwind CSS v4
- Tailwind v4 is configured in CSS: `@import "tailwindcss";` plus `@theme { ... }` for design tokens. Do not create a `tailwind.config.js` unless the project already has one.
- Use theme tokens (colors, spacing) instead of arbitrary values like `w-[37px]`.
- Build responsive layouts mobile-first with `sm:`, `md:`, `lg:` prefixes.
- Extract repeated class lists into components, not `@apply` chains.
- Support dark mode with the `dark:` variant when the project uses it.
Docs: https://tailwindcss.com/docs
---
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: "Vitest conventions: Unit and component tests with Vitest."
globs: **/*.test.ts, **/*.test.tsx, **/*.spec.ts
alwaysApply: false
---
# Vitest
- Co-locate tests next to the code as `*.test.ts(x)`.
- Test behaviour through public APIs; for components use Testing Library queries by role/label.
- Mock network calls at the boundary (e.g. MSW) rather than mocking internal modules.
- Every bug fix adds a test that fails without the fix.
Docs: https://vitest.dev
---
description: "Zod validation conventions: Runtime schema validation with Zod."
globs: **/*.ts, **/*.tsx
alwaysApply: false
---
# Zod validation
- Validate all untrusted input (request bodies, form data, env vars, third-party API responses) with a Zod schema at the boundary.
- Derive TypeScript types from schemas with `z.infer<typeof schema>`; do not hand-write duplicate types.
- Use `safeParse` where you need to return validation errors to the user.
Docs: https://zod.dev
# Cursor rules - this project
You are an expert React + Vite, Tailwind CSS v4, TanStack Query, Vitest, Zod validation engineer working on this codebase. Follow these rules.
## Project
A React + Vite + Tailwind CSS v4 + TanStack Query + Vitest + Zod validation project.
Stack: React + Vite, Tailwind CSS v4, TanStack Query, Vitest, Zod validation.
## Commands
- Dev server: `npm run dev`
- Build: `npm run build`
- Type-check: `npx tsc --noEmit`
- Lint: `npm run lint`
- Unit tests: `npx vitest run`
## Project structure
- Features live in `src/features/<name>/` with their components, hooks and tests together.
- Shared UI in `src/components/`, hooks in `src/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.
## React + Vite
- Function components and hooks only. No class components.
- Follow the Rules of Hooks: call hooks at the top level, never inside conditions or loops.
- Derive values during render instead of syncing them into state with `useEffect`.
- Every list item needs a stable `key` from the data, never the array index if the list can change order.
- Type component props with an exported `Props` type or interface. No `any`.
- Env vars must start with `VITE_` to reach the client, which also means they are public. Never put secrets in them.
- Lazy-load heavy routes with `React.lazy` and `Suspense`.
## Tailwind CSS v4
- Tailwind v4 is configured in CSS: `@import "tailwindcss";` plus `@theme { ... }` for design tokens. Do not create a `tailwind.config.js` unless the project already has one.
- Use theme tokens (colors, spacing) instead of arbitrary values like `w-[37px]`.
- Build responsive layouts mobile-first with `sm:`, `md:`, `lg:` prefixes.
- Extract repeated class lists into components, not `@apply` chains.
- Support dark mode with the `dark:` variant when the project uses it.
## 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.
## Vitest
- Co-locate tests next to the code as `*.test.ts(x)`.
- Test behaviour through public APIs; for components use Testing Library queries by role/label.
- Mock network calls at the boundary (e.g. MSW) rather than mocking internal modules.
- Every bug fix adds a test that fails without the fix.
## Zod validation
- Validate all untrusted input (request bodies, form data, env vars, third-party API responses) with a Zod schema at the boundary.
- Derive TypeScript types from schemas with `z.infer<typeof schema>`; do not hand-write duplicate types.
- Use `safeParse` where you need to return validation errors to the user.
## Avoid
- Do not reach for global state for data that only one component tree uses.
## Reference docs
- [React docs](https://react.dev)
- [Vite docs](https://vite.dev/guide/)
- [Tailwind CSS docs](https://tailwindcss.com/docs)
- [TanStack Query docs](https://tanstack.com/query/latest)
- [Vitest docs](https://vitest.dev)
- [Zod docs](https://zod.dev)
# Copilot instructions - this project
A React + Vite + Tailwind CSS v4 + TanStack Query + Vitest + Zod validation project.
Stack: React + Vite, Tailwind CSS v4, TanStack Query, Vitest, Zod validation.
## Commands
- Dev server: `npm run dev`
- Build: `npm run build`
- Type-check: `npx tsc --noEmit`
- Lint: `npm run lint`
- Unit tests: `npx vitest run`
## 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: "src/**/*.tsx,src/**/*.ts"
---
# React + Vite
- Function components and hooks only. No class components.
- Follow the Rules of Hooks: call hooks at the top level, never inside conditions or loops.
- Derive values during render instead of syncing them into state with `useEffect`.
- Every list item needs a stable `key` from the data, never the array index if the list can change order.
- Type component props with an exported `Props` type or interface. No `any`.
- Env vars must start with `VITE_` to reach the client, which also means they are public. Never put secrets in them.
- Lazy-load heavy routes with `React.lazy` and `Suspense`.
---
applyTo: "**/*.css,**/*.tsx,**/*.vue,**/*.svelte,**/*.astro,**/*.html,**/*.blade.php,**/*.erb"
---
# Tailwind CSS v4
- Tailwind v4 is configured in CSS: `@import "tailwindcss";` plus `@theme { ... }` for design tokens. Do not create a `tailwind.config.js` unless the project already has one.
- Use theme tokens (colors, spacing) instead of arbitrary values like `w-[37px]`.
- Build responsive layouts mobile-first with `sm:`, `md:`, `lg:` prefixes.
- Extract repeated class lists into components, not `@apply` chains.
- Support dark mode with the `dark:` variant when the project uses it.
---
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: "**/*.test.ts,**/*.test.tsx,**/*.spec.ts"
---
# Vitest
- Co-locate tests next to the code as `*.test.ts(x)`.
- Test behaviour through public APIs; for components use Testing Library queries by role/label.
- Mock network calls at the boundary (e.g. MSW) rather than mocking internal modules.
- Every bug fix adds a test that fails without the fix.
---
applyTo: "**/*.ts,**/*.tsx"
---
# Zod validation
- Validate all untrusted input (request bodies, form data, env vars, third-party API responses) with a Zod schema at the boundary.
- Derive TypeScript types from schemas with `z.infer<typeof schema>`; do not hand-write duplicate types.
- Use `safeParse` where you need to return validation errors to the user.
---
trigger: always_on
---
# this project
A React + Vite + Tailwind CSS v4 + TanStack Query + Vitest + Zod validation project.
Stack: React + Vite, Tailwind CSS v4, TanStack Query, Vitest, Zod validation.
## Commands
- Dev server: `npm run dev`
- Build: `npm run build`
- Type-check: `npx tsc --noEmit`
- Lint: `npm run lint`
- Unit tests: `npx vitest run`
## 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: src/**/*.tsx, src/**/*.ts
---
# React + Vite
- Function components and hooks only. No class components.
- Follow the Rules of Hooks: call hooks at the top level, never inside conditions or loops.
- Derive values during render instead of syncing them into state with `useEffect`.
- Every list item needs a stable `key` from the data, never the array index if the list can change order.
- Type component props with an exported `Props` type or interface. No `any`.
- Env vars must start with `VITE_` to reach the client, which also means they are public. Never put secrets in them.
- Lazy-load heavy routes with `React.lazy` and `Suspense`.
---
trigger: glob
globs: **/*.css, **/*.tsx, **/*.vue, **/*.svelte, **/*.astro, **/*.html, **/*.blade.php, **/*.erb
---
# Tailwind CSS v4
- Tailwind v4 is configured in CSS: `@import "tailwindcss";` plus `@theme { ... }` for design tokens. Do not create a `tailwind.config.js` unless the project already has one.
- Use theme tokens (colors, spacing) instead of arbitrary values like `w-[37px]`.
- Build responsive layouts mobile-first with `sm:`, `md:`, `lg:` prefixes.
- Extract repeated class lists into components, not `@apply` chains.
- Support dark mode with the `dark:` variant when the project uses it.
---
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: **/*.test.ts, **/*.test.tsx, **/*.spec.ts
---
# Vitest
- Co-locate tests next to the code as `*.test.ts(x)`.
- Test behaviour through public APIs; for components use Testing Library queries by role/label.
- Mock network calls at the boundary (e.g. MSW) rather than mocking internal modules.
- Every bug fix adds a test that fails without the fix.
---
trigger: glob
globs: **/*.ts, **/*.tsx
---
# Zod validation
- Validate all untrusted input (request bodies, form data, env vars, third-party API responses) with a Zod schema at the boundary.
- Derive TypeScript types from schemas with `z.infer<typeof schema>`; do not hand-write duplicate types.
- Use `safeParse` where you need to return validation errors to the user.
# GEMINI.md - this project
Project context for Gemini CLI.
## Project
A React + Vite + Tailwind CSS v4 + TanStack Query + Vitest + Zod validation project.
Stack: React + Vite, Tailwind CSS v4, TanStack Query, Vitest, Zod validation.
## Commands
- Dev server: `npm run dev`
- Build: `npm run build`
- Type-check: `npx tsc --noEmit`
- Lint: `npm run lint`
- Unit tests: `npx vitest run`
## Project structure
- Features live in `src/features/<name>/` with their components, hooks and tests together.
- Shared UI in `src/components/`, hooks in `src/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.
## React + Vite
- Function components and hooks only. No class components.
- Follow the Rules of Hooks: call hooks at the top level, never inside conditions or loops.
- Derive values during render instead of syncing them into state with `useEffect`.
- Every list item needs a stable `key` from the data, never the array index if the list can change order.
- Type component props with an exported `Props` type or interface. No `any`.
- Env vars must start with `VITE_` to reach the client, which also means they are public. Never put secrets in them.
- Lazy-load heavy routes with `React.lazy` and `Suspense`.
## Tailwind CSS v4
- Tailwind v4 is configured in CSS: `@import "tailwindcss";` plus `@theme { ... }` for design tokens. Do not create a `tailwind.config.js` unless the project already has one.
- Use theme tokens (colors, spacing) instead of arbitrary values like `w-[37px]`.
- Build responsive layouts mobile-first with `sm:`, `md:`, `lg:` prefixes.
- Extract repeated class lists into components, not `@apply` chains.
- Support dark mode with the `dark:` variant when the project uses it.
## 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.
## Vitest
- Co-locate tests next to the code as `*.test.ts(x)`.
- Test behaviour through public APIs; for components use Testing Library queries by role/label.
- Mock network calls at the boundary (e.g. MSW) rather than mocking internal modules.
- Every bug fix adds a test that fails without the fix.
## Zod validation
- Validate all untrusted input (request bodies, form data, env vars, third-party API responses) with a Zod schema at the boundary.
- Derive TypeScript types from schemas with `z.infer<typeof schema>`; do not hand-write duplicate types.
- Use `safeParse` where you need to return validation errors to the user.
## Avoid
- Do not reach for global state for data that only one component tree uses.
## Reference docs
- [React docs](https://react.dev)
- [Vite docs](https://vite.dev/guide/)
- [Tailwind CSS docs](https://tailwindcss.com/docs)
- [TanStack Query docs](https://tanstack.com/query/latest)
- [Vitest docs](https://vitest.dev)
- [Zod docs](https://zod.dev)
Commands your agent should run
| Task | Command |
|---|---|
| Dev server | npm run dev |
| Build | npm run build |
| Type-check | npx tsc --noEmit |
| Lint | npm run lint |
| Unit tests | npx vitest run |
What the rules cover
React + Vite
Single-page React app built with Vite and TypeScript. Scoped to src/**/*.tsx, src/**/*.ts in Cursor, Copilot and Windsurf.
- Function components and hooks only. No class components.
- Follow the Rules of Hooks: call hooks at the top level, never inside conditions or loops.
- Derive values during render instead of syncing them into state with
useEffect. - Every list item needs a stable
keyfrom the data, never the array index if the list can change order. - Type component props with an exported
Propstype or interface. Noany. - Env vars must start with
VITE_to reach the client, which also means they are public. Never put secrets in them. - Lazy-load heavy routes with
React.lazyandSuspense.
Source docs: React docs, Vite docs
Tailwind CSS v4
Utility-first styling with Tailwind CSS v4. Scoped to **/*.css, **/*.tsx, **/*.vue, **/*.svelte, **/*.astro, **/*.html, **/*.blade.php, **/*.erb in Cursor, Copilot and Windsurf.
- Tailwind v4 is configured in CSS:
@import "tailwindcss";plus@theme { ... }for design tokens. Do not create atailwind.config.jsunless the project already has one. - Use theme tokens (colors, spacing) instead of arbitrary values like
w-[37px]. - Build responsive layouts mobile-first with
sm:,md:,lg:prefixes. - Extract repeated class lists into components, not
@applychains. - Support dark mode with the
dark:variant when the project uses it.
Source docs: Tailwind CSS 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
Vitest
Unit and component tests with Vitest. Scoped to **/*.test.ts, **/*.test.tsx, **/*.spec.ts in Cursor, Copilot and Windsurf.
- Co-locate tests next to the code as
*.test.ts(x). - Test behaviour through public APIs; for components use Testing Library queries by role/label.
- Mock network calls at the boundary (e.g. MSW) rather than mocking internal modules.
- Every bug fix adds a test that fails without the fix.
Source docs: Vitest docs
Zod validation
Runtime schema validation with Zod. Scoped to **/*.ts, **/*.tsx in Cursor, Copilot and Windsurf.
- Validate all untrusted input (request bodies, form data, env vars, third-party API responses) with a Zod schema at the boundary.
- Derive TypeScript types from schemas with
z.infer<typeof schema>; do not hand-write duplicate types. - Use
safeParsewhere you need to return validation errors to the user.
Source docs: Zod 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 React + Vite + Tailwind CSS v4 + TanStack Query + Vitest + Zod validation?
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 React + Vite?
Agents copy query results into useState and forget to invalidate queries after mutations.
Which commands should the agent run to check its work?
For this stack: npm run dev, npm run build, npx tsc --noEmit, npm run lint. They are listed in the generated files so the agent runs them before finishing a task.
Do these React + Vite + Tailwind CSS v4 + TanStack Query + Vitest + Zod validation 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
React + Vite + Tailwind CSS v4 + Firebase + Vitest
A React SPA on Firebase Auth and Firestore.
React + Vite + Tailwind CSS v4 + Supabase + Zustand
A client-only React app talking straight to Supabase, popular for quick prototypes and internal tools.
Next.js (App Router) + Tailwind CSS v4 + Supabase + Stripe payments + Zod validation + Vitest
The full indie-hacker SaaS kit: auth, database, payments and tests.
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 + Prisma + Stripe payments + Zod validation
A paid SaaS on Next.js with Prisma and Stripe subscriptions.
Next.js (App Router) + Tailwind CSS v4 + Drizzle ORM + Clerk auth + Zod validation
Next.js with Clerk for auth and Drizzle ORM on Postgres: fast to build, type-safe end to end.