B
Claude Code logoClaude CodeMobile (React Native / Expo)

Claude Code Mobile RN Studio

Theo Vance@appkid_t
84.0Overall score

A platform-reviewer subagent flags iOS/Android divergence early, and Detox smoke tests on stop catch broken screens before commit. Sonnet keeps cost reasonable for the high edit volume of mobile UI work.

84.0Score
521Votes
5Components
1dUpdated

Install this build

Export
terminal
npx setuproll add claude-code-mobile-rn

Components

Model

  • Claude Sonnet 4.6

MCP servers

  • filesystem
  • github
  • playwright

Subagents

  • screen-builder
  • platform-reviewer
  • tester

Hooks

  • PostToolUse: typecheck
  • Stop: run detox smoke

Rules

  • Respect platform conventions (iOS vs Android)
  • No layout without safe-area handling
  • Keep bundle size in check
Setup

How I let Claude Code build my RN screens without it breaking the safe area every time

My actual Sonnet 4.6 setup for shipping Expo apps solo: a screen-builder agent, a platform reviewer that nags about iOS vs Android, and a Detox smoke test on stop.

appkid_t8 min read2026-06-20

I build mobile apps alone. No designer, no QA, no backend team to argue with. Just me, a MacBook, a Pixel 7 on my desk and an old iPhone SE that I keep around specifically because if a layout survives that tiny screen it survives anything. For about a year I treated AI coding tools as a fancy autocomplete and not much else. Then I sat down and actually wired Claude Code into the way I work on React Native, and now it builds whole screens for me while I watch the simulator.

This is the exact setup I run, called Mobile RN Studio in my notes. Model is Sonnet 4.6, not Opus. People in mobile keep reaching for the biggest model out of habit and then complain about the bill. UI work is high edit volume, lots of small repetitive changes to JSX and styles, and Sonnet keeps up fine for a fraction of the cost. My runs land around 28 cents. I will take that.

Why Sonnet and not Opus
Mobile UI is not deep reasoning, it is volume. You touch the same StyleSheet forty times an hour. A cheaper, fast model that you run more often beats a slow expensive one you babysit. Save Opus for the gnarly native module debugging.

What actually lives in the config

Three things do the heavy lifting: my CLAUDE.md rules, three subagents, and two hooks. The MCP servers I keep boring on purpose: filesystem, github, and playwright (I use Playwright to drive the Expo web build for quick visual checks before I touch a device). Here is the memory file, trimmed to the parts that matter.

CLAUDE.md
# Mobile RN Studio

Stack: Expo SDK 53, React Native, TypeScript, expo-router, NativeWind.

## Hard rules
- Respect platform conventions. iOS and Android are NOT the same OS.
  Use Platform.select for anything that differs (shadows, ripple, headers).
- No screen ships without safe-area handling. Wrap in SafeAreaView or
  use useSafeAreaInsets. Never hardcode a 44px top pad and call it done.
- Keep the bundle in check. No moment.js, no lodash full import,
  no random animation lib when Reanimated already ships. Justify every dep.

## Conventions
- Screens live in app/, components in components/, never inline 200-line JSX.
- StyleSheet.create or NativeWind classes, no inline style objects in render.
- Every Pressable needs an accessibilityLabel.

## Before you say done
- Run the typecheck (the hook does it, but check it passed).
- Confirm it renders on iOS AND Android, not just one.

The safe-area rule is in there because I got burned. Early on Claude would happily build a beautiful header that sat right under the iPhone notch on every device with a notch. Looked perfect in the Android emulator, totally broken on real hardware. Now it is the second line of the file and it mostly behaves.

Safe area is not optional
If you do not spell this out, the model defaults to web habits and assumes the top-left of the screen is usable. On a phone it is not. Notches, status bars, gesture bars, punch-hole cameras. Make it a rule, not a hope.

The three subagents

I keep a tiny team. A screen-builder that writes the actual UI, a platform-reviewer whose entire job is to catch iOS versus Android divergence before I do, and a tester that handles Detox. The platform-reviewer is the one that earns its keep. Below is its definition.

.claude/agents/platform-reviewer.md
---
name: platform-reviewer
description: Reviews RN screens for iOS vs Android divergence and safe-area bugs. Use after any screen is built or edited.
tools: Read, Grep, Glob
---

You review React Native code for cross-platform correctness. You do NOT write features.

Check every changed screen for:
- Hardcoded top/bottom padding that ignores safe-area insets
- Shadow props (iOS) used without elevation (Android), or vice versa
- TouchableOpacity ripple assumptions that only work on one platform
- Platform-specific APIs called without Platform.OS guards
- Fonts/letterSpacing that render differently and need Platform.select

