Skip to content

■ SKILLS // SKILL SPECS

jutsu-expo

Validation and quality enforcement for Expo React Native projects with config, router, modules, updates, and build skills.

■ [!] ON THIS PAGE ▼
■ INSTALL // npx @self.md/cli install jutsu-expo
AuthorThe Bushido Collective
Namespace@TheBushidoCollective/han
Category#general
Version1.0.0
Stars★ 66
Downloads↓ 6
Verification[ ✓ ] self.md verified

Validation and quality enforcement for Expo React Native projects with config, router, modules, updates, and build skills.

Installation

npx claude-plugins install @TheBushidoCollective/han/jutsu-expo

Contents

Folders: skills

Files: CHANGELOG.md, README.md

Documentation

Validation and quality enforcement for Expo React Native projects.

What This Jutsu Provides

Skills

This jutsu provides the following skills:

  • expo-config: Configuring Expo apps with app.json, app.config.js/ts, and EAS configuration including plugins, build settings, and environment variables
  • expo-router: Implementing file-based routing with Expo Router including layouts, dynamic routes, navigation, and deep linking
  • expo-modules: Working with Expo SDK modules for camera, location, notifications, file system, and other device APIs
  • expo-updates: Implementing over-the-air (OTA) updates with Expo Updates for deploying changes without app store releases
  • expo-build: Building and deploying Expo apps with EAS Build including development builds, production builds, and app store submission

Installation

Install with npx (no installation required):

han plugin install jutsu-expo

Requirements

  • Expo SDK 50 or higher
  • TypeScript 5.0 or higher
  • Node.js 18 or higher

Why Expo?

Expo is a framework and platform for React Native that makes mobile development faster and easier:

  • Managed Workflow: Build apps without touching native code
  • EAS (Expo Application Services): Cloud build, updates, and submission
  • Expo Router: File-based routing system
  • Rich SDK: 50+ modules for device features (camera, location, etc.)
  • OTA Updates: Deploy updates instantly without app store review
  • Universal Apps: Share code across iOS, Android, and web
  • Developer Experience: Fast refresh, debugging tools, and documentation

Features Covered by Skills

Configuration (app.json/app.config.ts)

  • App metadata and settings
  • Platform-specific configuration
  • Plugin system
  • Environment variables
  • Build profiles
  • Deep linking setup

Expo Router

  • File-based routing
  • Stack, tab, and drawer navigation
  • Dynamic routes with parameters
  • Layouts and nested routes
  • Route groups
  • Authentication flows
  • Modal routes
  • Type-safe navigation

Expo Modules (SDK)

  • Camera and image picker
  • Location and maps
  • Push notifications
  • File system and storage
  • Secure storage
  • Device information
  • Background tasks
  • Sharing and permissions

OTA Updates

  • Automatic update checking
  • Manual update triggers
  • Update channels
  • Runtime versions
  • Silent updates
  • Update UI patterns

EAS Build

  • Development builds
  • Preview and production builds
  • Environment configuration
  • Secrets management
  • Version management
  • App store submission
  • Build monitoring

Quick Start Examples

Create New Expo App

npx create-expo-app@latest my-app
cd my-app

Basic Expo Router App

// app/_layout.tsx
import { Stack } from 'expo-router';

export default function RootLayout() {
  return <Stack />;
}

// app/index.tsx
import { Link } from 'expo-router';
import { View, Text } from 'react-native';

export default function Home() {
  return (
    <View>
      <Text>Home Screen</Text>
      <Link href="/details">Go to Details</Link>
    </View>
  );
}

// app/details.tsx
export default function Details() {
  return (
    <View>
      <Text>Details Screen</Text>
    </View>
  );
}

Using Expo Modules

import { Camera } from 'expo-camera';
import * as Location from 'expo-location';
import * as Notifications from 'expo-notifications';

// Request permissions and use modules
const [cameraPermission] = Camera.useCameraPermissions();

Configure for Production

// app.config.ts
export default {
  name: 'MyApp',
  slug: 'my-app',
  version: '1.0.0',
  extra: {
    apiUrl: process.env.API_URL,
  },
  plugins: [
    'expo-router',
    'expo-camera',
    'expo-location',
  ],
};

Build with EAS

# Install EAS CLI
npm install -g eas-cli

# Login
eas login

# Configure project
eas build:configure

# Build for iOS
eas build --platform ios --profile production

# Build for Android
eas build --platform android --profile production

Project Structure

Recommended structure for Expo apps with Expo Router:

