Expo Web To Native
expo/skills
Migrate an existing web React app to a native iOS/Android app with Expo.
A skill your agent uses when building or reviewing a client-side React SPA bundled by Vite (React 19.2): components, where state lives, hooks, server data fetching, client routing, re-render and…
$ npx skills add ericrisco/rsc-harness --skill react -a claude-codeProject install by default; add -g for ~/.claude/skills/.
$ gh skill install ericrisco/rsc-harness react --agent claude-codeProject scope by default; add --scope user for a personal install. Needs GitHub CLI 2.90.0 or later (public preview).
$ git clone --depth 1 https://github.com/ericrisco/rsc-harness.git skills-src && mkdir -p .claude/skills && cp -r skills-src/skills/react .claude/skills/react && rm -rf skills-srcUse ~/.claude/skills/ instead of .claude/skills for a personal install. The folder must contain SKILL.md.
Claude Code skills documentation · loads skills from .claude/skills/
Install the "react" agent skill from https://github.com/ericrisco/rsc-harness/tree/main/skills/react into .claude/skills/react/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "react", then confirm the skill loads.Claude Code copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$skill-installer install https://github.com/ericrisco/rsc-harness/tree/main/skills/reactType this inside Codex. $skill-installer <name> installs a curated skill from openai/skills. The installer writes to $CODEX_HOME/skills (default ~/.codex/skills). Restart Codex if the skill does not show up.
$ npx skills add ericrisco/rsc-harness --skill react -a codexProject install goes to .agents/skills/; add -g for ~/.codex/skills/.
$ gh skill install ericrisco/rsc-harness react --agent codexProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ericrisco/rsc-harness.git skills-src && mkdir -p .agents/skills && cp -r skills-src/skills/react .agents/skills/react && rm -rf skills-srcUse ~/.agents/skills/ instead of .agents/skills for a personal install.
Codex skills documentation · loads skills from .agents/skills/
Install the "react" agent skill from https://github.com/ericrisco/rsc-harness/tree/main/skills/react into .agents/skills/react/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "react", then confirm the skill loads.Codex copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add ericrisco/rsc-harness --skill react -a cursorProject install goes to .agents/skills/; add -g for ~/.cursor/skills/.
$ gh skill install ericrisco/rsc-harness react --agent cursorProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ericrisco/rsc-harness.git skills-src && mkdir -p .cursor/skills && cp -r skills-src/skills/react .cursor/skills/react && rm -rf skills-srcUse ~/.cursor/skills/ instead of .cursor/skills for a personal install.
Cursor skills documentation · loads skills from .cursor/skills/, .agents/skills/, .claude/skills/, .codex/skills/
Install the "react" agent skill from https://github.com/ericrisco/rsc-harness/tree/main/skills/react into .cursor/skills/react/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "react", then confirm the skill loads.Cursor copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gemini skills install https://github.com/ericrisco/rsc-harness.git --path skills/react--scope user (default) or --scope workspace; --path is the subfolder of the repo that holds the skill; --consent skips the security confirmation prompt.
$ npx skills add ericrisco/rsc-harness --skill react -a gemini-cliProject install goes to .agents/skills/; add -g for ~/.gemini/skills/.
$ gh skill install ericrisco/rsc-harness react --agent gemini-cliProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ericrisco/rsc-harness.git skills-src && mkdir -p .gemini/skills && cp -r skills-src/skills/react .gemini/skills/react && rm -rf skills-srcUse ~/.gemini/skills/ instead of .gemini/skills for a personal install, then run /skills reload.
Gemini CLI skills documentation · loads skills from .gemini/skills/, .agents/skills/
Install the "react" agent skill from https://github.com/ericrisco/rsc-harness/tree/main/skills/react into .gemini/skills/react/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "react", then confirm the skill loads.Gemini CLI copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ gh skill install ericrisco/rsc-harness reactInstalls for Copilot at project scope by default; add --scope user for a personal install. Preview a skill first with gh skill preview. Needs GitHub CLI 2.90.0 or later (public preview).
$ npx skills add ericrisco/rsc-harness --skill react -a github-copilotProject install goes to .agents/skills/; add -g for ~/.copilot/skills/.
$ git clone --depth 1 https://github.com/ericrisco/rsc-harness.git skills-src && mkdir -p .github/skills && cp -r skills-src/skills/react .github/skills/react && rm -rf skills-srcUse ~/.copilot/skills/ instead of .github/skills for a personal install. Commit .github/skills so cloud agent and code review can use it.
GitHub Copilot skills documentation · loads skills from .github/skills/, .claude/skills/, .agents/skills/
Install the "react" agent skill from https://github.com/ericrisco/rsc-harness/tree/main/skills/react into .github/skills/react/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "react", then confirm the skill loads.GitHub Copilot copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
$ npx skills add ericrisco/rsc-harness --skill react -a opencodeOpenCode documents no install command of its own. Project install goes to .agents/skills/; add -g for ~/.config/opencode/skills/.
$ gh skill install ericrisco/rsc-harness react --agent opencodeProject scope by default (.agents/skills/); add --scope user for a personal install.
$ git clone --depth 1 https://github.com/ericrisco/rsc-harness.git skills-src && mkdir -p .opencode/skills && cp -r skills-src/skills/react .opencode/skills/react && rm -rf skills-srcUse ~/.config/opencode/skills/ instead of .opencode/skills for a personal install.
OpenCode skills documentation · loads skills from .opencode/skills/, .claude/skills/, .agents/skills/
Install the "react" agent skill from https://github.com/ericrisco/rsc-harness/tree/main/skills/react into .opencode/skills/react/ in this project. Copy the whole folder (SKILL.md and every file beside it), keep the folder name "react", then confirm the skill loads.OpenCode copies the folder itself, the same result as the manual copy. Check what it changed before you commit it.
reactA skill your agent uses when building or reviewing a client-side React SPA bundled by Vite (React 19.2): components, where state lives, hooks, server data fetching, client routing, re-render and…
React is an agent skill from ericrisco/rsc-harness. Use when building or reviewing a client-side React SPA bundled by Vite (React 19.2): components, where state lives, hooks, server data fetching, client routing, re-render and effect bugs. NOT App Router / server components / SSR (that is nextjs); NOT native screens (that is react-native).
Its SKILL.md is about 3.2k tokens, which your agent loads only when the skill is triggered. The skill folder holds 9 other files, including scripts and reference files (for example `evals/README.md`, `evals/cases.yaml` and `references/data-and-state.md`).
It sits in Mobile, covering Cross-platform mobile apps. It works with React, Vite, Next.js and React Native. The repository describes itself as: Your agent invents things because it has no memory, and can't touch your database because it has no arms. rsc is the meta-harness that gives it both, plus the trade to know the… The licence is MIT.
Read from SKILL.md and the folder at commit 92fde8f. It shows what the files ask for, not the result of running them.
Pre-approves nothing: there is no allowed-tools line, so your agent's usual permission prompts apply.
From allowed-tools in the SKILL.md frontmatter.
Ships 1 file in scripts/ (Shell), which the agent can run.
Shell commands in SKILL.md call:
tscFrom the folder's file list and the shell code blocks in SKILL.md.
No URLs in SKILL.md.
From URLs in SKILL.md, links to its own repository left out.
Names these keys or tokens, usually read from environment variables:
VITE_API_SECRETFrom names ending in _API_KEY, _TOKEN, _SECRET, _KEY or _PASSWORD in SKILL.md.
React loads about 3.2k tokens when it runs, and up to ~6.2k if it reads all its reference files. Until then it costs about 75 tokens; SKILL.md has 1,199 words of instructions outside code blocks.
Estimates: characters ÷ 4, the usual rule of thumb; real counts depend on the model's tokenizer. Scripts and assets cost tokens only if the agent reads them.
The automated check found no risky patterns in SKILL.md.
Automated static check — not a guarantee. Review scripts before installing. It scans the text of SKILL.md for risky patterns (piping downloads into a shell, reading credential files, hidden Unicode, destructive commands); the scripts in this folder are not scanned.
The full file from ericrisco/rsc-harness at commit 92fde8f, republished under its MIT licence (© ericrisco). 1,199 words, ~3,207 tokens.
.claude/skills/react/SKILL.md (or your agent's skills folder). This skill also uses 6 other files; get the full folder from GitHub.Hand-off — picking dependencies. Which library to reach for (UI primitives, command menus,
toasts, OTP inputs, charts, virtualization, drag and drop, state, styling, theming) is
../ui-engineering/SKILL.md's — build vs adopt is decided there, before hand-rolling a component. Animating what you
install is ../motion-craft/SKILL.md's.
Build or review a fast, typed, correctly-architected client-side React single-page app bundled by Vite. No server runtime, no RSC tree, no framework router. Server-rendered React (App Router, server actions, SSR/SSG) is not this skill — that is
../nextjs/SKILL.md.
SDD gate — before writing feature code. If this skill fired on a new, non-trivial feature or behaviour change and there is no approved spec + plan under 02-DOCS/wiki/sdd/, stop and hand off to ../specify/SKILL.md: it runs brainstorm → spec → plan → tasks, then routes back here once the plan is approved. Build directly only for a genuinely one-line / low-risk change. Method: ../sdd/SKILL.md.
Read package.json before giving any advice — it stops you applying SSR/RSC patterns to a client SPA.
| Signal in package.json | Read it as | Where |
|---|---|---|
vite + react, no next | Vite SPA | here |
next | metaframework / RSC | ../nextjs/SKILL.md |
@react-router/dev | RR framework mode/SSR (Remix successor) | ../nextjs/SKILL.md-shape |
react-router only | RR library mode | here (Routing) |
expo / react-native | native | ../react-native/SKILL.md |
Then pick the data layer (TanStack Query, always) and the router (React Router v7 library mode or TanStack Router).
Adjacent jobs route out: the type system itself (generics, discriminated unions, tsconfig theory) with no React shape → ../typescript/SKILL.md; visual design, tokens, spacing, button states → ../design/SKILL.md; writing the Vitest/RTL or E2E suite as the task → ../testing-web/SKILL.md; hosting the built dist/ → ../deployment/SKILL.md.
useState synced by an effect.| Where does this state live? | Trigger |
|---|---|
Local useState/useReducer | only one component cares |
| Lifted to nearest common parent | a few siblings share it |
| URL search params | it should be shareable / bookmarkable / survive reload |
| Context | wide read, low write frequency (theme, auth user) |
| External store (Zustand) + selectors | wide read, high write frequency, or deep prop-drilling |
| TanStack Query cache | it's server data (anything fetched) |
// Bad: syncing a derived value into state with an effect → stale + extra render
const [fullName, setFullName] = useState("");
useEffect(() => { setFullName(`${first} ${last}`); }, [first, last]);
// Good: derive in render
const fullName = `${first} ${last}`;useState for one or two independent values; useReducer when the next state depends on the previous one or several fields move together.useEffect rule: effects exist to synchronize with a non-React external system (a subscription, a DOM node, a non-React widget). They are not for transforming data and not for fetching server data. If you can compute it in render or in an event handler, do that instead.useEffectEvent (stable in 19.2): extract the non-reactive part of an effect so it reads the latest props/state without being a dependency. Fixes the stale-closure / over-firing class of effect bug.// Effect re-subscribes only when roomId changes, but still logs the latest theme.
const onConnected = useEffectEvent(() => log("connected", theme));
useEffect(() => {
const c = connect(roomId);
c.on("open", onConnected);
return () => c.close();
}, [roomId]); // theme is NOT a dependencyuse(promise) reads a promise during render under <Suspense> + an error boundary. The promise must come from a cache (TanStack Query, a stable module cache) — never created inline, or you make a new promise every render and suspend forever.// Bad: new promise each render → infinite suspense loop
function Profile({ id }: { id: string }) {
const user = use(fetch(`/api/users/${id}`).then(r => r.json())); // ❌
}
// Good: the promise is owned by a cache (useSuspenseQuery, below)useTransition / useDeferredValue keep the UI responsive: mark a slow state update non-urgent so typing/clicks stay live.ref is a plain prop in React 19 — no forwardRef. The provider is <Context value={...}> (no .Provider). Refs may return a cleanup function.Fetching server data in useEffect gives you waterfalls, race conditions, no caching, no dedupe, and double-fires under Strict Mode. Use TanStack Query v5 for all server state.
// Bad: the effect-as-fetch anti-pattern — races, no cache, refetches on every mount
const [user, setUser] = useState<User | null>(null);
useEffect(() => {
fetch(`/api/users/${id}`).then(r => r.json()).then(setUser); // ❌ stale id, race, no error/loading
}, [id]);
// Good
const { data: user, isPending, isError } = useQuery({
queryKey: ["user", id], // identity + cache key + dedupe
queryFn: () => getUser(id), // typed fetcher
staleTime: 60_000, // 1 min "fresh" → no needless refetch
});const qc = useQueryClient();
const remove = useMutation({
mutationFn: deleteUser,
onSuccess: () => qc.invalidateQueries({ queryKey: ["users"] }),
});useSuspenseQuery + <Suspense fallback> + an error boundary moves loading/error out of the component body and is the correct source for use()-style reads.onMutate snapshots + writes the expected state, onError rolls back, onSettled invalidates.invalidateQueries vs setQueryData, infinite queries, prefetch, Zustand store + selectors, the full Bad→Good set → references/data-and-state.md.React Router v7 — library mode is the default SPA router:
const router = createBrowserRouter([
{ path: "/", element: <Layout />, children: [
{ index: true, element: <Home /> },
{ path: "users/:id", lazy: () => import("./routes/user") }, // code-split route
]},
]);
// <RouterProvider router={router} />@react-router/dev framework mode is SSR → treat like nextjs, out of scope.useSearchParams-as-state → references/routing.md.Measure first with the React DevTools Profiler — guessing wastes effort. Then:
key: a stable id, never the array index when the list can reorder/insert/delete (index keys leak state and update the wrong row — see anti-patterns).@tanstack/react-virtual.lazy() + <Suspense>; Vite splits automatically on dynamic import().useMemo/useCallback/React.memo — it auto-memoizes; leaving them in is dead noise.references/performance.md.any. Turn on strict and noUncheckedIndexedAccess so arr[i] is T | undefined.VITE_-prefixed vars reach the client via import.meta.env.VITE_* — and everything VITE_ ships in the browser bundle. A VITE_API_SECRET is public. Proxy real secrets through a backend.vite-env.d.ts.vite.config.ts (resolve.alias) and tsconfig.json (paths) or imports break in one place.vite build emits dist/ — the deployable artifact. Deep types → ../typescript/SKILL.md.| Anti-pattern | Reality | Do instead |
|---|---|---|
"Fetch in useEffect, it's simpler" | Waterfalls, races, double-fire, no cache/dedupe | useQuery / useSuspenseQuery |
"Create the promise inline for use()" | New promise every render → suspends forever | Promise owned by a cache (TanStack Query) |
"Index as key, the list looks fine" | On reorder/delete, state sticks to the wrong row, list flickers | Stable id as key |
| "Put it in context so anyone can read it" | High-write context re-renders the whole consumer tree | Zustand + narrow selector |
| "Sync the prop into state with an effect" | Duplicated, stale state + an extra render | Derive in render, or key to reset a subtree |
"useMemo/useCallback everywhere for speed" | Noise; with React Compiler it's redundant | Measure first; let the compiler memoize |
"VITE_API_SECRET is fine, it's an env var" | It ships in the browser bundle — fully public | Proxy the secret through a backend |
"useEffect to compute a derived value" | Extra render + a stale window | Recompute in render |
scripts/verify.sh runs from the project root: ESLint → tsc --noEmit → Vitest → vite build, in that order. Each tool is detected and skipped with a warning (never a failure) if absent. The final vite build writes dist/; the lint/type/test steps are read-only. No installs, no network mutations, safe to re-run. It exits non-zero only on a real tool failure, and exits 0 on a clean/empty target.
If the workspace has 02-DOCS/, record stack-specific React conventions (chosen router, store, query defaults) in 02-DOCS/wiki/stack/react.md and index it from CLAUDE.md. Recorded, not gated — skip silently if there is no 02-DOCS/.
© ericrisco, MIT. Rendered from Markdown: HTML in the file is shown as text, images as links, and headings moved down two levels. Raw file
SKILL.md and 6 other files (scripts, references) in skills/react of ericrisco/rsc-harness.
Open the folder on GitHubat commit 92fde8f
React next to the 5 skills that share the most tags, products or categories with it. Stars are the repository's; “used in” counts other GitHub owners with a copy.
| Skill | Stars | Used in | Tokens | Auto-check | Licence | Repo updated |
|---|---|---|---|---|---|---|
| React this skillericrisco/rsc-harness | 156 | — | ~3.2k | Automated safety check: Pass | MIT | |
| Expo Web To Nativeexpo/skills | 2.7k | — | ~2.6k | Automated safety check: Pass | MIT | |
| Olore Tanstack Form Latestolorehq/olore | 103 | — | ~1.1k | Automated safety check: Pass | MIT | |
| Lingui Framework SetupB0und/WikiSpeedrun | 133 | — | ~1.9k | Automated safety check: Pass | MIT | |
| Add Error Trackinggotempsh/temps | 822 | — | ~4.2k | Automated safety check: Notes | Apache-2.0 | |
| React Native Mmkvmargelo/react-native-skills | 175 | — | ~2.1k | Automated safety check: Pass | MIT |
expo/skills
Migrate an existing web React app to a native iOS/Android app with Expo.
olorehq/olore
Local TanStack Form documentation reference (latest, v1.33.5).
B0und/WikiSpeedrun
Set up Lingui in a React framework. An agent skill from B0und/WikiSpeedrun.
gotempsh/temps
Add Temps error tracking to applications using the Sentry-compatible SDK.
margelo/react-native-skills
Fast synchronous key-value storage for React Native via react-native-mmkv (Nitro-backed).
tech-leads-club/agent-skills
Guides React Native and Expo work for cross-platform apps: Expo Router navigation, fast lists, Reanimated animation, platform-specific code and project structure.
ericrisco/rsc-harness
A skill your agent uses when designing or analyzing a controlled experiment — falsifiable hypothesis, sample size from an MDE, reading significance/CI/power, CUPED, or rescuing tests that won't go…
ericrisco/rsc-harness
A skill your agent uses when making a web UI conform to WCAG 2.2 Level AA — axe-core or Lighthouse a11y violations, keyboard operability, focus management, ARIA roles/names/live regions, contrast…
ericrisco/rsc-harness
A skill your agent uses when running or fixing paid acquisition on Google or Meta — campaign structure (Performance Max, Demand Gen, Search, Advantage+), platform-fit creative, budget/scaling rules…
ericrisco/rsc-harness
A skill your agent uses when measuring whether an LLM or agent system actually got better and gating merges on it: golden sets, fixing an inflated LLM-as-judge, scoring RAG (faithfulness, contextual…
ericrisco/rsc-harness
A skill your agent uses when a creative goal must become a finished media file: pick and order generative-media models per modality — AI voiceover, image-to-video clips, score — then glue them with…
ericrisco/rsc-harness
A skill your agent uses when instrumenting product or web analytics — GA4/PostHog SDK wiring, event taxonomy, funnels, double-counted events, consent gating, PII scrubbing.
Categories
A skill your agent uses when building or reviewing a client-side React SPA bundled by Vite (React 19.2): components, where state lives, hooks, server data fetching, client routing, re-render and…. React is an agent skill from ericrisco/rsc-harness.2): components, where state lives, hooks, server data fetching, client routing, re-render and effect bugs.
React fits situations like: reviewing a client-side React SPA bundled by Vite (React 19.2): components; where state lives; server data fetching; re-render and effect bugs.
Run `npx skills add ericrisco/rsc-harness --skill react -a claude-code`. Or copy the skill folder (skills/react in ericrisco/rsc-harness) into .claude/skills/react in your project. Claude Code loads it when a task matches its description.
Run `npx skills add ericrisco/rsc-harness --skill react -a codex`. Or copy the skill folder (skills/react in ericrisco/rsc-harness) into .agents/skills/react in your project. Codex loads it when a task matches its description.
Cursor, Gemini CLI, GitHub Copilot and OpenCode also load SKILL.md folders. With the skills CLI, run `npx skills add ericrisco/rsc-harness --skill react -a cursor` (or -a gemini-cli, github-copilot or opencode for the others). To copy it by hand, put the folder in .cursor/skills/react, .gemini/skills/react, .github/skills/react and .opencode/skills/react in your project.
Going by SKILL.md and its folder, React needs a shell for the scripts in its folder, the command-line tools its instructions call (tsc) and credentials named VITE_API_SECRET. Our summary lists: A Bash shell; A credential in VITE_API_SECRET.
SKILL.md contains no URLs. Any network use would come from the scripts or tools the agent runs. This is read from the text; nothing was executed.
Our automated static check of SKILL.md found no risky patterns, such as piping downloads into a shell, reading credential files or hidden Unicode. It is not a guarantee. The check reads SKILL.md only: the scripts in the folder are not scanned, so read them before running anything.
React is published under the MIT licence (the repository's licence). It allows redistribution, so the full SKILL.md is shown on this page.
About 3.2k tokens (SKILL.md is roughly 13k characters). Agents keep only the skill's name and description in context until a task matches; then they load SKILL.md in full. Its references folder adds about 3k tokens, read only when the agent opens those files.
Skills that share tags, products or a category with React: Expo Web To Native (expo/skills, 2.7k stars), Olore Tanstack Form Latest (olorehq/olore, 103 stars), Lingui Framework Setup (B0und/WikiSpeedrun, 133 stars) and Add Error Tracking (gotempsh/temps, 822 stars). The comparison table on this page puts their stars, adoption, token cost, safety result and licence side by side.
ericrisco (a GitHub user) maintains it in ericrisco/rsc-harness, which has 156 GitHub stars. The repository holds 229 skills in this directory. The repository was last updated on October 6, 2026.
Source: ericrisco/rsc-harness on GitHub. Facts on this page come from the repository at the commit we read; the author's words are quoted as theirs.