From 4ab819416406b535a216852458c8459d5cb1a01b Mon Sep 17 00:00:00 2001 From: Jon Samp Date: Mon, 6 Jul 2026 10:32:52 -0500 Subject: [PATCH 1/2] Organize skills with expo-* and eas-* naming Prefix every skill with expo-* (framework/OSS) or eas-* (paid EAS service), and prefix each description with "Framework (OSS)." or "EAS service (paid)." so the free/paid boundary is visible in the always-loaded metadata and /expo- / /eas- discovery works. Renames to established product names: - building-native-ui (visual guide) -> expo-native-ui; navigation stays in the expo-router skill, matching the #99 split - native-data-fetching -> expo-data-fetching - use-dom -> expo-dom - web-to-native -> expo-web-to-native - add-app-clip -> expo-app-clip - upgrading-expo -> expo-upgrade - expo-observe -> eas-observe - expo-cicd-workflows -> eas-workflows - expo-deployment -> eas-app-stores (web deploy split into eas-hosting) - expo-api-routes -> eas-hosting Add CONTRIBUTING.md with documented patterns, CI checks for skill limits and plugin version bump, and bump the expo plugin to 1.7.0. Co-Authored-By: Claude Opus 4.8 (1M context) --- .claude/skills/expo-skill-eval/SKILL.md | 2 +- .../references/runtime-matrix.md | 20 +-- AGENTS.md | 25 +++- CONTRIBUTING.md | 129 ++++++++++++++++++ README.md | 49 ++++--- plugins/expo/.claude-plugin/plugin.json | 2 +- plugins/expo/.codex-plugin/plugin.json | 2 +- plugins/expo/.cursor-plugin/plugin.json | 2 +- plugins/expo/README.md | 97 +++++++------ plugins/expo/skills/README.md | 44 ++++++ .../skills/add-app-clip/agents/openai.yaml | 4 - .../building-native-ui/agents/openai.yaml | 4 - .../SKILL.md | 37 ++--- .../skills/eas-app-stores/agents/openai.yaml | 4 + .../references/app-store-metadata.md | 0 .../references/ios-app-store.md | 0 .../references/play-store.md | 0 .../references/testflight.md | 0 .../references/workflows.md | 46 +------ .../{expo-api-routes => eas-hosting}/SKILL.md | 63 ++++++++- .../skills/eas-hosting/agents/openai.yaml | 4 + .../{expo-observe => eas-observe}/SKILL.md | 6 +- .../skills/eas-observe/agents/openai.yaml | 4 + .../references/metrics.md | 0 .../references/queries.md | 0 .../references/setup.md | 0 plugins/expo/skills/eas-simulator/SKILL.md | 4 +- .../skills/eas-simulator/agents/openai.yaml | 4 + .../expo/skills/eas-update-insights/SKILL.md | 6 +- .../eas-update-insights/agents/openai.yaml | 4 +- .../SKILL.md | 6 +- .../skills/eas-workflows/agents/openai.yaml | 4 + .../scripts/fetch.js | 0 .../scripts/package.json | 0 .../scripts/validate.js | 0 .../skills/expo-api-routes/agents/openai.yaml | 4 - .../{add-app-clip => expo-app-clip}/SKILL.md | 6 +- .../skills/expo-app-clip/agents/openai.yaml | 4 + .../references/native-module.md | 0 plugins/expo/skills/expo-brownfield/SKILL.md | 2 +- .../references/brownfield-integrated.md | 2 +- .../expo-cicd-workflows/agents/openai.yaml | 4 - .../SKILL.md | 68 +-------- .../expo-data-fetching/agents/openai.yaml | 4 + .../references/expo-router-loaders.md | 0 .../references/offline-and-cancellation.md | 68 +++++++++ .../skills/expo-deployment/agents/openai.yaml | 4 - plugins/expo/skills/expo-dev-client/SKILL.md | 4 +- .../skills/{use-dom => expo-dom}/SKILL.md | 4 +- .../expo/skills/expo-dom/agents/openai.yaml | 4 + plugins/expo/skills/expo-examples/SKILL.md | 7 +- .../skills/expo-examples/agents/openai.yaml | 4 + plugins/expo/skills/expo-module/SKILL.md | 2 +- .../SKILL.md | 8 +- .../skills/expo-native-ui/agents/openai.yaml | 4 + .../references/animations.md | 0 .../references/controls.md | 0 .../references/gradients.md | 0 .../references/icons.md | 0 .../references/media.md | 0 .../references/storage.md | 0 .../references/visual-effects.md | 0 .../references/webgpu-three.md | 0 plugins/expo/skills/expo-router/SKILL.md | 8 +- .../expo/skills/expo-tailwind-setup/SKILL.md | 2 +- plugins/expo/skills/expo-ui/SKILL.md | 2 +- .../{upgrading-expo => expo-upgrade}/SKILL.md | 4 +- .../skills/expo-upgrade/agents/openai.yaml | 4 + .../references/expo-av-to-audio.md | 0 .../references/expo-av-to-video.md | 0 .../references/native-tabs.md | 0 .../references/new-architecture.md | 0 .../references/react-19.md | 0 .../references/react-compiler.md | 0 .../react-navigation-to-expo-router.md | 0 .../SKILL.md | 26 ++-- .../expo-web-to-native/agents/openai.yaml | 4 + .../references/false-friends.md | 14 +- .../references/native-patterns.md | 10 +- .../references/run-as-goal.md | 6 +- .../references/verify-on-device.md | 2 +- .../native-data-fetching/agents/openai.yaml | 4 - .../skills/upgrading-expo/agents/openai.yaml | 4 - .../expo/skills/use-dom/agents/openai.yaml | 4 - scripts/check-skill-limits.ts | 77 +++++++++-- skills.sh.json | 47 +++---- 86 files changed, 632 insertions(+), 361 deletions(-) create mode 100644 plugins/expo/skills/README.md delete mode 100644 plugins/expo/skills/add-app-clip/agents/openai.yaml delete mode 100644 plugins/expo/skills/building-native-ui/agents/openai.yaml rename plugins/expo/skills/{expo-deployment => eas-app-stores}/SKILL.md (59%) create mode 100644 plugins/expo/skills/eas-app-stores/agents/openai.yaml rename plugins/expo/skills/{expo-deployment => eas-app-stores}/references/app-store-metadata.md (100%) rename plugins/expo/skills/{expo-deployment => eas-app-stores}/references/ios-app-store.md (100%) rename plugins/expo/skills/{expo-deployment => eas-app-stores}/references/play-store.md (100%) rename plugins/expo/skills/{expo-deployment => eas-app-stores}/references/testflight.md (100%) rename plugins/expo/skills/{expo-deployment => eas-app-stores}/references/workflows.md (73%) rename plugins/expo/skills/{expo-api-routes => eas-hosting}/SKILL.md (77%) create mode 100644 plugins/expo/skills/eas-hosting/agents/openai.yaml rename plugins/expo/skills/{expo-observe => eas-observe}/SKILL.md (69%) create mode 100644 plugins/expo/skills/eas-observe/agents/openai.yaml rename plugins/expo/skills/{expo-observe => eas-observe}/references/metrics.md (100%) rename plugins/expo/skills/{expo-observe => eas-observe}/references/queries.md (100%) rename plugins/expo/skills/{expo-observe => eas-observe}/references/setup.md (100%) create mode 100644 plugins/expo/skills/eas-simulator/agents/openai.yaml rename plugins/expo/skills/{expo-cicd-workflows => eas-workflows}/SKILL.md (83%) create mode 100644 plugins/expo/skills/eas-workflows/agents/openai.yaml rename plugins/expo/skills/{expo-cicd-workflows => eas-workflows}/scripts/fetch.js (100%) rename plugins/expo/skills/{expo-cicd-workflows => eas-workflows}/scripts/package.json (100%) rename plugins/expo/skills/{expo-cicd-workflows => eas-workflows}/scripts/validate.js (100%) delete mode 100644 plugins/expo/skills/expo-api-routes/agents/openai.yaml rename plugins/expo/skills/{add-app-clip => expo-app-clip}/SKILL.md (92%) create mode 100644 plugins/expo/skills/expo-app-clip/agents/openai.yaml rename plugins/expo/skills/{add-app-clip => expo-app-clip}/references/native-module.md (100%) delete mode 100644 plugins/expo/skills/expo-cicd-workflows/agents/openai.yaml rename plugins/expo/skills/{native-data-fetching => expo-data-fetching}/SKILL.md (86%) create mode 100644 plugins/expo/skills/expo-data-fetching/agents/openai.yaml rename plugins/expo/skills/{native-data-fetching => expo-data-fetching}/references/expo-router-loaders.md (100%) create mode 100644 plugins/expo/skills/expo-data-fetching/references/offline-and-cancellation.md delete mode 100644 plugins/expo/skills/expo-deployment/agents/openai.yaml rename plugins/expo/skills/{use-dom => expo-dom}/SKILL.md (97%) create mode 100644 plugins/expo/skills/expo-dom/agents/openai.yaml create mode 100644 plugins/expo/skills/expo-examples/agents/openai.yaml rename plugins/expo/skills/{building-native-ui => expo-native-ui}/SKILL.md (95%) create mode 100644 plugins/expo/skills/expo-native-ui/agents/openai.yaml rename plugins/expo/skills/{building-native-ui => expo-native-ui}/references/animations.md (100%) rename plugins/expo/skills/{building-native-ui => expo-native-ui}/references/controls.md (100%) rename plugins/expo/skills/{building-native-ui => expo-native-ui}/references/gradients.md (100%) rename plugins/expo/skills/{building-native-ui => expo-native-ui}/references/icons.md (100%) rename plugins/expo/skills/{building-native-ui => expo-native-ui}/references/media.md (100%) rename plugins/expo/skills/{building-native-ui => expo-native-ui}/references/storage.md (100%) rename plugins/expo/skills/{building-native-ui => expo-native-ui}/references/visual-effects.md (100%) rename plugins/expo/skills/{building-native-ui => expo-native-ui}/references/webgpu-three.md (100%) rename plugins/expo/skills/{upgrading-expo => expo-upgrade}/SKILL.md (97%) create mode 100644 plugins/expo/skills/expo-upgrade/agents/openai.yaml rename plugins/expo/skills/{upgrading-expo => expo-upgrade}/references/expo-av-to-audio.md (100%) rename plugins/expo/skills/{upgrading-expo => expo-upgrade}/references/expo-av-to-video.md (100%) rename plugins/expo/skills/{upgrading-expo => expo-upgrade}/references/native-tabs.md (100%) rename plugins/expo/skills/{upgrading-expo => expo-upgrade}/references/new-architecture.md (100%) rename plugins/expo/skills/{upgrading-expo => expo-upgrade}/references/react-19.md (100%) rename plugins/expo/skills/{upgrading-expo => expo-upgrade}/references/react-compiler.md (100%) rename plugins/expo/skills/{upgrading-expo => expo-upgrade}/references/react-navigation-to-expo-router.md (100%) rename plugins/expo/skills/{web-to-native => expo-web-to-native}/SKILL.md (67%) create mode 100644 plugins/expo/skills/expo-web-to-native/agents/openai.yaml rename plugins/expo/skills/{web-to-native => expo-web-to-native}/references/false-friends.md (91%) rename plugins/expo/skills/{web-to-native => expo-web-to-native}/references/native-patterns.md (78%) rename plugins/expo/skills/{web-to-native => expo-web-to-native}/references/run-as-goal.md (79%) rename plugins/expo/skills/{web-to-native => expo-web-to-native}/references/verify-on-device.md (90%) delete mode 100644 plugins/expo/skills/native-data-fetching/agents/openai.yaml delete mode 100644 plugins/expo/skills/upgrading-expo/agents/openai.yaml delete mode 100644 plugins/expo/skills/use-dom/agents/openai.yaml diff --git a/.claude/skills/expo-skill-eval/SKILL.md b/.claude/skills/expo-skill-eval/SKILL.md index 763c48c..4ea45bd 100644 --- a/.claude/skills/expo-skill-eval/SKILL.md +++ b/.claude/skills/expo-skill-eval/SKILL.md @@ -72,7 +72,7 @@ Read `references/runtime-matrix.md` to find the skill's default mode before sugg Pass the choice to the snapshot scripts via the `EXPO_SKILL_EVAL_RUNNER` env var (`expo-go` default, or `dev-build`), and reflect it in each eval case's `runtime.mode` (`expo-go` or `dev-build`). See step 5. -**Pick the platforms — always ask, regardless of skill.** Offer iOS / Android / web (multi-select) with `AskUserQuestion`; default to iOS + Android, but always present web as an option — don't pre-filter by skill. **Web is a valid choice for most skills**: `@expo/ui`'s *universal* components (`Host`, `Row`, `Column`, `Button`, `List`, …) render on web, as do `use-dom`, NativeWind/Tailwind, API routes, and plain React Native. The only thing that won't show on web is a *platform-specific* native tree (`@expo/ui/swift-ui` or `@expo/ui/jetpack-compose`), which renders blank there — and that blank is itself a useful signal, so it's still the user's call. Web runs via `snapshot-web.sh` (`expo start --web` + Playwright/Chromium) **regardless of the runner** (`expo run` is native-only; there's no web dev build), and it's the least-exercised path. Write the chosen set into each eval case's `runtime.platforms` and have `run_snapshots.py` loop them. +**Pick the platforms — always ask, regardless of skill.** Offer iOS / Android / web (multi-select) with `AskUserQuestion`; default to iOS + Android, but always present web as an option — don't pre-filter by skill. **Web is a valid choice for most skills**: `@expo/ui`'s *universal* components (`Host`, `Row`, `Column`, `Button`, `List`, …) render on web, as do `expo-dom`, NativeWind/Tailwind, API routes, and plain React Native. The only thing that won't show on web is a *platform-specific* native tree (`@expo/ui/swift-ui` or `@expo/ui/jetpack-compose`), which renders blank there — and that blank is itself a useful signal, so it's still the user's call. Web runs via `snapshot-web.sh` (`expo start --web` + Playwright/Chromium) **regardless of the runner** (`expo run` is native-only; there's no web dev build), and it's the least-exercised path. Write the chosen set into each eval case's `runtime.platforms` and have `run_snapshots.py` loop them. **Confirm how `claude -p` subprocesses run — once, before starting.** Ask with `AskUserQuestion` whether they may run with `--dangerously-skip-permissions`, then apply the same answer to every subprocess this run (never re-prompt mid-run): diff --git a/.claude/skills/expo-skill-eval/references/runtime-matrix.md b/.claude/skills/expo-skill-eval/references/runtime-matrix.md index aa65f97..752569a 100644 --- a/.claude/skills/expo-skill-eval/references/runtime-matrix.md +++ b/.claude/skills/expo-skill-eval/references/runtime-matrix.md @@ -10,25 +10,25 @@ Modes: | Skill | Mode | Platforms | Notes | |-------|------|-----------|-------| -| building-native-ui | expo-go | ios, android | Core target for visual evals. RN primitives + styling/controls/media/animations all work in Expo Go. | | expo-router | expo-go | ios, android | Navigation/routing target: routes, links, native stacks, modals, sheets, headers. Native tabs sections may need a dev build — verify per case. | +| expo-native-ui | expo-go | ios, android | Core target for visual evals. RN primitives + styling/controls/media/animations all work in Expo Go. | | expo-tailwind-setup | expo-go | ios, android, web | NativeWind v5 / react-native-css are JS-level; works in Expo Go. Good web candidate too. | -| native-data-fetching | expo-go | ios, android | Fetch/React Query/SWR are pure JS. Mock or use stable public endpoints so evals are deterministic. | -| use-dom | expo-go | ios, android, web | DOM components run in a webview on native (Expo Go, SDK 52+) and as-is on web. Allow extra settle time for the webview to paint. | -| expo-api-routes | static-only + HTTP | — | No screenshot: while Metro runs, `curl` the route and save the response as an output file for grading. | +| expo-data-fetching | expo-go | ios, android | Fetch/React Query/SWR are pure JS. Mock or use stable public endpoints so evals are deterministic. | +| expo-dom | expo-go | ios, android, web | DOM components run in a webview on native (Expo Go, SDK 52+) and as-is on web. Allow extra settle time for the webview to paint. | +| eas-hosting | static-only + HTTP | — | No screenshot: while Metro runs, `curl` the route and save the response as an output file for grading. | | expo-ui (merged swift-ui + jetpack-compose) | expo-go | ios, android, web | `@expo/ui` ships in the SDK 56 default template (~56.0.17) and its native code is included in Expo Go 56 — verified rendering 2026-06: a SwiftUI Form renders in Expo Go on the iOS simulator. The **universal** components (`Host`, `Row`, `Column`, `Button`, `List`, …) also render on **web**; only the platform-specific `@expo/ui/swift-ui` (SwiftUI) and `@expo/ui/jetpack-compose` (Compose) trees are native-only and render blank on web. Pick platforms by what the eval case uses. | | expo-module | static-only | — | Custom native modules can't load in Expo Go. Gate on TS compile of the module API; native compilation (prebuild + xcodebuild/gradle) is possible but expensive — out of scope for now. | -| add-app-clip | static-only | — | App Clip targets require prebuild + Xcode. Assert on config-plugin output instead. | +| expo-app-clip | static-only | — | App Clip targets require prebuild + Xcode. Assert on config-plugin output instead. | | expo-brownfield | static-only | — | Brownfield integration has no Expo Go story. Assert on generated integration files. | | expo-dev-client | n/a | — | Output is build/distribution workflow, not renderable app code. | -| expo-deployment | n/a | — | Deployment guidance; assert on transcript/config content only. | -| expo-cicd-workflows | n/a | — | Output is `.eas/workflows/` YAML; assert on YAML content (and `workflow_validate` via the Expo MCP if available). | -| upgrading-expo | static-only | — | An upgrade eval can run the static gate on the upgraded fixture — a strong signal. Needs a fixture pinned to an *older* SDK (pass e.g. `55` to make-fixture.sh). | +| eas-app-stores | n/a | — | Deployment guidance; assert on transcript/config content only. | +| eas-workflows | n/a | — | Output is `.eas/workflows/` YAML; assert on YAML content (and `workflow_validate` via the Expo MCP if available). | +| expo-upgrade | static-only | — | An upgrade eval can run the static gate on the upgraded fixture — a strong signal. Needs a fixture pinned to an *older* SDK (pass e.g. `55` to make-fixture.sh). | | eas-update-insights | n/a | — | CLI/metrics interpretation; no app code output. | -| expo-observe | expo-go (verify) | ios, android | `expo-observe` instrumentation is JS-level, but confirm the package works in Expo Go before relying on screenshots; fall back to static-only. | +| eas-observe | expo-go (verify) | ios, android | `expo-observe` instrumentation is JS-level, but confirm the package works in Expo Go before relying on screenshots; fall back to static-only. | Entries marked "verify" haven't been validated against a real run yet — confirm on first use and update this table. ## Image-prompt (clone-this) candidates -Image prompts (`reference_image` — build an app to match a target screenshot, graded by `reference_match` + `references/design-rubric.md`) are most informative for the **visual** skills — `building-native-ui`, `expo-ui`, `expo-tailwind-setup`, `use-dom` — where reproducing a specific UI is the point. Pair them with "Runtime + screenshots" so the harness captures the generated app to compare against the target. They add nothing for `n/a` skills (no app UI). +Image prompts (`reference_image` — build an app to match a target screenshot, graded by `reference_match` + `references/design-rubric.md`) are most informative for the **visual** skills — `expo-router`, `expo-ui`, `expo-tailwind-setup`, `expo-dom` — where reproducing a specific UI is the point. Pair them with "Runtime + screenshots" so the harness captures the generated app to compare against the target. They add nothing for `n/a` skills (no app UI). diff --git a/AGENTS.md b/AGENTS.md index 04e596e..e5d87ea 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -23,13 +23,18 @@ plugins/ .mcp.json # Claude Code and Codex MCP server configuration mcp.json # Cursor MCP server configuration skills/ + README.md # Grouped index of all skills skill-name/ SKILL.md # Main skill file references/ # Optional supporting documentation scripts/ # Optional utility scripts + agents/ + openai.yaml # Codex trigger metadata README.md # Plugin documentation README.md # User-facing installation instructions -CONTRIBUTING.md # Contributor guidance +CONTRIBUTING.md # Contributor guidance (adding skills, naming, free vs paid) +skills.sh.json # skills.sh catalog groupings +scripts/ # CI checks (skill limits, plugin version bump) ``` The Claude Code marketplace currently exposes `expo` as the active plugin. It also keeps deprecated aliases such as `expo-app-design`, `upgrading-expo`, and `expo-deployment` pointing at `./plugins/expo` for backward compatibility. The Codex and Cursor marketplaces expose only the active `expo` plugin because their marketplace entries must match the plugin manifest name. @@ -89,7 +94,8 @@ Frontmatter fields: Skill guidelines: -- Keep `SKILL.md` focused and under 500 lines when practical. +- Name skills `expo-*` (open-source framework) or `eas-*` (paid EAS service), and prefix the description with `Framework (OSS).` or `EAS service (paid).` to match. Paid skills open the body with a costs/plan-limits callout. See `CONTRIBUTING.md` for the full rules. +- Keep the `SKILL.md` body under 500 lines and the `description` under 1024 characters - both are CI-enforced by `scripts/check-skill-limits.ts`. - Move detailed material to `references/` and load it only when the skill needs it. - Put reusable validation or fetching logic in `scripts/` instead of pasting large command blocks into the skill. - Write descriptions that match how users naturally ask for help. @@ -188,11 +194,14 @@ When changing Claude Code marketplace aliases, preserve backward compatibility u ## Adding a Skill -1. Create `plugins/expo/skills/my-skill/SKILL.md`. -2. Add focused reference files under `plugins/expo/skills/my-skill/references/` when the skill needs more detail than belongs in the main `SKILL.md`. -3. Add scripts under `plugins/expo/skills/my-skill/scripts/` only for reusable logic. -4. Update `plugins/expo/README.md` or the root `README.md` only when the user-facing installation or usage story changes. -5. Keep the skill under the existing `expo` plugin unless there is a clear distribution reason to create a new plugin. +Follow the full guide in `CONTRIBUTING.md`. In short: + +1. Pick the name per the naming rule: `expo-*` for open-source framework skills, `eas-*` for paid EAS service skills. +2. Create `plugins/expo/skills//SKILL.md` with the category-prefixed description (`Framework (OSS).` or `EAS service (paid).`); paid skills open with a costs/plan-limits callout. +3. Add focused reference files under `references/` when the skill needs more detail than belongs in the main `SKILL.md`, scripts under `scripts/` only for reusable logic, and `agents/openai.yaml` for Codex triggering. +4. Register the skill in every catalog: `skills.sh.json`, `plugins/expo/README.md`, `plugins/expo/skills/README.md`, and the root `README.md`. +5. Bump the version in all three plugin manifests together (they must match and be greater than main; CI-enforced). +6. Keep the skill under the existing `expo` plugin unless there is a clear distribution reason to create a new plugin. ## Testing Plugins @@ -201,6 +210,8 @@ Validate the changed surface before publishing: ```bash claude plugin validate . claude plugin validate ./plugins/expo +bun scripts/check-skill-limits.ts +bun scripts/check-plugin-version-bump.ts origin/main ``` For JSON-only changes, also verify the edited JSON file parses: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index f8fd73c..f1a0f25 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,3 +1,132 @@ # Contributing - Use your skills locally first to build something meaningful before contributing. + +## Adding a new skill + +Skills teach an agent how to do one Expo task well. Follow these guidelines so new +skills stay consistent with the rest of the marketplace. + +### 1. Scaffold it with `skill-creator` + +From Claude Code, run the `/skill-creator` skill to scaffold a new skill - and to edit, optimize, +or eval an existing one. It sets up the folder structure and helps you tune the `description` for +reliable triggering. + +Skills live one level deep: + +``` +plugins/expo/skills// + SKILL.md # required + references/ # optional, loaded on demand + scripts/ # optional, reusable logic + agents/openai.yaml # Codex trigger metadata +``` + +### 2. Name it `expo-*` or `eas-*` + +Names are lowercase kebab-case (max 64 chars). The prefix signals the free/paid boundary: + +- **`expo-*`** - open-source framework skills: the Expo SDK, Expo Router, React Native, and + local tooling. Examples: `expo-router`, `expo-dom`, `expo-module`, `expo-web-to-native`. +- **`eas-*`** - skills whose core purpose is a paid Expo Application Services product. + Examples: `eas-hosting`, `eas-app-stores`, `eas-workflows`, `eas-observe`, `eas-simulator`. + +Name after what users say, and prefer the real product or package name (e.g. `eas-hosting`, +not `expo-api-routes`). To rename an existing skill, `git mv` the directory (to preserve +history), update the frontmatter `name:`, and fix every reference (catalogs, `agents/openai.yaml`, +cross-links in other skills). + +### 3. Decide free vs paid - and be strict about it + +A skill belongs in **Services & paid distribution** only if its **core purpose requires a paid +EAS product** (EAS Build, Submit, Hosting, Update, Workflows, Observe, Simulator, …). + +- A paid **Apple Developer or Google Play** account does **not** make a skill "paid" here - that + is app-store distribution, not EAS. `expo-app-clip` is a framework skill even though shipping a + Clip needs an Apple account. +- If authoring is free and only *deploying* is paid, it is usually still framework - unless the + skill is fundamentally about the paid service. (`eas-hosting` is the deploy skill, so it is + paid; free API-route authoring lives inside it.) +- Litmus test: *can a developer get the main value of this skill without paying Expo?* + Yes → framework (`expo-*`). No → paid (`eas-*`). + +### 4. Prefix the description, and add a costs note for paid skills + +Every `description` opens with its category label: + +- Framework: `Framework (OSS). ` +- Paid: `EAS service (paid). ` + +Paid skills also open the `SKILL.md` **body** with a short callout: + +```markdown +> **EAS service - costs apply.** . See https://expo.dev/pricing. +``` + +### 5. Write a description that triggers well + +The `description` is how an agent decides to load the skill, so it matters more than any other field. + +- **Max 1024 characters** (CI-enforced). +- Say **what it does** *and* **when to use it**, in the words users actually type ("turn a website + into an app", "run on a cloud simulator", "ship to TestFlight"). +- Use concrete package, command, and API names (`@expo/ui`, `eas deploy`, `+api.ts`) - but don't + keyword-stuff with unrelated terms. +- When a sibling skill is easy to confuse with, add a `Not for …` clause (see `expo-ui` vs + `expo-router`). + +### 6. Keep it concise - context windows are the constraint + +When a skill triggers, its whole `SKILL.md` loads into the agent's context. Shorter is better. + +- The body is capped at **500 lines** (CI-enforced) - treat that as a ceiling, not a target. +- Move anything the agent needs only *sometimes* into `references/*.md` and link to it; references + load on demand. +- Put reusable validation or fetching logic in `scripts/` instead of long inline command blocks. +- One skill = one job. If it grows two distinct triggers, split it (that is why `eas-hosting` and + `eas-app-stores` are separate skills). + +### 7. Add the Codex agent file + +Add `agents/openai.yaml` with `display_name`, `short_description` (paid skills prefix it +`Paid EAS service.`), and a `default_prompt` that references the skill via `$`. + +### 8. Register the skill in every catalog + +Add it to the correct group (framework vs paid) in all of: + +- `skills.sh.json` +- `plugins/expo/README.md` - **What This Plugin Does**, **When to Use**, and **Skills Included** +- `plugins/expo/skills/README.md` +- `README.md` + +### 9. Bump the plugin version + +Bump `version` in **all three** manifests together - they must match each other and be greater +than `main`. CI enforces this. + +- `plugins/expo/.claude-plugin/plugin.json` +- `plugins/expo/.codex-plugin/plugin.json` +- `plugins/expo/.cursor-plugin/plugin.json` + +### 10. Validate before opening a PR + +```bash +claude plugin validate ./plugins/expo +bun scripts/check-skill-limits.ts +bun scripts/check-plugin-version-bump.ts origin/main +``` + +Also run `python3 -m json.tool ` on any JSON you edited, and if the skill ships `scripts/`, +run that skill's own validation. + +`check-skill-limits.ts` enforces more than the size caps: the naming rule (step 2), the category +prefixes and paid costs callout (step 4), the Codex agent file and its paid prefix (step 7), and +the `skills.sh.json` grouping (step 8) all fail CI when violated. + +### Conventions + +- MIT license for every skill; use `@expo.io` or `@expo.dev` author emails. +- Keep `references/` next to the skill that uses them. +- Don't broaden a skill's scope or trigger intent when editing it - keep changes focused. diff --git a/README.md b/README.md index 140bab1..094a990 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ npx skills@latest update To update a single Expo skill, pass its name: ```text -npx skills@latest update building-native-ui +npx skills@latest update expo-router ``` ## Try It @@ -91,43 +91,40 @@ Agents choose the right skill from the task context and each skill's description ## Skills Included -### App Design and Architecture +Skills come in two groups so the free vs paid boundary is clear. Each skill's description carries the same label, and every services skill opens with a costs/plan-limits note. -| Skill | Use it for | -| --- | --- | -| `building-native-ui` | Native-feeling screen styling, semantic colors, controls, icons, media, animations, and visual effects. | -| `expo-router` | Expo Router navigation: file-based routes, links, native stacks, modals, sheets, native tabs, and headers. | -| `native-data-fetching` | API calls, React Query, SWR, caching, offline support, and Expo Router data loaders. | -| `expo-api-routes` | Expo Router API routes with EAS Hosting. | -| `expo-tailwind-setup` | Tailwind CSS v4, `react-native-css`, and NativeWind v5 setup. | -| `use-dom` | Expo DOM components for gradually using web code in native apps. | -| `expo-dev-client` | Local and TestFlight development client builds. | +### Framework (open source) -### Native and Platform Work +Free, open-source Expo SDK and React Native skills. | Skill | Use it for | | --- | --- | +| `expo-router` | Expo Router navigation: file-based routes, links, native stacks, modals, sheets, native tabs, and headers. | +| `expo-native-ui` | Native-feeling screen styling, semantic colors, controls, icons, media, animations, and visual effects. | +| `expo-ui` | `@expo/ui` native components: universal cross-platform first, with SwiftUI and Jetpack Compose for platform-specific needs. | +| `expo-data-fetching` | API calls, React Query, SWR, caching, offline support, and Expo Router data loaders. | +| `expo-tailwind-setup` | Tailwind CSS v4, `react-native-css`, and NativeWind v5 setup. | +| `expo-dom` | Expo DOM components for gradually using web code in native apps. | +| `expo-web-to-native` | Migrating an existing web/React app (Next.js, Vite, CRA) to a native iOS/Android app with Expo. | | `expo-module` | Expo native modules and views with Swift, Kotlin, TypeScript, config plugins, and autolinking. | -| `expo-ui-swift-ui` | `@expo/ui/swift-ui` components and modifiers. | -| `expo-ui-jetpack-compose` | `@expo/ui/jetpack-compose` views and modifiers. | -| `add-app-clip` | iOS App Clip targets, AASA files, associated domains, and Smart App Banners. | | `expo-brownfield` | Adding Expo or React Native to an existing iOS or Android app. | +| `expo-dev-client` | Development clients (local builds are free; EAS Build/TestFlight is a paid step). | +| `expo-examples` | The `expo/examples` repo of `with-*` integrations to adapt or scaffold a new project from. | +| `expo-app-clip` | iOS App Clip targets, AASA files, associated domains, and Smart App Banners. | +| `expo-upgrade` | Expo SDK upgrades, dependency conflicts, deprecated packages, and cache cleanup. | -### Deployment, CI, and Observability +### Services & paid distribution -| Skill | Use it for | -| --- | --- | -| `expo-deployment` | App Store, Play Store, TestFlight, EAS Build, web hosting, and API route deployment. | -| `expo-cicd-workflows` | EAS Workflow YAML files and CI/CD automation. | -| `expo-observe` | EAS Observe setup and launch, route, event, and version metrics. | -| `eas-update-insights` | EAS Update health, crash rates, launch counts, payload size, and rollout gates. | -| `eas-simulator` | Run and drive your app on a remote iOS simulator or Android emulator on EAS cloud — from the CLI or an agent, with a live browser preview (iOS only). | - -### Maintenance +Skills whose core purpose uses paid Expo Application Services (EAS). | Skill | Use it for | | --- | --- | -| `upgrading-expo` | Expo SDK upgrades, dependency conflicts, deprecated packages, and cache cleanup. | +| `eas-app-stores` | Production builds, App Store, Play Store, TestFlight, eas.json profiles, versioning, and store metadata. | +| `eas-hosting` | Deploying Expo websites and Expo Router API routes to EAS Hosting: secrets, custom domains, Cloudflare Workers. | +| `eas-workflows` | EAS Workflow YAML files and CI/CD automation. | +| `eas-observe` | EAS Observe setup and launch, route, event, and version metrics. | +| `eas-update-insights` | EAS Update health, crash rates, launch counts, payload size, and rollout gates. | +| `eas-simulator` | Run and drive your app on a remote iOS simulator or Android emulator on EAS cloud - from the CLI or an agent, with a live browser preview (iOS only). | ## Expo MCP Server diff --git a/plugins/expo/.claude-plugin/plugin.json b/plugins/expo/.claude-plugin/plugin.json index 535e84b..683095c 100644 --- a/plugins/expo/.claude-plugin/plugin.json +++ b/plugins/expo/.claude-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "expo", - "version": "1.6.0", + "version": "1.7.0", "description": "Official Expo skills for building, deploying, upgrading, and debugging Expo apps", "author": { "name": "Expo Team", diff --git a/plugins/expo/.codex-plugin/plugin.json b/plugins/expo/.codex-plugin/plugin.json index afedcb4..a359a7e 100644 --- a/plugins/expo/.codex-plugin/plugin.json +++ b/plugins/expo/.codex-plugin/plugin.json @@ -1,6 +1,6 @@ { "name": "expo", - "version": "1.6.0", + "version": "1.7.0", "description": "Official Expo skills for building, deploying, upgrading, and debugging Expo and React Native apps.", "author": { "name": "Expo Team", diff --git a/plugins/expo/.cursor-plugin/plugin.json b/plugins/expo/.cursor-plugin/plugin.json index 0175432..92fbfe5 100644 --- a/plugins/expo/.cursor-plugin/plugin.json +++ b/plugins/expo/.cursor-plugin/plugin.json @@ -1,7 +1,7 @@ { "name": "expo", "displayName": "Expo", - "version": "1.6.0", + "version": "1.7.0", "description": "Official Expo skills for building, deploying, upgrading, and debugging Expo and React Native apps.", "author": { "name": "Expo Team", diff --git a/plugins/expo/README.md b/plugins/expo/README.md index 1ef9ea8..9b59696 100644 --- a/plugins/expo/README.md +++ b/plugins/expo/README.md @@ -2,89 +2,88 @@ Official AI agent skills from the Expo team for building, deploying, upgrading, and debugging Expo apps. +Skills come in two groups so the free vs paid boundary stays clear: open-source **framework** skills, and **services & paid distribution** skills whose core purpose uses paid Expo Application Services (EAS). Each services skill opens with a costs/plan-limits note. + ## What This Plugin Does -### App Design +### Framework (open source) - Provides UI guidelines following Apple Human Interface Guidelines - Covers Expo Router navigation patterns (stacks, tabs, modals, sheets) - Explains native iOS controls, SF Symbols, animations, and visual effects -- Guides API route creation with EAS Hosting +- Covers `@expo/ui` native components (universal, SwiftUI, and Jetpack Compose) - Covers data fetching patterns with React Query, offline support, and Expo Router loaders - Helps set up Tailwind CSS v4 with NativeWind v5 - Explains DOM components for running web code in native apps -- Covers iOS App Clips and brownfield Expo integration into existing native apps +- Covers Expo native modules, iOS App Clips, and brownfield integration into existing native apps +- Points at the `expo/examples` repo for canonical third-party integrations +- Walks through Expo SDK upgrades, deprecated-package migration, cache clearing, and dependency fixes - Wires Expo projects into the Codex app Run button and action terminal -### Deployment +### Services & paid distribution - Guides iOS App Store, TestFlight, and Android Play Store submissions - Covers EAS Build configuration and version management - Helps write and validate EAS Workflow YAML files for CI/CD - Checks EAS Update health, adoption, crash rates, and payload size -- Covers web deployment with EAS Hosting - -### Upgrading - -- Walks through the step-by-step Expo SDK upgrade process -- Identifies deprecated packages and their modern replacements -- Handles cache clearing for both managed and bare workflows -- Fixes dependency conflicts after an upgrade +- Tracks production performance with EAS Observe +- Covers website and API route authoring and deployment with EAS Hosting +- Runs and drives your app on remote iOS/Android simulators on EAS cloud ## When to Use -### App Design +### Framework (open source) - Building new Expo apps from scratch - Adding navigation, styling, or animations -- Setting up API routes or data fetching +- Wiring up data fetching - Integrating web libraries via DOM components +- Migrating an existing web/React app to native with Expo - Configuring Tailwind CSS for React Native -- Adding an iOS App Clip or integrating Expo into an existing native app -- Adding a Codex app Run button for `expo start` -- Creating optional Codex action buttons for iOS, Android, Web, dev-client, diagnostics, or export +- Writing Expo native modules or integrating Expo into an existing native app +- Adapting a third-party integration from `expo/examples` +- Upgrading to a new Expo SDK version and fixing dependency conflicts after an upgrade +- Migrating from deprecated packages (expo-av to expo-audio/expo-video) +- Adding an iOS App Clip (needs an Apple Developer account) +- Adding a Codex app Run button for `expo start` and optional iOS/Android/Web/dev-client action buttons -### Deployment +### Services & paid distribution - Submitting apps to App Store Connect or Google Play - Setting up TestFlight beta testing - Configuring EAS Build profiles - Writing CI/CD workflows for automated deployments - Inspecting EAS Update rollout health and adoption -- Deploying web apps with EAS Hosting - -### Upgrading - -- Upgrading to a new Expo SDK version -- Fixing dependency conflicts after an upgrade -- Migrating from deprecated packages (expo-av to expo-audio/expo-video) -- Cleaning up legacy configuration files +- Tracking startup, navigation, and event performance with EAS Observe +- Deploying a website or Expo Router API routes to EAS Hosting +- Running your app on a remote cloud simulator when no local simulator is available ## Skills Included -### App Design - -- **add-app-clip** — Add an iOS App Clip target to an Expo app (AASA, associated domains, TestFlight) -- **building-native-ui** — Build beautiful native-feeling screens: styling, semantic colors, controls, icons, media, animations, and visual effects -- **expo-api-routes** — Create API routes in Expo Router with EAS Hosting -- **expo-brownfield** — Integrate Expo and React Native into existing native iOS or Android apps -- **expo-dev-client** — Build and distribute Expo development clients locally or via TestFlight -- **expo-router** — Navigation and routing: file-based routes, links, native stacks, modals, sheets, native tabs, and headers -- **expo-tailwind-setup** — Set up Tailwind CSS v4 in Expo with NativeWind v5 -- **expo-ui** — Native UI with @expo/ui: universal cross-platform components first, with SwiftUI and Jetpack Compose for platform-specific needs -- **native-data-fetching** — Network requests, API calls, caching, and offline support -- **use-dom** — Run web code in a webview on native using DOM components - -### Deployment - -- **eas-update-insights** — Check EAS Update health, crash rates, adoption, and payload size -- **eas-simulator** — Run and drive your app on a remote iOS/Android simulator on EAS cloud, from the CLI or an AI agent -- **expo-deployment** — Deploy to iOS App Store, Android Play Store, and web hosting -- **expo-cicd-workflows** — EAS workflow YAML files for CI/CD pipelines - -### Upgrading - -- **upgrading-expo** — Upgrade Expo SDK versions and fix dependency issues +### Framework (open source) + +- **expo-router** - Navigation and routing: file-based routes, links, native stacks, modals, sheets, native tabs, and headers +- **expo-native-ui** - Build beautiful native-feeling screens: styling, semantic colors, controls, icons, media, animations, and visual effects +- **expo-ui** - Native UI with @expo/ui: universal cross-platform components first, with SwiftUI and Jetpack Compose for platform-specific needs +- **expo-data-fetching** - Network requests, API calls, caching, and offline support +- **expo-tailwind-setup** - Set up Tailwind CSS v4 in Expo with NativeWind v5 +- **expo-dom** - Run web code in a webview on native using DOM components +- **expo-web-to-native** - Migrate an existing web/React app to a native iOS/Android app with Expo +- **expo-module** - Write Expo native modules and views (Swift, Kotlin, TypeScript, config plugins) +- **expo-brownfield** - Integrate Expo and React Native into existing native iOS or Android apps +- **expo-dev-client** - Build and distribute Expo development clients (local builds free; EAS Build/TestFlight paid) +- **expo-examples** - Adapt or scaffold from the `expo/examples` repo of `with-*` integrations +- **expo-app-clip** - Add an iOS App Clip target (AASA, associated domains, Smart App Banners; needs an Apple Developer account) +- **expo-upgrade** - Upgrade Expo SDK versions and fix dependency issues + +### Services & paid distribution + +- **eas-app-stores** - Build and submit to the iOS App Store, Android Play Store, and TestFlight +- **eas-hosting** - Deploy Expo websites and API routes to EAS Hosting (secrets, custom domains, Cloudflare Workers) +- **eas-workflows** - EAS workflow YAML files for CI/CD pipelines +- **eas-observe** - EAS Observe setup and launch, route, event, and version metrics +- **eas-update-insights** - Check EAS Update health, crash rates, adoption, and payload size +- **eas-simulator** - Run and drive your app on a remote iOS/Android simulator on EAS cloud, from the CLI or an AI agent ## License diff --git a/plugins/expo/skills/README.md b/plugins/expo/skills/README.md new file mode 100644 index 0000000..0c771dd --- /dev/null +++ b/plugins/expo/skills/README.md @@ -0,0 +1,44 @@ +# Expo Skills Index + +Every skill in this directory is a sibling folder containing a `SKILL.md`. Skills are discovered **one level deep** - `skills//SKILL.md` - so this index groups them for humans; the filesystem stays flat. Each skill's frontmatter `description` is prefixed with its category so agents can see the free vs paid boundary in the always-loaded metadata. + +## Framework (open source) + +Free, open-source Expo SDK and React Native skills. Descriptions are prefixed `Framework (OSS).`. + +| Skill | Use it for | +| --- | --- | +| `expo-router` | Expo Router navigation: file-based routes, links, native stacks, modals, sheets, native tabs, and headers. | +| `expo-native-ui` | Native-feeling screen styling, semantic colors, controls, icons, media, animations, and visual effects. | +| `expo-ui` | `@expo/ui` native components: universal cross-platform first, plus SwiftUI and Jetpack Compose. | +| `expo-data-fetching` | API calls, React Query, SWR, caching, offline support, and Expo Router data loaders. | +| `expo-tailwind-setup` | Tailwind CSS v4, `react-native-css`, and NativeWind v5 setup. | +| `expo-dom` | Expo DOM components for gradually using web code in native apps. | +| `expo-web-to-native` | Migrating an existing web/React app (Next.js, Vite, CRA) to a native iOS/Android app with Expo. | +| `expo-module` | Expo native modules and views with Swift, Kotlin, TypeScript, config plugins, and autolinking. | +| `expo-brownfield` | Adding Expo or React Native to an existing iOS or Android app. | +| `expo-dev-client` | Development clients (local builds are free; EAS Build/TestFlight is a paid step). | +| `expo-examples` | The `expo/examples` repo of `with-*` integrations to adapt or scaffold from. | +| `expo-app-clip` | iOS App Clip targets, AASA files, associated domains, and Smart App Banners. | +| `expo-upgrade` | Expo SDK upgrades, dependency conflicts, deprecated packages, and cache cleanup. | + +## Services & paid distribution + +Skills whose core purpose uses paid Expo Application Services (EAS). Descriptions are prefixed `EAS service (paid).`, and each `SKILL.md` opens with a costs/plan-limits callout. + +| Skill | Use it for | Paid dependency | +| --- | --- | --- | +| `eas-app-stores` | Production builds, App Store, Play Store, TestFlight, eas.json profiles, versioning, and store metadata. | EAS + Apple/Google accounts | +| `eas-hosting` | Deploying Expo websites and Expo Router API routes to EAS Hosting: secrets, custom domains, Cloudflare Workers. | EAS Hosting usage | +| `eas-workflows` | EAS Workflow YAML files and CI/CD automation. | EAS build/compute minutes | +| `eas-observe` | EAS Observe setup and launch, route, event, and version metrics. | EAS Observe usage | +| `eas-update-insights` | EAS Update health, crash rates, launch counts, payload size, and rollout gates. | EAS Update usage | +| `eas-simulator` | Remote iOS/Android simulators on EAS cloud, driven from the CLI or an agent, with browser preview. | EAS Simulator usage | + +## Adding a skill + +1. Create `skills//SKILL.md` (one level deep - do not nest under a category folder, or it will not be discovered). +2. Prefix the frontmatter `description` with the category label (`Framework (OSS).` or `EAS service (paid).`). +3. For a services skill, open the body with a costs/plan-limits callout right after the H1. +4. Add the skill to the table above, to `skills.sh.json`, and to the root and plugin `README.md` lists. +5. Bump the version in all three plugin manifests (see `CONTRIBUTING.md`). diff --git a/plugins/expo/skills/add-app-clip/agents/openai.yaml b/plugins/expo/skills/add-app-clip/agents/openai.yaml deleted file mode 100644 index bb8b09b..0000000 --- a/plugins/expo/skills/add-app-clip/agents/openai.yaml +++ /dev/null @@ -1,4 +0,0 @@ -interface: - display_name: "Add App Clip" - short_description: "Add an iOS App Clip target to an Expo app with AASA, associated domains, and TestFlight setup" - default_prompt: "Use $add-app-clip when adding or reviewing an iOS App Clip target for an Expo app, including bundle IDs, associated domains, AASA files, smart app banners, App Store Connect setup, and TestFlight verification." diff --git a/plugins/expo/skills/building-native-ui/agents/openai.yaml b/plugins/expo/skills/building-native-ui/agents/openai.yaml deleted file mode 100644 index d515050..0000000 --- a/plugins/expo/skills/building-native-ui/agents/openai.yaml +++ /dev/null @@ -1,4 +0,0 @@ -interface: - display_name: "Building Native UI" - short_description: "Build beautiful Expo Router UI with native-feeling navigation, controls, media, animation, and visual effects" - default_prompt: "Use $building-native-ui to build or refactor Expo Router UI, choose native-feeling navigation and controls, structure routes, style screens, and decide when Expo Go is enough before creating native builds." diff --git a/plugins/expo/skills/expo-deployment/SKILL.md b/plugins/expo/skills/eas-app-stores/SKILL.md similarity index 59% rename from plugins/expo/skills/expo-deployment/SKILL.md rename to plugins/expo/skills/eas-app-stores/SKILL.md index 8f96e7d..6867390 100644 --- a/plugins/expo/skills/expo-deployment/SKILL.md +++ b/plugins/expo/skills/eas-app-stores/SKILL.md @@ -1,19 +1,21 @@ --- -name: expo-deployment -description: Deploy Expo apps to production with EAS — build and submit to the iOS App Store, Google Play Store, and TestFlight, configure eas.json build and submit profiles, manage app versions and build numbers, publish App Store metadata and ASO, and deploy web bundles and API routes via EAS Hosting. Use whenever the user is preparing a production build, running eas build or eas submit, shipping to TestFlight, releasing or rolling out to the app stores, bumping version or build numbers, or setting up store listing metadata for an Expo app. +name: eas-app-stores +description: EAS service (paid). Deploy Expo apps to the app stores with EAS - build and submit to the iOS App Store, Google Play Store, and TestFlight, configure eas.json build and submit profiles, manage app versions and build numbers, and publish App Store metadata and ASO. Use whenever the user wants to deploy, release, or ship an app to production or the app stores, is preparing a production build, running eas build or eas submit, shipping to TestFlight, bumping version or build numbers, or setting up store listing metadata. For deploying an Expo website or API routes, use the eas-hosting skill. version: 1.0.0 license: MIT --- -# Deployment +# App Store Deployment -This skill covers deploying Expo applications across all platforms using EAS (Expo Application Services). +> **EAS service - costs apply.** This skill uses Expo Application Services (EAS), a paid product with free-tier limits. `eas build` and `eas submit` consume your plan's build minutes, and store submission requires paid Apple Developer and Google Play accounts. Review https://expo.dev/pricing before running cloud commands. + +This skill covers building and releasing Expo apps to the iOS App Store, Google Play Store, and TestFlight using EAS (Expo Application Services). For deploying an Expo website or API routes to EAS Hosting, use the `eas-hosting` skill. ## References Consult these resources as needed: -- ./references/workflows.md -- CI/CD workflows for automated deployments and PR previews +- ./references/workflows.md -- CI/CD workflows for automated store releases and PR previews - ./references/testflight.md -- Submitting iOS builds to TestFlight for beta testing - ./references/app-store-metadata.md -- Managing App Store metadata and ASO optimization - ./references/play-store.md -- Submitting Android builds to Google Play Store @@ -64,20 +66,9 @@ npx eas-cli@latest build -p android --profile production --submit npx testflight ``` -## Web Deployment - -Deploy web apps using EAS Hosting: - -```bash -# Deploy to production -npx expo export -p web -npx eas-cli@latest deploy --prod - -# Deploy PR preview -npx eas-cli@latest deploy -``` +## Web & API Route Hosting -Expo Router API routes deploy together with the web bundle on EAS Hosting — `eas deploy` ships both. To author or configure the API routes themselves, use the `expo-api-routes` skill. +Deploying an Expo website or Expo Router API routes to EAS Hosting (`npx expo export -p web` then `eas deploy`) is covered by the `eas-hosting` skill. This skill focuses on native app store releases. ## EAS Configuration @@ -131,15 +122,9 @@ Standard `eas.json` for production deployments: - Configure tracks: internal → closed → open → production - See ./references/play-store.md for detailed setup -### Web - -- EAS Hosting provides preview URLs for PRs -- Production deploys to your custom domain -- See ./references/workflows.md for CI/CD automation - -## Automated Deployments +## Automated Releases -EAS Workflows automate the build → submit → update → deploy pipeline for CI/CD. See ./references/workflows.md for deployment-oriented examples. To author or validate workflow YAML, use the `expo-cicd-workflows` skill — it works from the live workflow schema. +EAS Workflows automate the build → submit → update pipeline for CI/CD. See ./references/workflows.md for store-release examples. To author or validate workflow YAML, use the `eas-workflows` skill - it works from the live workflow schema. ## Version Management diff --git a/plugins/expo/skills/eas-app-stores/agents/openai.yaml b/plugins/expo/skills/eas-app-stores/agents/openai.yaml new file mode 100644 index 0000000..79ce425 --- /dev/null +++ b/plugins/expo/skills/eas-app-stores/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "EAS App Stores" + short_description: "Paid EAS service. Build and submit Expo apps to the iOS App Store, Google Play Store, and TestFlight, with eas.json profiles, versioning, and store metadata" + default_prompt: "Use $eas-app-stores when preparing production EAS builds, store submissions, TestFlight distribution, app-store metadata and ASO, or version and build-number management for an Expo app. For web or API route hosting, use eas-hosting instead." diff --git a/plugins/expo/skills/expo-deployment/references/app-store-metadata.md b/plugins/expo/skills/eas-app-stores/references/app-store-metadata.md similarity index 100% rename from plugins/expo/skills/expo-deployment/references/app-store-metadata.md rename to plugins/expo/skills/eas-app-stores/references/app-store-metadata.md diff --git a/plugins/expo/skills/expo-deployment/references/ios-app-store.md b/plugins/expo/skills/eas-app-stores/references/ios-app-store.md similarity index 100% rename from plugins/expo/skills/expo-deployment/references/ios-app-store.md rename to plugins/expo/skills/eas-app-stores/references/ios-app-store.md diff --git a/plugins/expo/skills/expo-deployment/references/play-store.md b/plugins/expo/skills/eas-app-stores/references/play-store.md similarity index 100% rename from plugins/expo/skills/expo-deployment/references/play-store.md rename to plugins/expo/skills/eas-app-stores/references/play-store.md diff --git a/plugins/expo/skills/expo-deployment/references/testflight.md b/plugins/expo/skills/eas-app-stores/references/testflight.md similarity index 100% rename from plugins/expo/skills/expo-deployment/references/testflight.md rename to plugins/expo/skills/eas-app-stores/references/testflight.md diff --git a/plugins/expo/skills/expo-deployment/references/workflows.md b/plugins/expo/skills/eas-app-stores/references/workflows.md similarity index 73% rename from plugins/expo/skills/expo-deployment/references/workflows.md rename to plugins/expo/skills/eas-app-stores/references/workflows.md index 86053ce..4901f75 100644 --- a/plugins/expo/skills/expo-deployment/references/workflows.md +++ b/plugins/expo/skills/eas-app-stores/references/workflows.md @@ -1,50 +1,10 @@ # EAS Workflows -Automate builds, submissions, and deployments with EAS Workflows. The examples below are deployment-oriented starting points. +Automate builds, submissions, and PR-preview updates with EAS Workflows. The examples below are store-release-oriented starting points. -When you need to write, edit, or validate a workflow YAML file beyond these examples, use the `expo-cicd-workflows` skill. +When you need to write, edit, or validate a workflow YAML file beyond these examples, use the `eas-workflows` skill. For website and API-route deploy workflows (`type: deploy`), see the `eas-hosting` skill. -## Web Deployment - -Deploy web apps on push to main: - -`.eas/workflows/deploy.yml` - -```yaml -name: Deploy - -on: - push: - branches: - - main - -# https://docs.expo.dev/eas/workflows/syntax/#deploy -jobs: - deploy_web: - type: deploy - params: - prod: true -``` - -## PR Previews - -### Web PR Previews - -```yaml -name: Web PR Preview - -on: - pull_request: - types: [opened, synchronize] - -jobs: - preview: - type: deploy - params: - prod: false -``` - -### Native PR Previews with EAS Updates +## PR Previews with EAS Update Deploy OTA updates for pull requests: diff --git a/plugins/expo/skills/expo-api-routes/SKILL.md b/plugins/expo/skills/eas-hosting/SKILL.md similarity index 77% rename from plugins/expo/skills/expo-api-routes/SKILL.md rename to plugins/expo/skills/eas-hosting/SKILL.md index 85cb198..988d677 100644 --- a/plugins/expo/skills/expo-api-routes/SKILL.md +++ b/plugins/expo/skills/eas-hosting/SKILL.md @@ -1,10 +1,16 @@ --- -name: expo-api-routes -description: Guidelines for creating API routes in Expo Router with EAS Hosting +name: eas-hosting +description: EAS service (paid). Deploy Expo websites and Expo Router API routes to EAS Hosting - export the web bundle, run eas deploy for production and PR preview URLs, manage environment secrets and custom domains, and work within the Cloudflare Workers runtime. Also covers authoring API routes (+api.ts handlers, HTTP methods, request handling, CORS). Use when deploying an Expo web app or API routes, setting up EAS Hosting, or configuring hosting environments and domains. Not for native builds or store releases - use the eas-app-stores skill for those. version: 1.0.0 license: MIT --- +# EAS Hosting + +> **EAS service - costs apply.** EAS Hosting is a paid Expo Application Services product with free-tier limits; production deploys use your plan's request and bandwidth allowance. See https://expo.dev/pricing. Authoring API routes and exporting the web bundle are free and open source, and you can self-host the exported server output instead of EAS Hosting. + +EAS Hosting deploys your Expo **web app and API routes** to Expo's managed edge (Cloudflare Workers). Export the web bundle with `npx expo export -p web` and ship it with `eas deploy` - the same command deploys any Expo Router API routes bundled alongside it. This skill covers deploying a website, authoring API routes, and the hosting runtime; see the Deployment section below for the deploy workflow. + ## When to Use API Routes Use API routes when you need: @@ -221,11 +227,20 @@ eas login ### Deploy +Deploying ships your web bundle and any Expo Router API routes together - `eas deploy` handles both. The export runs whether you have a full website, an API-routes-only backend, or both. + ```bash -eas deploy +# Export the web bundle (includes any API routes) +npx expo export -p web + +# Deploy a preview (PR-style URL) +npx eas-cli@latest deploy + +# Deploy to production +npx eas-cli@latest deploy --prod ``` -This builds and deploys your API routes to EAS Hosting (Cloudflare Workers). +Everything lands on EAS Hosting (Cloudflare Workers). ### Environment Variables for Production @@ -240,6 +255,46 @@ eas env:create --name OPENAI_API_KEY --value sk-xxx --environment production Configure in `eas.json` or Expo dashboard. +### Automate with EAS Workflows + +Deploy the website (and API routes) on every push to main with a `type: deploy` workflow: + +`.eas/workflows/deploy.yml` + +```yaml +name: Deploy + +on: + push: + branches: + - main + +# https://docs.expo.dev/eas/workflows/syntax/#deploy +jobs: + deploy_web: + type: deploy + params: + prod: true +``` + +Preview deploys for pull requests use the same job type with `prod: false`: + +```yaml +name: Web PR Preview + +on: + pull_request: + types: [opened, synchronize] + +jobs: + preview: + type: deploy + params: + prod: false +``` + +To author or validate workflow YAML beyond these examples, use the `eas-workflows` skill. + ## EAS Hosting Runtime (Cloudflare Workers) API routes run on Cloudflare Workers. Key limitations: diff --git a/plugins/expo/skills/eas-hosting/agents/openai.yaml b/plugins/expo/skills/eas-hosting/agents/openai.yaml new file mode 100644 index 0000000..a5b2bf1 --- /dev/null +++ b/plugins/expo/skills/eas-hosting/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "EAS Hosting" + short_description: "Paid EAS service. Deploy Expo websites and Expo Router API routes to EAS Hosting, with environment secrets, custom domains, and the Cloudflare Workers runtime" + default_prompt: "Use $eas-hosting to deploy an Expo web app or Expo Router API routes to EAS Hosting, author +api.ts route handlers, manage hosting environment secrets and custom domains, and work within the Cloudflare Workers runtime." diff --git a/plugins/expo/skills/expo-observe/SKILL.md b/plugins/expo/skills/eas-observe/SKILL.md similarity index 69% rename from plugins/expo/skills/expo-observe/SKILL.md rename to plugins/expo/skills/eas-observe/SKILL.md index 6e6c62a..4582bd2 100644 --- a/plugins/expo/skills/expo-observe/SKILL.md +++ b/plugins/expo/skills/eas-observe/SKILL.md @@ -1,12 +1,14 @@ --- -name: expo-observe -description: Use for anything related to EAS Observe — adding `expo-observe` to an Expo project (AppMetricsRoot/ObserveRoot HOC, markInteractive, the useObserve hook, the Expo Router / React Navigation integrations for per-route metrics, and user-defined events via `Observe.logEvent`), querying via the EAS CLI (`eas observe:metrics-summary`, `observe:metrics`, `observe:routes`, `observe:events`, `observe:versions`), or interpreting the resulting metrics (cold/warm launch, TTR, TTI, navigation cold/warm TTR, update download, and the TTI frameRate params for triaging slow startups). +name: eas-observe +description: EAS service (paid). Use for anything related to EAS Observe - adding `expo-observe` to an Expo project (AppMetricsRoot/ObserveRoot HOC, markInteractive, the useObserve hook, the Expo Router / React Navigation integrations for per-route metrics, and user-defined events via `Observe.logEvent`), querying via the EAS CLI (`eas observe:metrics-summary`, `observe:metrics`, `observe:routes`, `observe:events`, `observe:versions`), or interpreting the resulting metrics (cold/warm launch, TTR, TTI, navigation cold/warm TTR, update download, and the TTI frameRate params for triaging slow startups). version: 1.0.0 license: MIT --- # EAS Observe +> **EAS service - costs apply.** EAS Observe is a paid Expo Application Services product with free-tier limits. Ingesting and querying production metrics counts against your plan's event/usage allowance. Review https://expo.dev/pricing before enabling it in production. + EAS Observe tracks startup, navigation, and custom-event performance from production Expo apps. > **Source of truth:** https://docs.expo.dev/eas/observe/ — always consult the canonical docs when API details matter, especially get-started, configuration, integrations, and the metrics reference. EAS Observe is evolving; this skill's references are written to stay accurate but may lag the docs. diff --git a/plugins/expo/skills/eas-observe/agents/openai.yaml b/plugins/expo/skills/eas-observe/agents/openai.yaml new file mode 100644 index 0000000..9d5184f --- /dev/null +++ b/plugins/expo/skills/eas-observe/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "EAS Observe" + short_description: "Paid EAS service. Set up expo-observe app metrics and query launch, route, event, and version performance with the EAS CLI" + default_prompt: "Use $eas-observe to add expo-observe instrumentation (AppMetricsRoot/ObserveRoot, useObserve, the router integrations), query metrics with eas observe:* commands, and interpret cold/warm launch, TTR, and TTI results." diff --git a/plugins/expo/skills/expo-observe/references/metrics.md b/plugins/expo/skills/eas-observe/references/metrics.md similarity index 100% rename from plugins/expo/skills/expo-observe/references/metrics.md rename to plugins/expo/skills/eas-observe/references/metrics.md diff --git a/plugins/expo/skills/expo-observe/references/queries.md b/plugins/expo/skills/eas-observe/references/queries.md similarity index 100% rename from plugins/expo/skills/expo-observe/references/queries.md rename to plugins/expo/skills/eas-observe/references/queries.md diff --git a/plugins/expo/skills/expo-observe/references/setup.md b/plugins/expo/skills/eas-observe/references/setup.md similarity index 100% rename from plugins/expo/skills/expo-observe/references/setup.md rename to plugins/expo/skills/eas-observe/references/setup.md diff --git a/plugins/expo/skills/eas-simulator/SKILL.md b/plugins/expo/skills/eas-simulator/SKILL.md index e57a7fd..6456152 100644 --- a/plugins/expo/skills/eas-simulator/SKILL.md +++ b/plugins/expo/skills/eas-simulator/SKILL.md @@ -1,6 +1,6 @@ --- name: eas-simulator -description: "Run and control a user's app on a remote iOS/Android simulator hosted on EAS cloud. Always read before executing any `eas simulator:*` commands — it has the current syntax for this experimental API. Use whenever the user needs a simulator they can't run locally — 'run my app on a cloud simulator', 'use eas simulator to run/install/screenshot my app', 'I'm on Linux/Cursor and need an iOS device', 'no sim on this box / headless CI', 'let an agent click through my app and screenshot it', 'test my dev build on a remote sim with live reload', 'stream a sim's screen to my browser' — even when they don't say 'EAS Simulator' or 'cloud'. On a host WITHOUT a local simulator (Linux, CI, cloud sandbox) it's the default — just use it; on macOS, do NOT auto-trigger for a plain 'run on the simulator' — use it only for a cloud/remote/shareable sim, an iOS version they lack, or an agent-driven session. NOT for local sims (expo run:ios, Xcode, Android Studio), EAS Build/Update, web preview, or physical devices." +description: "EAS service (paid). Run and control a user's app on a remote iOS/Android simulator hosted on EAS cloud. Read before running any `eas simulator:*` commands - it has the current syntax for this experimental API. Use whenever the user needs a simulator they can't run locally - 'run my app on a cloud simulator', 'use eas simulator to run/install/screenshot my app', 'I'm on Linux/Cursor and need an iOS device', 'no sim on this box / headless CI', 'let an agent click through my app and screenshot it', 'test my dev build on a remote sim with live reload', 'stream a sim to my browser' - even when they don't say 'EAS Simulator' or 'cloud'. On a host WITHOUT a local simulator (Linux, CI, cloud sandbox) it's the default; on macOS, do NOT auto-trigger for a plain 'run on the simulator' - use it only for a cloud/remote/shareable sim, an iOS version they lack, or an agent-driven session. NOT for local sims (expo run:ios, Xcode, Android Studio), EAS Build/Update, web preview, or physical devices." version: 1.0.0 license: MIT allowed-tools: "Bash(npx *eas-cli@*), Bash(npx *agent-device@*), Bash(npx expo *), Bash(eas *), Bash(expo *), Bash(xcodebuild*), Bash(pod*)" @@ -8,6 +8,8 @@ allowed-tools: "Bash(npx *eas-cli@*), Bash(npx *agent-device@*), Bash(npx expo * # EAS Simulator +> **EAS service - costs apply.** EAS Simulator runs on Expo Application Services cloud infrastructure, a paid product with free-tier limits; remote simulator sessions use your plan's compute allowance. See https://expo.dev/pricing. + EAS Simulator runs a remote iOS simulator or Android emulator on EAS infrastructure that you drive from your machine — from the CLI, from an AI agent (via `agent-device`), and from a browser preview. It's the unlock for **environments that can't run a simulator locally** (Linux boxes, cloud/background agents like Cursor Cloud), and for letting an agent *verify* a change on a real device instead of only reasoning about code. The `simulator:*` commands are **experimental and hidden**, and need a recent eas-cli (≥ 20.3.0 as of writing) — which is why this skill runs everything via `npx --yes eas-cli@latest`. Flags and verbs may change; if a command fails, **` --help` is authoritative.** diff --git a/plugins/expo/skills/eas-simulator/agents/openai.yaml b/plugins/expo/skills/eas-simulator/agents/openai.yaml new file mode 100644 index 0000000..dc3573b --- /dev/null +++ b/plugins/expo/skills/eas-simulator/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "EAS Simulator" + short_description: "Paid EAS service. Run and drive your app on a remote iOS/Android simulator on EAS cloud, from the CLI or an agent, with a live browser preview" + default_prompt: "Use $eas-simulator to run, install, screenshot, and drive an app on a remote EAS cloud simulator - especially when no local simulator is available (Linux, CI, cloud agents) or a shareable browser preview is needed." diff --git a/plugins/expo/skills/eas-update-insights/SKILL.md b/plugins/expo/skills/eas-update-insights/SKILL.md index 840673e..b6f1b4d 100644 --- a/plugins/expo/skills/eas-update-insights/SKILL.md +++ b/plugins/expo/skills/eas-update-insights/SKILL.md @@ -1,6 +1,6 @@ --- name: eas-update-insights -description: "Check the health of published EAS Updates: crash rates, install/launch counts, unique users, payload size, and the split between embedded and OTA users per channel. Use when the user asks how an update is performing, whether a rollout is healthy, how many users are on the embedded build vs OTA, or wants to gate CI on update health." +description: "EAS service (paid). Check the health of published EAS Update: crash rates, install/launch counts, unique users, payload size, and the split between embedded and OTA users per channel. Use when the user asks how an update is performing, whether a rollout is healthy, how many users are on the embedded build vs OTA, or wants to gate CI on update health." version: 1.0.0 license: MIT allowed-tools: "Bash(eas *)" @@ -8,7 +8,9 @@ allowed-tools: "Bash(eas *)" # EAS Update Insights -Query the health of published EAS Updates directly from the CLI: launches, failed launches, crash rates, unique users, payload size, the embedded-vs-OTA user split per channel, and the most popular updates per runtime version. The data is the same data that powers the update and channel detail pages on expo.dev; these commands expose it in the terminal in human and JSON form. +> **EAS service - costs apply.** Insights cover updates published through EAS Update, a paid Expo Application Services product with free-tier limits. Update delivery and the data behind these commands count against your plan's EAS Update usage. Review https://expo.dev/pricing. + +Query the health of published EAS Update directly from the CLI: launches, failed launches, crash rates, unique users, payload size, the embedded-vs-OTA user split per channel, and the most popular updates per runtime version. The data is the same data that powers the update and channel detail pages on expo.dev; these commands expose it in the terminal in human and JSON form. ## When to use this skill diff --git a/plugins/expo/skills/eas-update-insights/agents/openai.yaml b/plugins/expo/skills/eas-update-insights/agents/openai.yaml index 29a5807..b838395 100644 --- a/plugins/expo/skills/eas-update-insights/agents/openai.yaml +++ b/plugins/expo/skills/eas-update-insights/agents/openai.yaml @@ -1,4 +1,4 @@ interface: display_name: "EAS Update Insights" - short_description: "Check EAS Update health, adoption, crash rates, launch counts, payload size, and OTA vs embedded usage" - default_prompt: "Use $eas-update-insights to inspect published EAS Updates with eas-cli, compare rollout health, gather update or channel metrics, parse JSON output, and gate releases on aggregate update performance." + short_description: "Paid EAS service. Check EAS Update health, adoption, crash rates, launch counts, payload size, and OTA vs embedded usage" + default_prompt: "Use $eas-update-insights to inspect published EAS Update with eas-cli, compare rollout health, gather update or channel metrics, parse JSON output, and gate releases on aggregate update performance." diff --git a/plugins/expo/skills/expo-cicd-workflows/SKILL.md b/plugins/expo/skills/eas-workflows/SKILL.md similarity index 83% rename from plugins/expo/skills/expo-cicd-workflows/SKILL.md rename to plugins/expo/skills/eas-workflows/SKILL.md index ed0c96b..188581d 100644 --- a/plugins/expo/skills/expo-cicd-workflows/SKILL.md +++ b/plugins/expo/skills/eas-workflows/SKILL.md @@ -1,6 +1,6 @@ --- -name: expo-cicd-workflows -description: Helps understand and write EAS workflow YAML files for Expo projects. Use this skill when the user asks about CI/CD or workflows in an Expo or EAS context, mentions .eas/workflows/, or wants help with EAS build pipelines or deployment automation. +name: eas-workflows +description: EAS service (paid). Helps understand and write EAS workflow YAML files for Expo projects. Use this skill when the user asks about CI/CD or workflows in an Expo or EAS context, mentions .eas/workflows/, or wants help with EAS build pipelines or deployment automation. allowed-tools: "Read,Write,Bash(node:*)" version: 1.0.0 license: MIT License @@ -8,6 +8,8 @@ license: MIT License # EAS Workflows Skill +> **EAS service - costs apply.** EAS Workflows run on Expo Application Services, a paid product with free-tier limits. Each workflow job consumes your plan's build/compute minutes, and jobs that build or submit also need paid Apple Developer and Google Play accounts. Review https://expo.dev/pricing before triggering runs. + Help developers write and edit EAS CI/CD workflow YAML files. ## Reference Documentation diff --git a/plugins/expo/skills/eas-workflows/agents/openai.yaml b/plugins/expo/skills/eas-workflows/agents/openai.yaml new file mode 100644 index 0000000..2b280ec --- /dev/null +++ b/plugins/expo/skills/eas-workflows/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "EAS Workflows" + short_description: "Paid EAS service. Write and validate EAS workflow YAML files for Expo projects" + default_prompt: "Use $eas-workflows when creating or editing .eas/workflows YAML, validating EAS workflow configuration, or answering questions about workflow triggers, jobs, runners, and expressions." diff --git a/plugins/expo/skills/expo-cicd-workflows/scripts/fetch.js b/plugins/expo/skills/eas-workflows/scripts/fetch.js similarity index 100% rename from plugins/expo/skills/expo-cicd-workflows/scripts/fetch.js rename to plugins/expo/skills/eas-workflows/scripts/fetch.js diff --git a/plugins/expo/skills/expo-cicd-workflows/scripts/package.json b/plugins/expo/skills/eas-workflows/scripts/package.json similarity index 100% rename from plugins/expo/skills/expo-cicd-workflows/scripts/package.json rename to plugins/expo/skills/eas-workflows/scripts/package.json diff --git a/plugins/expo/skills/expo-cicd-workflows/scripts/validate.js b/plugins/expo/skills/eas-workflows/scripts/validate.js similarity index 100% rename from plugins/expo/skills/expo-cicd-workflows/scripts/validate.js rename to plugins/expo/skills/eas-workflows/scripts/validate.js diff --git a/plugins/expo/skills/expo-api-routes/agents/openai.yaml b/plugins/expo/skills/expo-api-routes/agents/openai.yaml deleted file mode 100644 index 831a4aa..0000000 --- a/plugins/expo/skills/expo-api-routes/agents/openai.yaml +++ /dev/null @@ -1,4 +0,0 @@ -interface: - display_name: "Expo API Routes" - short_description: "Create Expo Router API routes for server-side secrets, validation, webhooks, proxies, and EAS Hosting" - default_prompt: "Use $expo-api-routes to design, implement, test, and deploy Expo Router API routes, especially when secrets or server-side validation must stay out of the client." diff --git a/plugins/expo/skills/add-app-clip/SKILL.md b/plugins/expo/skills/expo-app-clip/SKILL.md similarity index 92% rename from plugins/expo/skills/add-app-clip/SKILL.md rename to plugins/expo/skills/expo-app-clip/SKILL.md index bc502be..2a510d4 100644 --- a/plugins/expo/skills/add-app-clip/SKILL.md +++ b/plugins/expo/skills/expo-app-clip/SKILL.md @@ -1,10 +1,12 @@ --- -name: add-app-clip -description: Add an iOS App Clip target to an Expo app. Use when the user mentions App Clip, AASA, apple-app-site-association, appclips, smart app banner, or wants to ship a lightweight iOS Clip invoked from a URL alongside their parent app. +name: expo-app-clip +description: Framework (OSS). Add an iOS App Clip target to an Expo app. Use when the user mentions App Clip, AASA, apple-app-site-association, appclips, smart app banner, or wants to ship a lightweight iOS Clip invoked from a URL alongside their parent app. --- # Add an App Clip to an Expo App +> **Requirements.** Adding the App Clip target is open source. Shipping one requires an Apple Developer Program membership and App Store review, and the AASA file must be served over HTTPS on your domain (any HTTPS host works; EAS Hosting is one option). Building via EAS Build or `bunx testflight` uses your EAS plan's build minutes. See https://expo.dev/pricing and https://developer.apple.com/app-clips/. + Adds an iOS App Clip target to an Expo project. The Clip lives in `targets/clip/`, ships alongside the parent app, and is invoked from a URL on the app's domain via an Apple App Site Association (AASA) file. The parent app's bundle ID becomes `com..` and the Clip's is automatically derived as `.clip` (e.g. `com.bacon.may20.clip`). diff --git a/plugins/expo/skills/expo-app-clip/agents/openai.yaml b/plugins/expo/skills/expo-app-clip/agents/openai.yaml new file mode 100644 index 0000000..41a76e1 --- /dev/null +++ b/plugins/expo/skills/expo-app-clip/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Expo App Clip" + short_description: "Add an iOS App Clip target to an Expo app with AASA, associated domains, and TestFlight setup (needs an Apple Developer account)" + default_prompt: "Use $expo-app-clip when adding or reviewing an iOS App Clip target for an Expo app, including bundle IDs, associated domains, AASA files, smart app banners, App Store Connect setup, and TestFlight verification." diff --git a/plugins/expo/skills/add-app-clip/references/native-module.md b/plugins/expo/skills/expo-app-clip/references/native-module.md similarity index 100% rename from plugins/expo/skills/add-app-clip/references/native-module.md rename to plugins/expo/skills/expo-app-clip/references/native-module.md diff --git a/plugins/expo/skills/expo-brownfield/SKILL.md b/plugins/expo/skills/expo-brownfield/SKILL.md index bbd0c62..d8d1d97 100644 --- a/plugins/expo/skills/expo-brownfield/SKILL.md +++ b/plugins/expo/skills/expo-brownfield/SKILL.md @@ -1,6 +1,6 @@ --- name: expo-brownfield -description: Integrate Expo and React Native into an existing native iOS or Android app. Use when the user mentions brownfield, embedding React Native in a native app, AAR/XCFramework, or adding Expo to an existing Kotlin/Swift project. Covers both the isolated approach and the integrated approach. +description: Framework (OSS). Integrate Expo and React Native into an existing native iOS or Android app. Use when the user mentions brownfield, embedding React Native in a native app, AAR/XCFramework, or adding Expo to an existing Kotlin/Swift project. Covers both the isolated approach and the integrated approach. --- # Expo Brownfield diff --git a/plugins/expo/skills/expo-brownfield/references/brownfield-integrated.md b/plugins/expo/skills/expo-brownfield/references/brownfield-integrated.md index 6878f5f..dcbcbb2 100644 --- a/plugins/expo/skills/expo-brownfield/references/brownfield-integrated.md +++ b/plugins/expo/skills/expo-brownfield/references/brownfield-integrated.md @@ -508,7 +508,7 @@ Start Metro from the Expo project (or `yarn start` from the monorepo root): yarn start ``` -Build and run the native app normally (Android Studio / Xcode). Navigate to your React Native–powered Activity or screen — it loads JS from the Metro dev server with hot reloading. +Build and run the native app normally (Android Studio / Xcode). Navigate to your React Native-powered Activity or screen - it loads JS from the Metro dev server with hot reloading. ### Development vs. production diff --git a/plugins/expo/skills/expo-cicd-workflows/agents/openai.yaml b/plugins/expo/skills/expo-cicd-workflows/agents/openai.yaml deleted file mode 100644 index c0bbc18..0000000 --- a/plugins/expo/skills/expo-cicd-workflows/agents/openai.yaml +++ /dev/null @@ -1,4 +0,0 @@ -interface: - display_name: "Expo CI/CD Workflows" - short_description: "Write and validate EAS workflow YAML files for Expo projects" - default_prompt: "Use $expo-cicd-workflows when creating or editing .eas/workflows YAML, validating EAS workflow configuration, or answering questions about workflow triggers, jobs, runners, and expressions." diff --git a/plugins/expo/skills/native-data-fetching/SKILL.md b/plugins/expo/skills/expo-data-fetching/SKILL.md similarity index 86% rename from plugins/expo/skills/native-data-fetching/SKILL.md rename to plugins/expo/skills/expo-data-fetching/SKILL.md index b0b4e70..191a767 100644 --- a/plugins/expo/skills/native-data-fetching/SKILL.md +++ b/plugins/expo/skills/expo-data-fetching/SKILL.md @@ -1,6 +1,6 @@ --- -name: native-data-fetching -description: Use when implementing or debugging ANY network request, API call, or data fetching. Covers fetch API, React Query, SWR, error handling, caching, offline support, and Expo Router data loaders (`useLoaderData`). +name: expo-data-fetching +description: Framework (OSS). Use when implementing or debugging ANY network request, API call, or data fetching. Covers fetch API, React Query, SWR, error handling, caching, offline support, and Expo Router data loaders (`useLoaderData`). version: 1.0.0 license: MIT --- @@ -15,7 +15,8 @@ Consult these resources as needed: ``` references/ - expo-router-loaders.md Route-level data loading with Expo Router loaders (web, SDK 55+) + expo-router-loaders.md Route-level data loading with Expo Router loaders (web, SDK 55+) + offline-and-cancellation.md NetInfo network status, offline-first React Query, AbortController ``` ## When to Use @@ -262,40 +263,7 @@ const getValidToken = async (): Promise => { ### 5. Offline Support -**Check network status**: - -```tsx -import NetInfo from "@react-native-community/netinfo"; - -// Hook for network status -function useNetworkStatus() { - const [isOnline, setIsOnline] = useState(true); - - useEffect(() => { - return NetInfo.addEventListener((state) => { - setIsOnline(state.isConnected ?? true); - }); - }, []); - - return isOnline; -} -``` - -**Offline-first with React Query**: - -```tsx -import { onlineManager } from "@tanstack/react-query"; -import NetInfo from "@react-native-community/netinfo"; - -// Sync React Query with network status -onlineManager.setEventListener((setOnline) => { - return NetInfo.addEventListener((state) => { - setOnline(state.isConnected ?? true); - }); -}); - -// Queries will pause when offline and resume when online -``` +Network-status detection with NetInfo and offline-first React Query setup: see [./references/offline-and-cancellation.md](./references/offline-and-cancellation.md). --- @@ -386,31 +354,7 @@ export {}; ### 7. Request Cancellation -**Cancel on unmount**: - -```tsx -useEffect(() => { - const controller = new AbortController(); - - fetch(url, { signal: controller.signal }) - .then((response) => response.json()) - .then(setData) - .catch((error) => { - if (error.name !== "AbortError") { - setError(error); - } - }); - - return () => controller.abort(); -}, [url]); -``` - -**With React Query** (automatic): - -```tsx -// React Query automatically cancels requests when queries are invalidated -// or components unmount -``` +AbortController on unmount (React Query cancels automatically): see [./references/offline-and-cancellation.md](./references/offline-and-cancellation.md). --- diff --git a/plugins/expo/skills/expo-data-fetching/agents/openai.yaml b/plugins/expo/skills/expo-data-fetching/agents/openai.yaml new file mode 100644 index 0000000..8e942bc --- /dev/null +++ b/plugins/expo/skills/expo-data-fetching/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Expo Data Fetching" + short_description: "Implement and debug Expo network requests, caching, auth, offline support, and Expo Router data loaders" + default_prompt: "Use $expo-data-fetching for Expo data fetching work: fetch wrappers, React Query or SWR setup, error handling, retry/cancellation, authenticated requests, environment-based API URLs, offline behavior, and Expo Router loaders." diff --git a/plugins/expo/skills/native-data-fetching/references/expo-router-loaders.md b/plugins/expo/skills/expo-data-fetching/references/expo-router-loaders.md similarity index 100% rename from plugins/expo/skills/native-data-fetching/references/expo-router-loaders.md rename to plugins/expo/skills/expo-data-fetching/references/expo-router-loaders.md diff --git a/plugins/expo/skills/expo-data-fetching/references/offline-and-cancellation.md b/plugins/expo/skills/expo-data-fetching/references/offline-and-cancellation.md new file mode 100644 index 0000000..596bbed --- /dev/null +++ b/plugins/expo/skills/expo-data-fetching/references/offline-and-cancellation.md @@ -0,0 +1,68 @@ +# Offline Support & Request Cancellation + +Companion reference for `expo-data-fetching`. + +## Offline Support + +**Check network status**: + +```tsx +import NetInfo from "@react-native-community/netinfo"; + +// Hook for network status +function useNetworkStatus() { + const [isOnline, setIsOnline] = useState(true); + + useEffect(() => { + return NetInfo.addEventListener((state) => { + setIsOnline(state.isConnected ?? true); + }); + }, []); + + return isOnline; +} +``` + +**Offline-first with React Query**: + +```tsx +import { onlineManager } from "@tanstack/react-query"; +import NetInfo from "@react-native-community/netinfo"; + +// Sync React Query with network status +onlineManager.setEventListener((setOnline) => { + return NetInfo.addEventListener((state) => { + setOnline(state.isConnected ?? true); + }); +}); + +// Queries will pause when offline and resume when online +``` + +## Request Cancellation + +**Cancel on unmount**: + +```tsx +useEffect(() => { + const controller = new AbortController(); + + fetch(url, { signal: controller.signal }) + .then((response) => response.json()) + .then(setData) + .catch((error) => { + if (error.name !== "AbortError") { + setError(error); + } + }); + + return () => controller.abort(); +}, [url]); +``` + +**With React Query** (automatic): + +```tsx +// React Query automatically cancels requests when queries are invalidated +// or components unmount +``` diff --git a/plugins/expo/skills/expo-deployment/agents/openai.yaml b/plugins/expo/skills/expo-deployment/agents/openai.yaml deleted file mode 100644 index f8cc706..0000000 --- a/plugins/expo/skills/expo-deployment/agents/openai.yaml +++ /dev/null @@ -1,4 +0,0 @@ -interface: - display_name: "Expo Deployment" - short_description: "Deploy Expo apps to TestFlight, App Store, Play Store, EAS Hosting, and API routes" - default_prompt: "Use $expo-deployment when preparing production EAS builds, store submissions, web deploys, TestFlight distribution, app-store metadata, version management, or deployment workflows for an Expo app." diff --git a/plugins/expo/skills/expo-dev-client/SKILL.md b/plugins/expo/skills/expo-dev-client/SKILL.md index 2ca044e..8e1e9f7 100644 --- a/plugins/expo/skills/expo-dev-client/SKILL.md +++ b/plugins/expo/skills/expo-dev-client/SKILL.md @@ -1,12 +1,14 @@ --- name: expo-dev-client -description: Build Expo app for development +description: Framework (OSS). Build and distribute Expo development clients locally or via TestFlight for internal testing. For production TestFlight releases and store submission, use the eas-app-stores skill. version: 1.1.0 license: MIT --- Use EAS Build to create development clients for testing native code changes on physical devices. Use this for creating custom Expo Go clients for testing branches of your app. +> **Free locally; cloud builds are paid.** `expo-dev-client` itself is open source and building locally is free. Building or distributing via EAS Build/TestFlight uses your EAS plan's build minutes and needs a paid Apple Developer account for device/TestFlight distribution. See https://expo.dev/pricing. + ## Important: When Development Clients Are Needed **Development clients are the recommended setup for any real or production app.** Expo Go is a playground for learning and quick experiments with the native libraries it bundles; most apps outgrow it and move to a development client. See [Expo Go vs. development builds](https://docs.expo.dev/develop/development-builds/introduction/) for the full reasoning. diff --git a/plugins/expo/skills/use-dom/SKILL.md b/plugins/expo/skills/expo-dom/SKILL.md similarity index 97% rename from plugins/expo/skills/use-dom/SKILL.md rename to plugins/expo/skills/expo-dom/SKILL.md index b11eafa..f9dfd1b 100644 --- a/plugins/expo/skills/use-dom/SKILL.md +++ b/plugins/expo/skills/expo-dom/SKILL.md @@ -1,6 +1,6 @@ --- -name: use-dom -description: Use Expo DOM components to run web code in a webview on native and as-is on web. Migrate web code to native incrementally. +name: expo-dom +description: Framework (OSS). Use Expo DOM components to run web code in a webview on native and as-is on web. Migrate web code to native incrementally. For the end-to-end migration of a whole web app, use the expo-web-to-native skill. version: 1.0.0 license: MIT --- diff --git a/plugins/expo/skills/expo-dom/agents/openai.yaml b/plugins/expo/skills/expo-dom/agents/openai.yaml new file mode 100644 index 0000000..ed8c91c --- /dev/null +++ b/plugins/expo/skills/expo-dom/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Expo DOM Components" + short_description: "Use Expo DOM components to run web React code in native webviews and unchanged on web" + default_prompt: "Use $expo-dom to migrate web components into Expo via 'use dom', configure DOM props, expose native actions safely, use web-only libraries, and keep DOM components separate from native routes." diff --git a/plugins/expo/skills/expo-examples/SKILL.md b/plugins/expo/skills/expo-examples/SKILL.md index cb22926..edc49c9 100644 --- a/plugins/expo/skills/expo-examples/SKILL.md +++ b/plugins/expo/skills/expo-examples/SKILL.md @@ -1,6 +1,6 @@ --- name: expo-examples -description: Expo's official example projects — the expo/examples repo of ~70 `with-*` integrations (Stripe, Clerk, Supabase, OpenAI, maps, Reanimated, SQLite, Skia, NativeWind, and more). Use when integrating a third-party library or service into an existing Expo app and you want the canonical, version-matched pattern to adapt, or when scaffolding a new project from one with `npx create-expo --example`. +description: Framework (OSS). Expo's official example projects - the expo/examples repo of ~70 `with-*` integrations (Stripe, Clerk, Supabase, OpenAI, maps, Reanimated, SQLite, Skia, NativeWind, and more). Use when integrating a third-party library or service into an existing Expo app and you want the canonical, version-matched pattern to adapt, or when scaffolding a new project from one with `npx create-expo --example`. allowed-tools: "Read,Bash(gh api:*),Bash(git clone:*),Bash(npx create-expo:*),Bash(npx degit:*),Bash(bun create:*)" version: 1.0.0 license: MIT @@ -88,10 +88,11 @@ When the user already has an app, **add only what the example introduces; never ## Related skills - Tailwind / NativeWind styling → `expo-tailwind-setup` -- Native UI components → `building-native-ui` +- Native UI components (@expo/ui package) → `expo-ui` +- Styling and native-feeling screens → `expo-native-ui` - Navigation and routing → `expo-router` - Authoring a native module → `expo-module` -- Upgrade the SDK before adopting a latest-SDK example → `upgrading-expo` +- Upgrade the SDK before adopting a latest-SDK example → `expo-upgrade` ## References diff --git a/plugins/expo/skills/expo-examples/agents/openai.yaml b/plugins/expo/skills/expo-examples/agents/openai.yaml new file mode 100644 index 0000000..d68fe29 --- /dev/null +++ b/plugins/expo/skills/expo-examples/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Expo Examples" + short_description: "Adapt or scaffold from the expo/examples repo of with-* integrations (Stripe, Clerk, Supabase, maps, SQLite, and more)" + default_prompt: "Use $expo-examples when integrating a third-party library or service into an Expo app to find the canonical with-* example to adapt, or to scaffold a new project with npx create-expo --example." diff --git a/plugins/expo/skills/expo-module/SKILL.md b/plugins/expo/skills/expo-module/SKILL.md index dbd2f29..0b3063d 100644 --- a/plugins/expo/skills/expo-module/SKILL.md +++ b/plugins/expo/skills/expo-module/SKILL.md @@ -1,6 +1,6 @@ --- name: expo-module -description: Guide for creating and writing Expo native modules and views using the Expo Modules API (Swift, Kotlin, TypeScript). Covers module definition DSL, native views, shared objects, config plugins, lifecycle hooks, autolinking, and type system. Use when building or modifying native modules for Expo. +description: Framework (OSS). Guide for creating and writing Expo native modules and views using the Expo Modules API (Swift, Kotlin, TypeScript). Covers module definition DSL, native views, shared objects, config plugins, lifecycle hooks, autolinking, and type system. Use when building or modifying native modules for Expo. version: 1.0.0 license: MIT --- diff --git a/plugins/expo/skills/building-native-ui/SKILL.md b/plugins/expo/skills/expo-native-ui/SKILL.md similarity index 95% rename from plugins/expo/skills/building-native-ui/SKILL.md rename to plugins/expo/skills/expo-native-ui/SKILL.md index 44ceb2b..4b1024a 100644 --- a/plugins/expo/skills/building-native-ui/SKILL.md +++ b/plugins/expo/skills/expo-native-ui/SKILL.md @@ -1,11 +1,11 @@ --- -name: building-native-ui -description: Build beautiful, native-feeling Expo screens. Covers Apple HIG styling, semantic colors, native controls, SF Symbols, media, animations, visual effects, gradients, storage, and responsive layout. For routing and navigation, use the expo-router skill. -version: 1.1.0 +name: expo-native-ui +description: Framework (OSS). Build beautiful, native-feeling Expo screens. Covers Apple HIG styling, semantic colors, native controls, SF Symbols, media, animations, visual effects, gradients, storage, and responsive layout. For routing and navigation, use the expo-router skill. +version: 1.1.1 license: MIT --- -# Expo UI Guidelines +# Expo Native UI Guidelines For routes, links, stacks, tabs, modals, sheets, and headers, use the `expo-router` skill. diff --git a/plugins/expo/skills/expo-native-ui/agents/openai.yaml b/plugins/expo/skills/expo-native-ui/agents/openai.yaml new file mode 100644 index 0000000..bcd8e32 --- /dev/null +++ b/plugins/expo/skills/expo-native-ui/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Expo Native UI" + short_description: "Build beautiful, native-feeling Expo screens: HIG styling, semantic colors, controls, SF Symbols, media, animation, and visual effects" + default_prompt: "Use $expo-native-ui to style native-feeling Expo screens, choose semantic colors and native controls, add media, animations, and visual effects, and decide when Expo Go is enough before creating native builds." diff --git a/plugins/expo/skills/building-native-ui/references/animations.md b/plugins/expo/skills/expo-native-ui/references/animations.md similarity index 100% rename from plugins/expo/skills/building-native-ui/references/animations.md rename to plugins/expo/skills/expo-native-ui/references/animations.md diff --git a/plugins/expo/skills/building-native-ui/references/controls.md b/plugins/expo/skills/expo-native-ui/references/controls.md similarity index 100% rename from plugins/expo/skills/building-native-ui/references/controls.md rename to plugins/expo/skills/expo-native-ui/references/controls.md diff --git a/plugins/expo/skills/building-native-ui/references/gradients.md b/plugins/expo/skills/expo-native-ui/references/gradients.md similarity index 100% rename from plugins/expo/skills/building-native-ui/references/gradients.md rename to plugins/expo/skills/expo-native-ui/references/gradients.md diff --git a/plugins/expo/skills/building-native-ui/references/icons.md b/plugins/expo/skills/expo-native-ui/references/icons.md similarity index 100% rename from plugins/expo/skills/building-native-ui/references/icons.md rename to plugins/expo/skills/expo-native-ui/references/icons.md diff --git a/plugins/expo/skills/building-native-ui/references/media.md b/plugins/expo/skills/expo-native-ui/references/media.md similarity index 100% rename from plugins/expo/skills/building-native-ui/references/media.md rename to plugins/expo/skills/expo-native-ui/references/media.md diff --git a/plugins/expo/skills/building-native-ui/references/storage.md b/plugins/expo/skills/expo-native-ui/references/storage.md similarity index 100% rename from plugins/expo/skills/building-native-ui/references/storage.md rename to plugins/expo/skills/expo-native-ui/references/storage.md diff --git a/plugins/expo/skills/building-native-ui/references/visual-effects.md b/plugins/expo/skills/expo-native-ui/references/visual-effects.md similarity index 100% rename from plugins/expo/skills/building-native-ui/references/visual-effects.md rename to plugins/expo/skills/expo-native-ui/references/visual-effects.md diff --git a/plugins/expo/skills/building-native-ui/references/webgpu-three.md b/plugins/expo/skills/expo-native-ui/references/webgpu-three.md similarity index 100% rename from plugins/expo/skills/building-native-ui/references/webgpu-three.md rename to plugins/expo/skills/expo-native-ui/references/webgpu-three.md diff --git a/plugins/expo/skills/expo-router/SKILL.md b/plugins/expo/skills/expo-router/SKILL.md index df98c81..1829df8 100644 --- a/plugins/expo/skills/expo-router/SKILL.md +++ b/plugins/expo/skills/expo-router/SKILL.md @@ -1,13 +1,13 @@ --- name: expo-router -description: Navigation and routing for Expo Router. Covers file-based routes, groups and dynamic routes, folder organization, Link with previews and context menus, native Stack, page titles, modals and form sheets, NativeTabs, headers and toolbars, and header search bars. -version: 1.0.0 +description: Framework (OSS). Navigation and routing for Expo Router. Covers file-based routes, groups and dynamic routes, folder organization, Link with previews and context menus, native Stack, page titles, modals and form sheets, NativeTabs, headers and toolbars, and header search bars. +version: 1.0.1 license: MIT --- # Expo Router Navigation -Navigation and routing for Expo Router apps. For screen styling, colors, controls, animations, media, and visual effects, use the `building-native-ui` skill. +Navigation and routing for Expo Router apps. For screen styling, colors, controls, animations, media, and visual effects, use the `expo-native-ui` skill. ## References @@ -40,7 +40,7 @@ See `./references/route-structure.md` for detailed route conventions. ## Library Preferences -- `Color` from `expo-router` for native semantic colors, not raw `PlatformColor` (type-safe, auto-adapts to light/dark). See `building-native-ui` for the full color palette pattern. +- `Color` from `expo-router` for native semantic colors, not raw `PlatformColor` (type-safe, auto-adapts to light/dark). See `expo-native-ui` for the full color palette pattern. - In SDK 56+, never import from `@react-navigation/*` directly — use `expo-router/react-navigation` instead (covers `@react-navigation/native`, `/core`, `/elements`, `/routers`) ## Behavior diff --git a/plugins/expo/skills/expo-tailwind-setup/SKILL.md b/plugins/expo/skills/expo-tailwind-setup/SKILL.md index d37fe32..7afa7f0 100644 --- a/plugins/expo/skills/expo-tailwind-setup/SKILL.md +++ b/plugins/expo/skills/expo-tailwind-setup/SKILL.md @@ -1,6 +1,6 @@ --- name: expo-tailwind-setup -description: Set up Tailwind CSS v4 in Expo with react-native-css and NativeWind v5 for universal styling +description: Framework (OSS). Set up Tailwind CSS v4 in Expo with react-native-css and NativeWind v5 for universal styling version: 1.0.0 license: MIT --- diff --git a/plugins/expo/skills/expo-ui/SKILL.md b/plugins/expo/skills/expo-ui/SKILL.md index fd59c8c..2c14a82 100644 --- a/plugins/expo/skills/expo-ui/SKILL.md +++ b/plugins/expo/skills/expo-ui/SKILL.md @@ -1,6 +1,6 @@ --- name: expo-ui -description: "Build native UI with the @expo/ui package: real SwiftUI on iOS and Jetpack Compose on Android rendered from React in an Expo or React Native app. Covers universal cross-platform components (Host, Column, Row, Button, Text, List, and more imported from @expo/ui), drop-in replacements for popular React Native community libraries (BottomSheet, DateTimePicker, Slider, Menu, etc.), and platform-specific SwiftUI (@expo/ui/swift-ui, iOS only) and Jetpack Compose (@expo/ui/jetpack-compose, Android only) trees and modifiers. Use when adding or reviewing @expo/ui Host/RNHostView trees, building native-feeling UI where standard React Native components fall short (grouped settings forms with toggles, sections, menus, sheets, pickers, sliders), choosing between universal and platform-specific components, or replacing an RN community UI library with a native @expo/ui equivalent. Not for custom native modules, Expo Router navigation, Reanimated, or data fetching." +description: "Framework (OSS). Build native UI with the @expo/ui package: real SwiftUI on iOS and Jetpack Compose on Android rendered from React in an Expo or React Native app. Covers universal cross-platform components (Host, Column, Row, Button, Text, List, and more imported from @expo/ui), drop-in replacements for popular React Native community libraries (BottomSheet, DateTimePicker, Slider, Menu, etc.), and platform-specific SwiftUI (@expo/ui/swift-ui, iOS only) and Jetpack Compose (@expo/ui/jetpack-compose, Android only) trees and modifiers. Use when adding or reviewing @expo/ui Host/RNHostView trees, building native-feeling UI where standard React Native components fall short (grouped settings forms with toggles, sections, menus, sheets, pickers, sliders), choosing between universal and platform-specific components, or replacing an RN community UI library with a native @expo/ui equivalent. Not for custom native modules, Expo Router navigation, Reanimated, or data fetching." version: 1.0.0 license: MIT allowed-tools: "Bash(node *expo-ui/scripts/list-components.js *)" diff --git a/plugins/expo/skills/upgrading-expo/SKILL.md b/plugins/expo/skills/expo-upgrade/SKILL.md similarity index 97% rename from plugins/expo/skills/upgrading-expo/SKILL.md rename to plugins/expo/skills/expo-upgrade/SKILL.md index 5769946..865cb1a 100644 --- a/plugins/expo/skills/upgrading-expo/SKILL.md +++ b/plugins/expo/skills/expo-upgrade/SKILL.md @@ -1,6 +1,6 @@ --- -name: upgrading-expo -description: Guidelines for upgrading Expo SDK versions and fixing dependency issues +name: expo-upgrade +description: Framework (OSS). Guidelines for upgrading Expo SDK versions and fixing dependency issues version: 1.0.0 license: MIT --- diff --git a/plugins/expo/skills/expo-upgrade/agents/openai.yaml b/plugins/expo/skills/expo-upgrade/agents/openai.yaml new file mode 100644 index 0000000..39d580e --- /dev/null +++ b/plugins/expo/skills/expo-upgrade/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Expo Upgrade" + short_description: "Upgrade Expo SDKs, fix dependencies, adopt React 19 / React Compiler, and migrate deprecated Expo packages" + default_prompt: "Use $expo-upgrade to upgrade an Expo SDK, run diagnostics, fix dependency conflicts, decide whether prebuild/cache clearing applies, and migrate away from deprecated Expo packages." diff --git a/plugins/expo/skills/upgrading-expo/references/expo-av-to-audio.md b/plugins/expo/skills/expo-upgrade/references/expo-av-to-audio.md similarity index 100% rename from plugins/expo/skills/upgrading-expo/references/expo-av-to-audio.md rename to plugins/expo/skills/expo-upgrade/references/expo-av-to-audio.md diff --git a/plugins/expo/skills/upgrading-expo/references/expo-av-to-video.md b/plugins/expo/skills/expo-upgrade/references/expo-av-to-video.md similarity index 100% rename from plugins/expo/skills/upgrading-expo/references/expo-av-to-video.md rename to plugins/expo/skills/expo-upgrade/references/expo-av-to-video.md diff --git a/plugins/expo/skills/upgrading-expo/references/native-tabs.md b/plugins/expo/skills/expo-upgrade/references/native-tabs.md similarity index 100% rename from plugins/expo/skills/upgrading-expo/references/native-tabs.md rename to plugins/expo/skills/expo-upgrade/references/native-tabs.md diff --git a/plugins/expo/skills/upgrading-expo/references/new-architecture.md b/plugins/expo/skills/expo-upgrade/references/new-architecture.md similarity index 100% rename from plugins/expo/skills/upgrading-expo/references/new-architecture.md rename to plugins/expo/skills/expo-upgrade/references/new-architecture.md diff --git a/plugins/expo/skills/upgrading-expo/references/react-19.md b/plugins/expo/skills/expo-upgrade/references/react-19.md similarity index 100% rename from plugins/expo/skills/upgrading-expo/references/react-19.md rename to plugins/expo/skills/expo-upgrade/references/react-19.md diff --git a/plugins/expo/skills/upgrading-expo/references/react-compiler.md b/plugins/expo/skills/expo-upgrade/references/react-compiler.md similarity index 100% rename from plugins/expo/skills/upgrading-expo/references/react-compiler.md rename to plugins/expo/skills/expo-upgrade/references/react-compiler.md diff --git a/plugins/expo/skills/upgrading-expo/references/react-navigation-to-expo-router.md b/plugins/expo/skills/expo-upgrade/references/react-navigation-to-expo-router.md similarity index 100% rename from plugins/expo/skills/upgrading-expo/references/react-navigation-to-expo-router.md rename to plugins/expo/skills/expo-upgrade/references/react-navigation-to-expo-router.md diff --git a/plugins/expo/skills/web-to-native/SKILL.md b/plugins/expo/skills/expo-web-to-native/SKILL.md similarity index 67% rename from plugins/expo/skills/web-to-native/SKILL.md rename to plugins/expo/skills/expo-web-to-native/SKILL.md index dd3f3e9..1e28314 100644 --- a/plugins/expo/skills/web-to-native/SKILL.md +++ b/plugins/expo/skills/expo-web-to-native/SKILL.md @@ -1,6 +1,6 @@ --- -name: web-to-native -description: Migrate an existing web React app to a native iOS/Android app with Expo. Use when the user wants to turn a website into a mobile app, port a Next.js/Vite/CRA React codebase to React Native, reuse web code on native incrementally, or asks how web idioms (the DOM, CSS, React Router, localStorage, window) map to native. This is the end-to-end migration guide; use the `use-dom` skill for the DOM-component mechanism itself. +name: expo-web-to-native +description: Framework (OSS). Migrate an existing web React app to a native iOS/Android app with Expo. Use when the user wants to turn a website into a mobile app, port a Next.js/Vite/CRA React codebase to React Native, reuse web code on native incrementally, or asks how web idioms (the DOM, CSS, React Router, localStorage, window) map to native. This is the end-to-end migration guide; use the `expo-dom` skill for the DOM-component mechanism itself. version: 1.0.0 license: MIT --- @@ -12,11 +12,11 @@ A web React app does not *convert* to native — there is no transpiler. It **mi ```mermaid flowchart TD A1[1 · Assess: write the worklist] --> A2[2 · Scaffold Expo shell] - A2 --> A3[3 · DOM-component shell
· use-dom · SHIP DAY ONE] - A3 --> A4[4 · Strangle screens to native
highest-value first · building-native-ui] + A2 --> A3[3 · DOM-component shell
· expo-dom · SHIP DAY ONE] + A3 --> A4[4 · Strangle screens to native
highest-value first · expo-router] A4 -->|more screens| A4 - A4 --> A5[5 · Wire data / auth / storage
· native-data-fetching] - A5 --> A6[6 · Ship · expo-deployment] + A4 --> A5[5 · Wire data / auth / storage
· expo-data-fetching] + A5 --> A6[6 · Ship · eas-app-stores] ``` ## Principles @@ -24,7 +24,7 @@ flowchart TD - **Migrate, don't rewrite.** Never big-bang it; every step keeps the app shippable. - **Ship on day one.** The web UI runs in a DOM-component shell (step 3) before anything is nativized — that's the milestone; everything after is polish. - **Strangle by value.** Nativize the hot screens; leave the rest in the webview. Each DOM screen carries a ~2 MB web runtime — reason enough not to ship everything as DOM. -- **Nativize means redesign, not reskin.** A strangled screen should look like Apple/Google shipped it, not the web page reskinned. **Reach for `@expo/ui` first** — it renders real SwiftUI/Compose, so it feels *exactly* like the OS; styled RN primitives are the fallback for custom layouts only. Plus platform navigation (`expo-router`: NativeTabs, large titles), liquid glass and native components via `@expo/ui`, and mobile UX (sheets, swipe, haptics). The web→native pattern map is [`./references/native-patterns.md`](./references/native-patterns.md). If it still feels like a website, you ported instead of redesigned. +- **Nativize means redesign, not reskin.** A strangled screen should look like Apple/Google shipped it, not the web page reskinned. **Reach for `@expo/ui` first** - it renders real SwiftUI/Compose, so it feels *exactly* like the OS; styled RN primitives are the fallback for custom layouts only. Plus platform navigation (`expo-router`: NativeTabs, large titles), liquid glass and native components via `@expo/ui`, and mobile UX (sheets, swipe, haptics). The web→native pattern map is [`./references/native-patterns.md`](./references/native-patterns.md). If it still feels like a website, you ported instead of redesigned. - **Verify by running, not compiling.** A clean build proves nothing (a blank webview compiles fine). Run each screen — but judge *content and behavior* against the web original, not pixels (a nativized screen should look more native, not identical). - **Orchestrate, don't reinvent.** Each step routes into an existing skill. The value here is the *order* and the *gotchas* — the idiom-by-idiom mappings live in [`./references/false-friends.md`](./references/false-friends.md). @@ -34,13 +34,13 @@ The migration is a long repeat-until-done loop, so the first move is to **write ## The migration -> **No repo to migrate** — just building native fresh as a web dev? You don't need these steps: use `building-native-ui`, and keep [`./references/false-friends.md`](./references/false-friends.md) open for the web→native idiom map. Everything below assumes an existing web app. +> **No repo to migrate** - just building native fresh as a web dev? You don't need these steps: use `expo-router`, and keep [`./references/false-friends.md`](./references/false-friends.md) open for the web→native idiom map. Everything below assumes an existing web app. ### 1. Assess → write the worklist Read the repo and produce `migration-progress.md`, the durable worklist the rest of the migration checks off. Make two cuts: -- **Screens vs backend.** Page routes (`page.tsx`) are screens you migrate; server routes (`route.ts`), the ORM, and auth handlers stay server-side. Decide the backend once: keep it deployed (the native app becomes an HTTP client) or move it to EAS Hosting (`expo-api-routes`). +- **Screens vs backend.** Page routes (`page.tsx`) are screens you migrate; server routes (`route.ts`), the ORM, and auth handlers stay server-side. Decide the backend once: keep it deployed (the native app becomes an HTTP client) or move it to EAS Hosting (`eas-hosting`). - **Bucket each screen** by how it should land: **port-as-is** (presentational → ships in a DOM webview), **nativize-now** (hot, or needs native feel — gestures, lists, keyboard), **nativize-later**, or **hybrid** (a native shell around a web sub-tree, e.g. a chat list wrapping a markdown renderer). Note the framework signals as you read — RSC vs client, Tailwind/shadcn, where data is fetched — since they decide how each screen ports (false-friends has the mappings; async Server Components in particular must be split into a client fetch + a presentational component before they can move). **Flag third-party services/SDKs too** — browser SDKs don't carry over (`false-friends` → *Services & SDKs*); payments especially is a *fork, not a swap* (in-app digital goods must use store IAP via RevenueCat, ~30% — not Stripe), a business-model call to make now, not at App Store review. The worklist is only trustworthy once every route is sorted and every screen bucketed. @@ -51,19 +51,19 @@ Note the framework signals as you read — RSC vs client, Tailwind/shadcn, where ### 3. Shell it in DOM components — the day-one milestone -Bring every screen over as a DOM component (`'use dom'`, per the `use-dom` skill) rendered by its native route, so the whole app runs on a phone before anything is nativized. Expect per-screen edits — unwrapping Server Components, swapping framework imports (`next/link`), carrying the styling over — all covered in false-friends. Then verify by running (below); this is shippable to TestFlight as-is. +Bring every screen over as a DOM component (`'use dom'`, per the `expo-dom` skill) rendered by its native route, so the whole app runs on a phone before anything is nativized. Expect per-screen edits - unwrapping Server Components, swapping framework imports (`next/link`), carrying the styling over - all covered in false-friends. Then verify by running (below); this is shippable to TestFlight as-is. ### 4. Strangle screens to native — by value -Walk `migration-progress.md` top-down. For each screen, *redesign* it native — don't port the web layout. Reach for **`@expo/ui` first** (real SwiftUI/Compose — buttons, lists, sheets, pickers, sliders; [`./references/native-patterns.md`](./references/native-patterns.md) maps which web pattern becomes which native component), then platform navigation (`expo-router` — NativeTabs, large titles) and mobile UX (swipe, haptics, momentum/inverted scroll); RN primitives only for custom layouts. Consult [`./references/false-friends.md`](./references/false-friends.md) for each idiom. `@expo/ui` and DOM components both run in **Expo Go** (SDK 56+) — a dev build (the `expo-dev-client` skill) is only needed for *custom* native modules. Verify *content and behavior* against the running web original (the look should become more native), then check it off. One screen per pass, app shippable throughout. It's a loop over a durable worklist, so it can run unattended — hand it to a goal loop ([`./references/run-as-goal.md`](./references/run-as-goal.md)). +Walk `migration-progress.md` top-down. For each screen, *redesign* it native - don't port the web layout. Reach for **`@expo/ui` first** (real SwiftUI/Compose - buttons, lists, sheets, pickers, sliders; [`./references/native-patterns.md`](./references/native-patterns.md) maps which web pattern becomes which native component), then platform navigation (`expo-router` - NativeTabs, large titles) and mobile UX (swipe, haptics, momentum/inverted scroll); RN primitives only for custom layouts. Consult [`./references/false-friends.md`](./references/false-friends.md) for each idiom. `@expo/ui` and DOM components both run in **Expo Go** (SDK 56+) - a dev build (the `expo-dev-client` skill) is only needed for *custom* native modules. Verify *content and behavior* against the running web original (the look should become more native), then check it off. One screen per pass, app shippable throughout. It's a loop over a durable worklist, so it can run unattended - hand it to a goal loop ([`./references/run-as-goal.md`](./references/run-as-goal.md)). ### 5. Wire data, auth, and storage -The web data layer doesn't survive the move — relative fetches, cookie sessions, `localStorage`, and env vars all change (swaps in false-friends). Use `native-data-fetching` for requests and caching; add `expo-api-routes` if the backend moved to EAS Hosting. +The web data layer doesn't survive the move - relative fetches, cookie sessions, `localStorage`, and env vars all change (swaps in false-friends). Use `expo-data-fetching` for requests and caching; add `eas-hosting` if the backend moved to EAS Hosting. ### 6. Ship -`expo-deployment` for the store builds (App Store / Play / TestFlight), EAS Update for OTA pushes after. +`eas-app-stores` for the store builds (App Store / Play / TestFlight), EAS Update for OTA pushes after. ## Verify by running, not compiling diff --git a/plugins/expo/skills/expo-web-to-native/agents/openai.yaml b/plugins/expo/skills/expo-web-to-native/agents/openai.yaml new file mode 100644 index 0000000..7245548 --- /dev/null +++ b/plugins/expo/skills/expo-web-to-native/agents/openai.yaml @@ -0,0 +1,4 @@ +interface: + display_name: "Expo Web to Native" + short_description: "Migrate an existing web React app (Next.js, Vite, CRA) to a native iOS/Android app with Expo, screen by screen" + default_prompt: "Use $expo-web-to-native to migrate a web React codebase to native: assess and bucket screens, ship a DOM-component shell on day one, then nativize screens in priority order with @expo/ui and Expo Router." diff --git a/plugins/expo/skills/web-to-native/references/false-friends.md b/plugins/expo/skills/expo-web-to-native/references/false-friends.md similarity index 91% rename from plugins/expo/skills/web-to-native/references/false-friends.md rename to plugins/expo/skills/expo-web-to-native/references/false-friends.md index 22f1292..a43c261 100644 --- a/plugins/expo/skills/web-to-native/references/false-friends.md +++ b/plugins/expo/skills/expo-web-to-native/references/false-friends.md @@ -1,6 +1,6 @@ # False Friends: web idioms → native -Disclosed reference for [`web-to-native`](../SKILL.md). A *false friend* is a web idiom that looks portable but isn't — it compiles in your head, then breaks (or silently no-ops) on native. Each row is `web idiom → native equivalent → the gotcha`. Reach for this in steps 3–5 of a migration, and whenever you're learning native after the web. +Disclosed reference for [`expo-web-to-native`](../SKILL.md). A *false friend* is a web idiom that looks portable but isn't - it compiles in your head, then breaks (or silently no-ops) on native. Each row is `web idiom → native equivalent → the gotcha`. Reach for this in steps 3–5 of a migration, and whenever you're learning native after the web. This is the single source of truth for the mapping; the SKILL.md steps name a few high-traffic swaps but defer the full list here. @@ -46,9 +46,9 @@ This is the single source of truth for the mapping; the SKILL.md steps name a fe | React Router / Next.js routes | Expo Router (file-based) | File-based like Next App Router; `react-router` concepts map but the API differs. | | `` / `` | `expo-router` `` | Works in DOM components too. | | `useNavigate()` / `router.push` | `useRouter()` from `expo-router` | `router.push/replace/back`. | -| `useParams` / `useSearchParams` | `useLocalSearchParams()` | Note: doesn't work *inside* a DOM component — read in the native parent, pass as props (see `use-dom`). | +| `useParams` / `useSearchParams` | `useLocalSearchParams()` | Note: doesn't work *inside* a DOM component - read in the native parent, pass as props (see `expo-dom`). | | `window.location` | `usePathname()` / router | No `location` object. | -| Deep links / `myapp://` | URL scheme + universal links | Configure `scheme` in app config; native gives you real deep linking and (with AASA) app links — see `add-app-clip` for the AASA file. | +| Deep links / `myapp://` | URL scheme + universal links | Configure `scheme` in app config; native gives you real deep linking and (with AASA) app links - see `expo-app-clip` for the AASA file. | ## React architecture & data (Next.js / SSR apps) @@ -57,7 +57,7 @@ This is the single source of truth for the mapping; the SKILL.md steps name a fe | Async Server Component (`async function Page()`) | client component + data fetch | No RSC on native (Expo's is experimental and different). Split into a client component that fetches via the API + a presentational child *before* porting. | | Server actions (`'use server'`) | API route + `fetch` | No server actions. Expose an endpoint and call it. | | `cookies()` / `headers()` (server) | token in `expo-secure-store` | Server-only. Auth moves to a bearer token sent as a header. | -| ORM / DB client in a page (Drizzle, Prisma) | server only — call over HTTP | The device never talks to the DB. Keep the backend deployed, or move routes to EAS Hosting (`expo-api-routes`); the app fetches. | +| ORM / DB client in a page (Drizzle, Prisma) | server only - call over HTTP | The device never talks to the DB. Keep the backend deployed, or move routes to EAS Hosting (`eas-hosting`); the app fetches. | | `next/navigation` (`notFound`, `redirect`) | `expo-router` | `redirect()` → `router.replace`; `notFound()` → a native `+not-found` route. | | `_layout` as a DOM component | always native | Layout routes can't be DOM components — they *are* the native shell. Rewrite web-only layout logic (theme scripts, providers) with native APIs. | @@ -74,7 +74,7 @@ This is the single source of truth for the mapping; the SKILL.md steps name a fe | Web | Native | Gotcha | |---|---|---| -| `window`, `document` | none | Don't exist. Guard web-only libs, or keep them in a DOM component (`use-dom`). | +| `window`, `document` | none | Don't exist. Guard web-only libs, or keep them in a DOM component (`expo-dom`). | | `window.matchMedia('(prefers-color-scheme: dark)')` | `useColorScheme()` | Hook from `react-native`, reactive to the system theme. Web theme bootstrap scripts in the layout don't run. | | `window.innerWidth/Height` | `useWindowDimensions()` | Reactive hook; updates on rotation. | | `navigator.*`, Web APIs | Expo SDK modules | e.g. camera → `expo-camera`, geolocation → `expo-location`, clipboard → `expo-clipboard`. | @@ -90,8 +90,8 @@ This is the single source of truth for the mapping; the SKILL.md steps name a fe |---|---|---| | `fetch('/api/x')` (relative) | absolute URL | Native has no origin — relative paths fail. Use a configured base URL (`EXPO_PUBLIC_API_URL`). | | CORS | n/a | No browser CORS, but you still need a reachable absolute host. | -| `fetch`, React Query, SWR | same | The libraries themselves work on native — see `native-data-fetching`. | -| Next.js API routes | Expo Router API routes | Move server endpoints to Expo API routes on EAS Hosting — see `expo-api-routes`. | +| `fetch`, React Query, SWR | same | The libraries themselves work on native - see `expo-data-fetching`. | +| Next.js API routes | Expo Router API routes | Move server endpoints to Expo API routes on EAS Hosting - see `eas-hosting`. | | Streaming responses (SSE, AI SDK `useChat`) | `expo/fetch` with `textStreaming` | RN's built-in `fetch` can't read a streaming response body. Use `expo/fetch` (streams, and works with the Vercel AI SDK) or an XHR-based polyfill. | ## Third-party services & SDKs diff --git a/plugins/expo/skills/web-to-native/references/native-patterns.md b/plugins/expo/skills/expo-web-to-native/references/native-patterns.md similarity index 78% rename from plugins/expo/skills/web-to-native/references/native-patterns.md rename to plugins/expo/skills/expo-web-to-native/references/native-patterns.md index 6c98279..53d7cbe 100644 --- a/plugins/expo/skills/web-to-native/references/native-patterns.md +++ b/plugins/expo/skills/expo-web-to-native/references/native-patterns.md @@ -1,12 +1,12 @@ # Native patterns: redesigning web UX for native -Disclosed reference for [`web-to-native`](../SKILL.md), step 4. `false-friends.md` translates *idioms* (`div` → `View`); this translates *UX patterns* — a web interaction into its native equivalent. Step 4 isn't a port, it's this redesign. +Disclosed reference for [`expo-web-to-native`](../SKILL.md), step 4. `false-friends.md` translates *idioms* (`div` → `View`); this translates *UX patterns* - a web interaction into its native equivalent. Step 4 isn't a port, it's this redesign. **Reach for `@expo/ui` first.** It renders real SwiftUI (iOS) and Jetpack Compose (Android), so its components look and feel *exactly* like the OS — the difference between "native-ish RN" and "indistinguishable from an app Apple/Google shipped." See the `expo-ui` skill. Drop to styled RN primitives only for what `@expo/ui` doesn't cover: custom layouts (chat bubbles, bespoke cards) and **large data lists** (`@expo/ui` `List` is a JS-thread node per item — use `FlashList`/`FlatList` for feeds). `@expo/ui` runs in **Expo Go** (SDK 56+) — no dev build needed; reach for a dev build (the `expo-dev-client` skill) only for *custom* native modules. | Web pattern | Native redesign — reach for first | Why | |---|---|---| -| Top tab bar / nav links | **NativeTabs** — bottom, liquid glass on iOS 26 (`expo-router`) | Thumb-reachable, OS-native bar | +| Top tab bar / nav links | **NativeTabs** - bottom, liquid glass on iOS 26 (`expo-router`) | Thumb-reachable, OS-native bar | | Page header / breadcrumb | **large-title** Stack header + header **search field** (`expo-router`) | The native screen frame | | In-page tabs / toggle group | **SegmentedControl** — `@expo/ui` (`community/segmented-control`) | Native segmented switch | | Modal / dialog | **BottomSheet** — `@expo/ui` | Sheets *are* the native modal | @@ -28,10 +28,10 @@ Disclosed reference for [`web-to-native`](../SKILL.md), step 4. `false-friends.m ## Feel — beyond the components -The table gets the right *components*; "native" also lives in *motion and touch* — and a web port arrives with almost none, so you must add it. The tooling is in `expo-router` (navigation/transitions) and `building-native-ui` (motion/effects); reach for it, don't hand-roll: +The table gets the right *components*; "native" also lives in *motion and touch* - and a web port arrives with almost none, so you must add it. The tooling is in `expo-router` (navigation/transitions) and `expo-native-ui` (motion/effects); reach for it, don't hand-roll: -- **Transitions for free** — use Expo Router's native-stack so push/pop, modals, and sheets animate with real platform physics; shared-element zoom via `expo-router` `zoom-transitions.md`. -- **Motion** — Reanimated (`withSpring`/`withTiming`; `entering`/`exiting` for list items) + `react-native-gesture-handler` for swipes/drags → `building-native-ui` `animations.md`. +- **Transitions for free** - use Expo Router's native-stack so push/pop, modals, and sheets animate with real platform physics; shared-element zoom via `expo-router` `zoom-transitions.md`. +- **Motion** - Reanimated (`withSpring`/`withTiming`; `entering`/`exiting` for list items) + `react-native-gesture-handler` for swipes/drags → `expo-native-ui` `animations.md`. - **Touch** — `expo-haptics` on commits, selection changes, and pull-to-refresh — choreography, not just a toast buzz. - **Native rhythm** — large-title collapse on scroll, momentum / inverted scroll, a keyboard that pushes content (`KeyboardAvoidingView`). - **Respect reduced motion** — gate non-essential animation on Reanimated's `useReducedMotion()`. diff --git a/plugins/expo/skills/web-to-native/references/run-as-goal.md b/plugins/expo/skills/expo-web-to-native/references/run-as-goal.md similarity index 79% rename from plugins/expo/skills/web-to-native/references/run-as-goal.md rename to plugins/expo/skills/expo-web-to-native/references/run-as-goal.md index 539e225..67a77b0 100644 --- a/plugins/expo/skills/web-to-native/references/run-as-goal.md +++ b/plugins/expo/skills/expo-web-to-native/references/run-as-goal.md @@ -1,6 +1,6 @@ # Run the migration as a goal loop -Disclosed reference for [`web-to-native`](../SKILL.md) — the recommended way to drive the whole migration. The migration is a repeat-until-done loop (assess → nativize each screen → verify → check off), which is exactly the shape of a **goal loop**: a single objective re-injected every turn until the worklist is empty. This file carries a ready-shaped, migration-specific objective — and, crucially, the objective **re-reads this skill every iteration**, so the loop keeps following the playbook (and self-bootstraps the assess step if no worklist exists yet). +Disclosed reference for [`expo-web-to-native`](../SKILL.md) - the recommended way to drive the whole migration. The migration is a repeat-until-done loop (assess → nativize each screen → verify → check off), which is exactly the shape of a **goal loop**: a single objective re-injected every turn until the worklist is empty. This file carries a ready-shaped, migration-specific objective - and, crucially, the objective **re-reads this skill every iteration**, so the loop keeps following the playbook (and self-bootstraps the assess step if no worklist exists yet). Use it in one of two modes depending on the agent you're running. @@ -17,9 +17,9 @@ Write the filled-in objective to `migration-goal.md` in the project, then give t Fill the two `<…>` slots, then run or hand off verbatim. It is written to survive re-injection — it restates its own worklist, direction, and stop condition every turn. ``` -Goal: migrate from web to a native Expo app by following the web-to-native skill, one screen per iteration, until done. +Goal: migrate from web to a native Expo app by following the expo-web-to-native skill, one screen per iteration, until done. -Each iteration, FIRST re-read the playbook — plugins/expo/skills/web-to-native/SKILL.md (and its references) — then: +Each iteration, FIRST re-read the playbook - plugins/expo/skills/expo-web-to-native/SKILL.md (and its references) - then: 1. If migration-progress.md doesn't exist yet, do the skill's step 1 (Assess) to create the worklist, then stop. Otherwise open it and take the top unchecked item under "nativize-now"; if none are left unresolved (every nativize-now is diff --git a/plugins/expo/skills/web-to-native/references/verify-on-device.md b/plugins/expo/skills/expo-web-to-native/references/verify-on-device.md similarity index 90% rename from plugins/expo/skills/web-to-native/references/verify-on-device.md rename to plugins/expo/skills/expo-web-to-native/references/verify-on-device.md index 0789ba1..b5d82bd 100644 --- a/plugins/expo/skills/web-to-native/references/verify-on-device.md +++ b/plugins/expo/skills/expo-web-to-native/references/verify-on-device.md @@ -1,6 +1,6 @@ # Verify a migrated screen against the running web app -Disclosed reference for [`web-to-native`](../SKILL.md), steps 3–4. Verification means **running both apps and comparing the same screen** — the native port beside the web original. A clean compile or a green `expo export` proves nothing — a screen can build and still render blank or mis-render. This parity check is the gate the strangle loop runs each iteration. +Disclosed reference for [`expo-web-to-native`](../SKILL.md), steps 3–4. Verification means **running both apps and comparing the same screen** - the native port beside the web original. A clean compile or a green `expo export` proves nothing - a screen can build and still render blank or mis-render. This parity check is the gate the strangle loop runs each iteration. Two agents drive it, and this skill is **opinionated**: it requires both and installs them rather than falling back to manual screenshots. diff --git a/plugins/expo/skills/native-data-fetching/agents/openai.yaml b/plugins/expo/skills/native-data-fetching/agents/openai.yaml deleted file mode 100644 index f28d22d..0000000 --- a/plugins/expo/skills/native-data-fetching/agents/openai.yaml +++ /dev/null @@ -1,4 +0,0 @@ -interface: - display_name: "Native Data Fetching" - short_description: "Implement and debug Expo network requests, caching, auth, offline support, and Expo Router data loaders" - default_prompt: "Use $native-data-fetching for Expo data fetching work: fetch wrappers, React Query or SWR setup, error handling, retry/cancellation, authenticated requests, environment-based API URLs, offline behavior, and Expo Router loaders." diff --git a/plugins/expo/skills/upgrading-expo/agents/openai.yaml b/plugins/expo/skills/upgrading-expo/agents/openai.yaml deleted file mode 100644 index 09c353d..0000000 --- a/plugins/expo/skills/upgrading-expo/agents/openai.yaml +++ /dev/null @@ -1,4 +0,0 @@ -interface: - display_name: "Upgrading Expo" - short_description: "Upgrade Expo SDKs, fix dependencies, adopt React 19 / React Compiler, and migrate deprecated Expo packages" - default_prompt: "Use $upgrading-expo to upgrade an Expo SDK, run diagnostics, fix dependency conflicts, decide whether prebuild/cache clearing applies, and migrate away from deprecated Expo packages." diff --git a/plugins/expo/skills/use-dom/agents/openai.yaml b/plugins/expo/skills/use-dom/agents/openai.yaml deleted file mode 100644 index 1ca06f6..0000000 --- a/plugins/expo/skills/use-dom/agents/openai.yaml +++ /dev/null @@ -1,4 +0,0 @@ -interface: - display_name: "Use DOM" - short_description: "Use Expo DOM components to run web React code in native webviews and unchanged on web" - default_prompt: "Use $use-dom to migrate web components into Expo via 'use dom', configure DOM props, expose native actions safely, use web-only libraries, and keep DOM components separate from native routes." diff --git a/scripts/check-skill-limits.ts b/scripts/check-skill-limits.ts index e305d1f..545fa81 100644 --- a/scripts/check-skill-limits.ts +++ b/scripts/check-skill-limits.ts @@ -1,10 +1,15 @@ #!/usr/bin/env bun -import { readdirSync, readFileSync } from "node:fs"; -import { join } from "node:path"; +import { existsSync, readdirSync, readFileSync } from "node:fs"; +import { dirname, join } from "node:path"; const MAX_DESCRIPTION = 1024; const MAX_BODY_LINES = 500; +const FRAMEWORK_PREFIX = "Framework (OSS)."; +const PAID_PREFIX = "EAS service (paid)."; +const PAID_CALLOUT = "**EAS service - costs apply.**"; +const PAID_PRICING_LINK = "expo.dev/pricing"; +const PAID_CODEX_PREFIX = "Paid EAS service."; function findSkillFiles(dir: string): string[] { const results: string[] = []; @@ -16,36 +21,92 @@ function findSkillFiles(dir: string): string[] { return results; } -function parseSkill(path: string): { description: string; bodyLines: number } { +function parseSkill(path: string): { name: string; description: string; body: string; bodyLines: number } { const content = readFileSync(path, "utf8"); // captures everything between the two --- fences (group 1 = frontmatter, group 2 = body) const match = content.match(/^---\n([\s\S]*?)\n---\n([\s\S]*)$/); - if (!match) return { description: "", bodyLines: 0 }; + if (!match) return { name: "", description: "", body: "", bodyLines: 0 }; const frontmatter = match[1]; const body = match[2]; // matches "description: " — optional quotes, multiline value const descMatch = frontmatter.match(/^description:\s*["']?([\s\S]*?)["']?\s*$/m); const description = descMatch ? descMatch[1].replace(/^"|"$/g, "") : ""; - return { description, bodyLines: body.split("\n").length }; + const nameMatch = frontmatter.match(/^name:\s*(.+?)\s*$/m); + const name = nameMatch ? nameMatch[1] : ""; + return { name, description, body, bodyLines: body.split("\n").length }; +} + +function loadCatalogGroups(): Map { + const groups = new Map(); + const catalog = JSON.parse(readFileSync("skills.sh.json", "utf8")); + for (const grouping of catalog.groupings ?? []) { + const kind = grouping.title.startsWith("Framework") ? "framework" : "paid"; + for (const skill of grouping.skills ?? []) groups.set(skill, kind); + } + return groups; } const skills = findSkillFiles("plugins"); +const catalogGroups = loadCatalogGroups(); +const seenDirs = new Set(); const errors: string[] = []; for (const path of skills) { - const { description, bodyLines } = parseSkill(path); + const { name, description, body, bodyLines } = parseSkill(path); const rel = path.replace(process.cwd() + "/", ""); + const dirName = dirname(path).split("/").pop() ?? ""; + seenDirs.add(dirName); + const isPaid = dirName.startsWith("eas-"); + if (description.length > MAX_DESCRIPTION) errors.push(`${rel}: description ${description.length} chars (max ${MAX_DESCRIPTION})`); if (bodyLines > MAX_BODY_LINES) errors.push(`${rel}: body ${bodyLines} lines (max ${MAX_BODY_LINES})`); + + // naming: expo-* (framework) or eas-* (paid EAS service), frontmatter name matches directory + if (!dirName.startsWith("expo-") && !dirName.startsWith("eas-")) + errors.push(`${rel}: skill directory must be named expo-* or eas-* (got "${dirName}")`); + if (name !== dirName) + errors.push(`${rel}: frontmatter name "${name}" does not match directory "${dirName}"`); + + // category prefix on the always-loaded description + const expectedPrefix = isPaid ? PAID_PREFIX : FRAMEWORK_PREFIX; + if (!description.startsWith(expectedPrefix)) + errors.push(`${rel}: description must start with "${expectedPrefix}"`); + + // paid skills disclose costs up front (dash style varies: em dash or hyphen) + const normalizedBody = body.replace(/—/g, "-"); + if (isPaid && (!normalizedBody.includes(PAID_CALLOUT) || !normalizedBody.includes(PAID_PRICING_LINK))) + errors.push(`${rel}: paid skill body must include the "${PAID_CALLOUT}" callout with a ${PAID_PRICING_LINK} link`); + + // Codex trigger metadata + const openaiYamlPath = join(dirname(path), "agents", "openai.yaml"); + if (!existsSync(openaiYamlPath)) { + errors.push(`${rel}: missing agents/openai.yaml (Codex trigger metadata)`); + } else if (isPaid) { + const yaml = readFileSync(openaiYamlPath, "utf8"); + const shortDesc = yaml.match(/^\s*short_description:\s*"?(.*?)"?\s*$/m)?.[1] ?? ""; + if (!shortDesc.startsWith(PAID_CODEX_PREFIX)) + errors.push(`${rel}: paid skill's openai.yaml short_description must start with "${PAID_CODEX_PREFIX}"`); + } + + // catalog sync with skills.sh.json groups + const group = catalogGroups.get(dirName); + if (!group) errors.push(`${rel}: skill is not listed in skills.sh.json`); + else if (group !== (isPaid ? "paid" : "framework")) + errors.push(`${rel}: skills.sh.json lists this skill in the ${group} group, but the ${isPaid ? "eas-" : "expo-"} prefix requires the ${isPaid ? "paid" : "framework"} group`); +} + +for (const [skill] of catalogGroups) { + if (!seenDirs.has(skill)) + errors.push(`skills.sh.json: lists "${skill}" but plugins/expo/skills/${skill}/SKILL.md does not exist`); } if (errors.length === 0) { - console.log("✓ All skills pass description and body limits."); + console.log("✓ All skills pass limits, naming, category labels, paid callouts, Codex metadata, and catalog sync."); process.exit(0); } else { - console.log("✗ Skill limit violations:\n"); + console.log("✗ Skill check violations:\n"); for (const e of errors) console.log(` ${e}`); process.exit(1); } diff --git a/skills.sh.json b/skills.sh.json index 4460685..7a41625 100644 --- a/skills.sh.json +++ b/skills.sh.json @@ -3,46 +3,35 @@ "notGrouped": "bottom", "groupings": [ { - "title": "App Design", - "description": "Build Expo Router screens, native-feeling UI, styling, data fetching, and API routes.", + "title": "Framework (open source)", + "description": "Free, open-source Expo SDK and React Native skills: UI, navigation, styling, data fetching, native modules, DOM, examples, and SDK upgrades.", "skills": [ - "building-native-ui", "expo-router", - "native-data-fetching", - "expo-api-routes", + "expo-native-ui", + "expo-ui", + "expo-data-fetching", "expo-tailwind-setup", - "use-dom", - "expo-dev-client" - ] - }, - { - "title": "Native Platform", - "description": "Work with Expo native modules, SwiftUI, Jetpack Compose, App Clips, and brownfield apps.", - "skills": [ + "expo-dom", + "expo-web-to-native", "expo-module", - "expo-ui-swiftui", - "expo-ui-jetpack-compose", - "add-app-clip", - "expo-brownfield" + "expo-brownfield", + "expo-dev-client", + "expo-examples", + "expo-app-clip", + "expo-upgrade" ] }, { - "title": "Deploy and Observe", - "description": "Ship apps with EAS Build, EAS Workflows, EAS Update, EAS Observe, stores, and hosting.", + "title": "Services & paid distribution", + "description": "Skills whose core purpose uses paid Expo Application Services (EAS). Each one discloses costs and plan limits up front.", "skills": [ - "expo-deployment", - "expo-cicd-workflows", - "expo-observe", + "eas-app-stores", + "eas-hosting", + "eas-workflows", + "eas-observe", "eas-update-insights", "eas-simulator" ] - }, - { - "title": "Maintenance", - "description": "Upgrade Expo SDK versions and fix dependency, cache, and migration issues.", - "skills": [ - "upgrading-expo" - ] } ] } From 244153e5e85f4602d6888dbdde86cccf6276445a Mon Sep 17 00:00:00 2001 From: Jon Samp Date: Tue, 7 Jul 2026 11:15:29 -0500 Subject: [PATCH 2/2] Fix mangled EXPO_PUBLIC_ in expo-data-fetching quick reference --- plugins/expo/skills/expo-data-fetching/SKILL.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/plugins/expo/skills/expo-data-fetching/SKILL.md b/plugins/expo/skills/expo-data-fetching/SKILL.md index 191a767..06fa8cd 100644 --- a/plugins/expo/skills/expo-data-fetching/SKILL.md +++ b/plugins/expo/skills/expo-data-fetching/SKILL.md @@ -441,9 +441,9 @@ User: "How do I handle authentication tokens?" User: "API calls are slow" -> Check caching strategy, use React Query staleTime User: "How do I configure different API URLs for dev and prod?" --> Use EXPO*PUBLIC* env vars with .env.development and .env.production files +-> Use `EXPO_PUBLIC_` env vars with .env.development and .env.production files User: "Where should I put my API key?" --> Client-safe keys: EXPO*PUBLIC* in .env. Secret keys: non-prefixed env vars in API routes only +-> Client-safe keys: `EXPO_PUBLIC_` in .env. Secret keys: non-prefixed env vars in API routes only User: "How do I load data for a page in Expo Router?" -> See references/expo-router-loaders.md for route-level loaders (web, SDK 55+). For native, use React Query or fetch.