my-app/
├── app/                  # Routes (file-based routing)
│   ├── (tabs)/          # Tab navigation group
│   │   ├── _layout.tsx
│   │   ├── index.tsx
│   │   └── profile.tsx
│   ├── _layout.tsx      # Root layout
│   └── index.tsx        # Home route
├── components/          # Reusable components
├── hooks/               # Custom hooks
├── utils/               # Utility functions
├── assets/              # Images, fonts, etc.
├── app.json             # Expo configuration
├── eas.json             # EAS Build configuration
├── package.json
└── tsconfig.json

Common Expo Modules

Essential modules for most Expo apps:

  • expo-router: File-based navigation
  • expo-camera: Camera access
  • expo-location: Location services
  • expo-notifications: Push notifications
  • expo-image-picker: Select images/videos
  • expo-file-system: File operations
  • **expo-secure-stor

Included Skills

This plugin includes 5 skill definitions:

expo-build

Use when building and deploying Expo apps with EAS Build. Covers build configuration, development builds, production builds, and app store submission.

View skill definition

Expo Build with EAS

Use this skill when building and deploying Expo applications using EAS (Expo Application Services) Build.

Key Concepts

EAS Build Configuration

// eas.json
{
  "cli": {
    "version": ">= 5.9.0"
  },
  "build": {
    "development": {
      "developmentClient": true,
      "distribution": "internal",
      "ios": {
        "simulator": true
      }
    },
    "preview": {
      "distribution": "internal"
    },
    "production": {
      "autoIncrement": true
    }
  },
  "submit": {
    "production": {}
  }
}

Build Commands

# Development build
eas build --profile development --platform ios
eas build --profile development --platform android

# Preview build
eas build --profile preview --platform all

# Production build
eas build --profile production --platform all

# Local build
eas build --profile production --platform ios --local

Development Builds

{
  "build": {
    "development": {
      "developmentClient": true,
      "distribution": "internal",
      "env": {
        "NODE_ENV": "development"
      }
    }
  }
}

Best Practices

Environment Variables

// eas.json
{
  "build": {
    "production": {
      "env": {
        "APP_ENV": "production",
        "API_URL": "https://api.myapp.com"
      }
    },
    "staging": {
      "env": {
        "APP_ENV": "staging",
        "API_URL": "https://staging-api.myapp.com"
      }
    }
  }
}

Secrets Management

# Set sec

...(truncated)

</details>

### expo-config

> Use when configuring Expo apps with app.json, app.config.js, and EAS configuration. Covers app metadata, plugins, build configuration, and environment variables.

<details>
<summary>View skill definition</summary>

# Expo Configuration

Use this skill when configuring Expo applications using app.json, app.config.js/ts, and EAS (Expo Application Services) configuration files.

## Key Concepts

### app.json Configuration

Basic static configuration:

```json
{
  "expo": {
    "name": "MyApp",
    "slug": "my-app",
    "version": "1.0.0",
    "orientation": "portrait",
    "icon": "./assets/icon.png",
    "userInterfaceStyle": "automatic",
    "splash": {
      "image": "./assets/splash.png",
      "resizeMode": "contain",
      "backgroundColor": "#ffffff"
    },
    "assetBundlePatterns": [
      "**/*"
    ],
    "ios": {
      "supportsTablet": true,
      "bundleIdentifier": "com.mycompany.myapp",
      "buildNumber": "1"
    },
    "android": {
      "adaptiveIcon": {
        "foregroundImage": "./assets/adaptive-icon.png",
        "backgroundColor": "#ffffff"
      },
      "package": "com.mycompany.myapp",
      "versionCode": 1
    },
    "web": {
      "favicon": "./assets/favicon.png"
    }
  }
}

Dynamic Configuration (app.config.js)

Use JavaScript for dynamic configuration:

export default ({ config }) => ({
  ...config,
  name: process.env.APP_NAME || 'MyApp',
  slug: 'my-app',
  version: '1.0.0',
  extra: {
    apiUrl: process.env.API_URL,
    environment: process.env.NODE_ENV,
  },
  ios: {
    bundleIdentifier:
      process.env.NODE_ENV === 'production'
        ? 'com.mycompany.myapp'
        : 'com.mycompany.myapp.dev',
  },
  android: {
    packag

...(truncated)

</details>

### expo-modules

> Use when working with Expo SDK modules for camera, location, notifications, file system, and other device APIs. Covers permissions, configurations, and best practices.

<details>
<summary>View skill definition</summary>

# Expo Modules

Use this skill when working with Expo's extensive SDK modules for accessing device features and native functionality.

## Key Concepts

### Camera

```tsx
import { Camera, CameraType } from 'expo-camera';
import { useState } from 'react';
import { Button, View } from 'react-native';

