agentsclimarketplace

Ios dev

Skill Sean-Michael/skills/ios-dev

Use for any mobile app task: building, modifying, testing, or deploying with Expo + React Native. Triggers: mobile app, iOS app, React Native, Expo, simulator, TestFlight, App Store, expo run, app.json. Core rule: never hand off without completing the validation loop. The human's only job is UI/UX feel.From its SKILL.md

Install
npx -y skills add Sean-Michael/skills --skill ios-dev

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

2 things to look at

  • no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
  • 0 stars0 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

6.8 KB, ~1.7k tokens by cl100k_base, as published. Nobody here has run it

iOS Development Skill (Expo + React Native)

Stack

  • React Native via Expo SDK (latest stable), TypeScript strict
  • Build: npx expo run:ios (local builds, no EAS)
  • Navigation: Expo Router (preferred)
  • Backend: Supabase (always — see supabase/postgres skills for schema/RLS/migrations)
  • State: Zustand + React Query
  • Styling: NativeWind or StyleSheet — pick one per project, stay consistent

Project Setup

npx create-expo-app@latest <app-name> --template blank-typescript
npx expo install expo-router react-native-safe-area-context react-native-screens

Set "strict": true in tsconfig. Configure app.json bundleIdentifier, version: "1.0.0", ios.buildNumber: "1". Install all required libraries before writing features.

Version discipline — Apple rejects without this: version is semver, bump manually per App Store release. ios.buildNumber increments per TestFlight upload. Expo never auto-bumps either.

Supabase Wiring (RN-specific only)

The supabase skill handles everything else. These three things differ from web:

1. Install

npx expo install @supabase/supabase-js @react-native-async-storage/async-storage \
  expo-secure-store expo-auth-session expo-web-browser

2. Client configSecureStore adapter + detectSessionInUrl: false (breaks auth without it):

import { createClient } from '@supabase/supabase-js'
import * as SecureStore from 'expo-secure-store'

export const supabase = createClient(
  process.env.EXPO_PUBLIC_SUPABASE_URL!,   // EXPO_PUBLIC_ prefix required
  process.env.EXPO_PUBLIC_SUPABASE_ANON_KEY!,
  {
    auth: {
      storage: { getItem: SecureStore.getItemAsync, setItem: SecureStore.setItemAsync, removeItem: SecureStore.deleteItemAsync },
      autoRefreshToken: true, persistSession: true,
      detectSessionInUrl: false,
    },
  }
)

3. OAuth — web redirect flow doesn't work in RN:

import * as AuthSession from 'expo-auth-session'
import * as WebBrowser from 'expo-web-browser'
WebBrowser.maybeCompleteAuthSession()

const redirectUri = AuthSession.makeRedirectUri({ scheme: 'your-scheme' })
const { data } = await supabase.auth.signInWithOAuth({
  provider: 'google',
  options: { redirectTo: redirectUri, skipBrowserRedirect: true },
})
if (data.url) await WebBrowser.openAuthSessionAsync(data.url, redirectUri)

Register scheme in app.json. Register redirect URI in Supabase dashboard → Auth → URL Configuration.

Storage uploads — direct URI doesn't work, read via expo-file-system as base64 first.

Targeting a Simulator by Name

npx expo run:ios --simulator "iPhone 17 Pro"   # simulator — use --simulator, NOT --device
# --device targets physical devices and requires code signing

Boot + open:

xcrun simctl boot "iPhone 17 Pro" 2>/dev/null || true && open -a Simulator

Simulator Interaction

xcrun simctl io booted tap does NOT exist. Do not attempt it.

Options for driving UI without touch injection:

1. Debugger-driven navigation (preferred for validation)

Wire up a globalThis.__navigateTo helper in __DEV__ so the Metro debugger can drive navigation and read/write Zustand state without UI interaction:

// App.tsx or root layout — DEV only
import { createNavigationContainerRef } from '@react-navigation/native';
export const navigationRef = createNavigationContainerRef<any>();

if (__DEV__) {
  (globalThis as any).__navigateTo = (name: string) => {
    if (navigationRef.isReady()) navigationRef.navigate(name as never);
  };
}

Connect from Node.js:

const WebSocket = require('ws');
// get device id: GET http://localhost:8081/json
const ws = new WebSocket('ws://localhost:8081/inspector/debug?device=<id>&page=1');
ws.on('open', () => {
  ws.send(JSON.stringify({
    id: 1, method: 'Runtime.evaluate',
    params: { expression: '__navigateTo("ProfileScreen")' }
  }));
});

Use Runtime.evaluate to call __navigateTo, read/write Zustand stores, assert UI state.

2. xcrun simctl io booted screenshot <path> — always works, any process:

xcrun simctl io booted screenshot /tmp/sim.png

3. Physical mouse clicks on Simulator — only when Simulator is frontmost app.

4. xcrun simctl io booted sendPasteboard + keyboard shortcut — for text input.

Validation Loop

Run after every feature. Do not declare done until all pass.

npx tsc --noEmit           # must be clean
npx expo-doctor            # must be clean
xcrun simctl boot "iPhone 17 Pro" 2>/dev/null || true && open -a Simulator
npx expo run:ios --simulator "iPhone 17 Pro"

For each screen: navigate (via debugger or manual click) → screenshot → verify renders → exercise interactive elements → screenshot → verify result. Check empty/loading/error states.

xcrun simctl io booted screenshot /tmp/sim.png

Repeat on iPhone SE:

xcrun simctl boot "iPhone SE (3rd generation)" 2>/dev/null || true
npx expo run:ios --simulator "iPhone SE (3rd generation)"

Sign-off checklist:

  • tsc --noEmit clean
  • expo-doctor clean
  • Launches without crash on iPhone 17 Pro and iPhone SE sims
  • Every screen renders correctly (screenshot verified)
  • Every interactive element works (tap + screenshot verified, or debugger-driven)
  • No Metro console errors
  • Auth flow works: sign in, protected route gating, sign out
  • Data screens load real Supabase data

Footguns

  • Native rebuild: adding a native-code library requires re-running expo run:ios, not just restarting Metro. Same applies to changes to babel.config.js — module IDs change at the native boundary. Rule: anything that affects the Metro module graph at the native boundary needs a full rebuild.
  • --simulator vs --device: use --simulator "iPhone 17 Pro" to target a sim by name. --device targets physical devices and will trigger code signing prompts if one is paired.
  • Safe area: root needs <SafeAreaProvider>, screens need <SafeAreaView> — missing = content under notch
  • Keyboard: text input screens need <KeyboardAvoidingView behavior="padding">
  • Expo Go: some libraries don't work in Expo Go; always use expo run:ios dev builds
  • babel-preset-expo: use babel-preset-expo, not @react-native/babel-preset — the latter causes crashes

References

  • references/eas-testflight.md — TestFlight/App Store submission when ready
  • references/common-libraries.md — curated Expo-compatible library list
  • references/plugin-architecture.md — recommended structure for extensible apps

What ships with it: 3 files

5.3 KB alongside SKILL.md

Keep looking

Skills are one crate of 325,949. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.