scaffold — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited scaffold (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Expo SDK 52+ (managed), Expo Router v4, NativeWind v4, React Query, axios, react-hook-form + zod v4, zustand-x, Reanimated v3, Gesture Handler v2, MMKV, expo-secure-store, EAS.
Gather from user:
com.myorg.myapp)bunx create-expo-app@latest MyApp --template blank-typescript
cd MyAppbunx expo install expo-router react-native-safe-area-context react-native-screens expo-linking expo-constants expo-status-bar
bunx expo install nativewind react-native-reanimated react-native-gesture-handler
bun add tailwindcss@^3.4.0
bunx expo install @tanstack/react-query axios
bunx expo install react-hook-form @hookform/resolvers zod zod-empty
bunx expo install expo-secure-store react-native-mmkv
bunx expo install expo-image
bun add zustand-x mutativeNote: Installtailwindcssseparately withbun add tailwindcss@^3.4.0— do NOT usebunx expo install tailwindcssas it resolves Tailwind v4 which NativeWind v4 does not support. NativeWind v4 requires Tailwind CSS v3.
app.json{
"expo": {
"name": "MyApp",
"slug": "my-app",
"version": "1.0.0",
"scheme": "myapp",
"newArchEnabled": true,
"ios": {
"supportsTablet": true,
"bundleIdentifier": "com.myorg.myapp"
},
"android": {
"adaptiveIcon": { "foregroundImage": "./assets/adaptive-icon.png" },
"package": "com.myorg.myapp"
},
"plugins": [
"expo-router",
"expo-secure-store"
]
}
}tailwind.config.js:
/** @type {import('tailwindcss').Config} */
module.exports = {
content: ['./app/**/*.{js,jsx,ts,tsx}', './src/**/*.{js,jsx,ts,tsx}'],
presets: [require('nativewind/preset')],
theme: {
extend: {
colors: {
primary: '#6366f1',
background: '#ffffff',
},
},
},
}global.css:
@tailwind base;
@tailwind components;
@tailwind utilities;metro.config.js:
const { getDefaultConfig } = require('expo/metro-config')
const { withNativeWind } = require('nativewind/metro')
const config = getDefaultConfig(__dirname)
module.exports = withNativeWind(config, { input: './global.css' })babel.config.js:
module.exports = function (api) {
api.cache(true)
return {
presets: [
['babel-preset-expo', { jsxImportSource: 'nativewind' }],
'nativewind/babel',
],
}
}app/
├── (auth)/
│ ├── _layout.tsx
│ ├── login.tsx
│ └── register.tsx
├── (app)/
│ ├── _layout.tsx
│ └── (tabs)/
│ ├── _layout.tsx
│ └── index.tsx
├── _layout.tsx
└── +not-found.tsx
src/
├── api/
├── components/
│ ├── ui/
│ └── app/
├── hooks/
├── stores/
├── libs/
│ ├── cn.ts
│ ├── query-client.ts
│ └── axios.ts
└── types/src/libs/cn.ts:
import { clsx, type ClassValue } from 'clsx'
import { twMerge } from 'tailwind-merge'
export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)) }src/libs/query-client.ts:
import { QueryClient } from '@tanstack/react-query'
export const queryClient = new QueryClient({
defaultOptions: {
queries: { staleTime: Infinity, gcTime: Infinity, retry: false, refetchOnMount: false, refetchOnWindowFocus: false },
mutations: { retry: false },
},
})src/libs/axios.ts:
import axios from 'axios'
export const api = axios.create({
baseURL: process.env.EXPO_PUBLIC_API_URL,
timeout: 30_000,
})
// Add auth interceptor: attach token from SecureStoreapp/_layout.tsx)import '../global.css'
import { QueryClientProvider } from '@tanstack/react-query'
import { Stack } from 'expo-router'
import { queryClient } from '@/libs/query-client'
export default function RootLayout() {
return (
<QueryClientProvider client={queryClient}>
<Stack screenOptions={{ headerShown: false }} />
</QueryClientProvider>
)
}bun add -D eas-cli
bunx eas init
bunx eas build:configureeas.json:
{
"cli": { "version": ">= 12.0.0" },
"build": {
"development": { "developmentClient": true, "distribution": "internal" },
"preview": { "distribution": "internal" },
"production": { "autoIncrement": true }
},
"submit": {
"production": {}
}
}bun add -D eslint @typescript-eslint/eslint-plugin @typescript-eslint/parser prettier husky lint-staged
bunx husky initeslint.config.js:
import tsPlugin from '@typescript-eslint/eslint-plugin'
import tsParser from '@typescript-eslint/parser'
export default [
{ files: ['src/**/*.{ts,tsx}', 'app/**/*.{ts,tsx}'], languageOptions: { parser: tsParser },
plugins: { '@typescript-eslint': tsPlugin },
rules: { '@typescript-eslint/no-explicit-any': 'error', 'no-console': 'error' } },
].prettierrc:
{ "singleQuote": true, "semi": false, "trailingComma": "all", "useTabs": true }.husky/pre-commit:
bun run typecheck && bun run lintbun run typecheck passesbunx expo start opens in Expo GonewArchEnabled: true in app.json(auth)/ and (app)/ layouts created.env.local with EXPO_PUBLIC_API_URL (never committed)~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.