export default function CameraScreen() {
  const [permission, requestPermission] = Camera.useCameraPermissions();
  const [type, setType] = useState(CameraType.back);

  if (!permission?.granted) {
    return (
      <View>
        <Button title="Grant Permission" onPress={requestPermission} />
      </View>
    );
  }

  return (
    <Camera style={{ flex: 1 }} type={type}>
      <Button
        title="Flip Camera"
        onPress={() =>
          setType(type === CameraType.back ? CameraType.front : CameraType.back)
        }
      />
    </Camera>
  );
}

Location

import * as Location from 'expo-location';
import { useEffect, useState } from 'react';

export function useLocation() {
  const [location, setLocation] = useState<Location.LocationObject | null>(null);

  useEffect(() => {
    (async () => {
      const { status } = await Location.requestForegroundPermissionsAsync();
      if (status !== 'granted') return;

      const loc = await Location.getCurrentPositionAsync({});
      setLocation(loc);
    })();
  }, []);

  return location;
}

Notifications

import * as Notifications from 'expo-notifications';
import { useEffect } from 'react';



...(truncated)

</details>

### expo-router

> Use when implementing file-based routing in Expo with Expo Router. Covers app directory structure, navigation, layouts, dynamic routes, and deep linking.

<details>
<summary>View skill definition</summary>

# Expo Router

Use this skill when implementing file-based routing with Expo Router, the recommended navigation solution for Expo apps.

## Key Concepts

### File-Based Routing

Routes are defined by file structure:

app/ _layout.tsx # Root layout index.tsx # / route about.tsx # /about route (tabs)/ # Group (not in URL) _layout.tsx # Tabs layout home.tsx # /home profile.tsx # /profile users/ [id].tsx # /users/:id dynamic route index.tsx # /users route


### Basic Routes

```tsx
// app/index.tsx
import { View, Text } from 'react-native';
import { Link } from 'expo-router';

export default function Home() {
  return (
    <View>
      <Text>Home Screen</Text>
      <Link href="/about">Go to About</Link>
    </View>
  );
}

// app/about.tsx
export default function About() {
  return (
    <View>
      <Text>About Screen</Text>
    </View>
  );
}

Layouts

// app/_layout.tsx
import { Stack } from 'expo-router';

export default function RootLayout() {
  return (
    <Stack>
      <Stack.Screen name="index" options={{ title: 'Home' }} />
      <Stack.Screen name="about" options={{ title: 'About' }} />
    </Stack>
  );
}

Tab Navigation

// app/(tabs)/_layout.tsx
import { Tabs } from 'expo-router';
import { Ionicons } from '@expo/vector-icons';

export default function TabLayout() {
  return (
    <Tabs>
      <Tabs.Screen
       

...(truncated)

</details>

### expo-updates

> Use when implementing over-the-air (OTA) updates with Expo Updates. Covers update configuration, checking for updates, and update strategies.

<details>
<summary>View skill definition</summary>

# Expo Updates

Use this skill when implementing over-the-air (OTA) updates to deploy JavaScript and asset updates without app store releases.

## Key Concepts

### Configuration

```json
// app.json
{
  "expo": {
    "updates": {
      "enabled": true,
      "checkAutomatically": "ON_LOAD",
      "fallbackToCacheTimeout": 0,
      "url": "https://u.expo.dev/[project-id]"
    },
    "runtimeVersion": {
      "policy": "sdkVersion"
    }
  }
}

Checking for Updates

import * as Updates from 'expo-updates';
import { useEffect, useState } from 'react';
import { View, Text, Button } from 'react-native';

export default function App() {
  const [updateAvailable, setUpdateAvailable] = useState(false);

  useEffect(() => {
    async function checkForUpdates() {
      if (!__DEV__) {
        const update = await Updates.checkForUpdateAsync();
        setUpdateAvailable(update.isAvailable);
      }
    }
    checkForUpdates();
  }, []);

  const handleUpdate = async () => {
    const { isNew } = await Updates.fetchUpdateAsync();
    if (isNew) {
      await Updates.reloadAsync();
    }
  };

  if (updateAvailable) {
    return (
      <View>
        <Text>Update Available!</Text>
        <Button title="Update Now" onPress={handleUpdate} />
      </View>
    );
  }

  return <View>{/* Your app */}</View>;
}

Runtime Versions

// app.config.ts
export default {
  expo: {
    runtimeVersion: {
      policy: 'appVersion', // Match app version
    },
   

...(truncated)

</details>

## Source

[View on GitHub](https://github.com/TheBushidoCollective/han)