Output a short numbered list of findings, each with file:line and the fix.
If a screen is clean on both platforms, say so in one line. Do not pad.

It runs read-only on purpose. I do not want my reviewer also being my editor, because then it starts justifying its own work. Separate context, separate job. The screen-builder writes, the reviewer pokes holes, and I make the call.

Hooks that catch the dumb stuff

Two hooks. A PostToolUse typecheck so a broken edit never sits quietly, and a Stop hook that runs a Detox smoke test so I find out a screen is blank before I commit, not after.

.claude/settings.json
{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write",
        "hooks": [
          {
            "type": "command",
            "command": "npx tsc --noEmit -p tsconfig.json"
          }
        ]
      }
    ],
    "Stop": [
      {
        "hooks": [
          {
            "type": "command",
            "command": "detox test -c ios.sim.debug e2e/smoke.test.ts --silent"
          }
        ]
      }
    ]
  }
}

The Detox smoke test is dead simple. It launches the app, taps through the three main tabs, and asserts each one has its title text on screen. That is it. It is not full coverage, it is a smoke alarm. Catches the white-screen-of-death where a screen throws on mount and the bundler does not warn you.

zsh - mobile-rn-studio
$claude
> build the new streak history screen, list of past 30 days with a calendar grid
screen-builder: created app/(tabs)/history.tsx + components/StreakGrid.tsx
PostToolUse hook: tsc --noEmit ... 0 errors
platform-reviewer: 2 findings
1) StreakGrid.tsx:41 shadow* set, no elevation -> Android renders flat
2) history.tsx:18 paddingTop: 24 ignores inset -> use useSafeAreaInsets
Applying both fixes...
Stop hook: detox smoke ... 3 passed, 0 failed (11.4s)
$
$

That is a real shape of a session. The reviewer caught the exact two things I would have caught myself an hour later on the Pixel, except it caught them in eleven seconds. The elevation one specifically. I would have shipped a card that has a nice shadow on iOS and looks completely flat on Android, and I would not have noticed until a user emailed me.

Expo Go - StreakGrid
iOS 17 (iPhone SE) Android 14 (Pixel 7)
------------------------ ------------------------
[ Streak History ] [ Streak History ]
inset top: 20px ok inset top: 24px ok
card shadow: visible card elevation: visible
calendar grid: 7 cols calendar grid: 7 cols
scroll: bounces (iOS) scroll: overscroll glow
smoke test: PASS smoke test: PASS
The history screen after the reviewer pass, side by side on both sims.
The honest tradeoff
Pass rate on this build sits around 80 percent, lower than my refactor setup. Mobile UI is fiddly and the model still guesses wrong on gesture handling sometimes. But at 2.6s a turn and 28 cents a run, I iterate fast enough that the misses do not hurt.

What I reach for, what I skip

TaskLet Claude run itDo it myself
New screen from a sketchYes, screen-builder nails layout
Cross-platform style reviewYes, the reviewer is faster than me
Reanimated gesture handlersSometimes, verify on deviceTricky ones
Native module / config pluginAlmost always me
App Store metadata + screenshotsMe, every time

Native modules are still my job. The moment you are editing a config plugin or touching Podfile stuff, the model starts confidently inventing API that does not exist in your SDK version. I let it draft, I never let it ship that unread.

Claude Code Tutorial #8 - Subagents12:36
Claude Code Tutorial #8 - Subagents· Net Ninja

If you have never set up a subagent, that Net Ninja video is the cleanest intro I have seen. It is web-focused but the mechanics are identical to what I do for mobile. Define the markdown file, give it a tight tool allowlist, point it at one job.

Create custom subagents - Claude Code DocsThe frontmatter spec I copied for my platform-reviewer. The tool allowlist field is the important part.code.claude.comdisler/claude-code-hooks-masteryWhere I figured out the Stop hook lifecycle. My Detox-on-stop idea came straight out of reading this.github.com4.2k

A few things that took me a while to learn

  • Keep the reviewer read-only. The second it can edit, it stops being a critic.
  • Detox on stop, not on every edit. Smoke tests are slow, you do not want one per keystroke.
  • Put the safe-area rule in CLAUDE.md, near the top. It gets ignored if it is rule number nine.
  • Test on the smallest real device you own. Sims lie about safe-area sometimes.
  • Pick the cheap model for UI. You will run it ten times more often, so cost compounds.

That is the whole thing. Nothing exotic, just a model that fits the work, three small agents with one job each, and two hooks that catch the mistakes I always make. If you want to try the exact setup, grab it with setuproll install claude-code-mobile-rn and point it at an Expo project. Then go put it on a real phone, because that is the only review that counts.

0 Reviews

Your rating
Sign in to post

Loading discussion...