Skip to content

feat(mobile): add expo app with tailwind, ui tokens; fix cli api path#140

Merged
gaboesquivel merged 10 commits intomainfrom
other-apps
Mar 12, 2026
Merged

feat(mobile): add expo app with tailwind, ui tokens; fix cli api path#140
gaboesquivel merged 10 commits intomainfrom
other-apps

Conversation

@gaboesquivel
Copy link
Member

@gaboesquivel gaboesquivel commented Mar 12, 2026

  • Add apps/mobile with Expo SDK 55, NativeWind v5, @repo/ui tokens
  • Align mobile with monorepo: tsconfig, biome, eslint, cursor rules
  • Add tools/typescript/expo.json, tools/eslint/expo.js
  • Add dev-environments doc, narrow web-only cursor rules
  • Fix packages/cli and turbo.json: apps/fastify -> apps/api for openapi
  • Extract packages/ui tokens.css for shared design system

Summary by CodeRabbit

  • New Features

    • Added a new Expo mobile app with starter screens, tab navigation, animated splash/icon, themed components, and developer hints.
  • Documentation

    • Added onboarding and dev-environments guides; comprehensive Expo deployment, upgrade, Tailwind, migration, and reference guides; updated architecture and READMEs to include mobile.
  • Tooling

    • Added Expo-specific lint and TypeScript configs, project reset and CI validation helpers, cached fetch/validator scripts, and workspace tooling for mobile.

- Add apps/mobile with Expo SDK 55, NativeWind v5, @repo/ui tokens
- Align mobile with monorepo: tsconfig, biome, eslint, cursor rules
- Add tools/typescript/expo.json, tools/eslint/expo.js
- Add dev-environments doc, narrow web-only cursor rules
- Fix packages/cli and turbo.json: apps/fastify -> apps/api for openapi
- Extract packages/ui tokens.css for shared design system
@vercel
Copy link

vercel bot commented Mar 12, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

3 Skipped Deployments
Project Deployment Actions Updated (UTC)
basilic-docs Ignored Ignored Preview Mar 12, 2026 9:53pm
basilic-fastify Ignored Ignored Preview Mar 12, 2026 9:53pm
basilic-next Ignored Ignored Preview Mar 12, 2026 9:53pm

@coderabbitai
Copy link

coderabbitai bot commented Mar 12, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Adds a new Expo-based mobile app (sources, assets, config, tooling), design tokens and UI token export, many documentation SKILLs and EAS tooling scripts (fetchCached, validate), workspace/tooling adjustments (ESLint, TypeScript, pnpm/turbo), updated OpenAPI generator path, and developer environment docs.

Changes

Cohort / File(s) Summary
Mobile scaffold & config
apps/mobile/app.json, apps/mobile/package.json, apps/mobile/.gitignore, apps/mobile/metro.config.cjs, apps/mobile/postcss.config.mjs, apps/mobile/eslint.config.js, apps/mobile/.vscode/*, apps/mobile/README.md, apps/mobile/scripts/reset-project.cjs
New Expo app manifest, package, build/tooling configs, editor settings, ESLint overrides, .gitignore, README and reset script. Inspect deps, scripts, ESLint ignores, and filesystem effects of reset script.
Mobile source: screens & components
apps/mobile/src/app/*, apps/mobile/src/components/*, apps/mobile/src/components/*.{web,tsx}, apps/mobile/src/components/ui/*, apps/mobile/src/components/*.{module.css,web.tsx}
Adds layout, Home/Explore screens and many cross-platform components (animated icon/splash, tabs, hint row, collapsible, external link, themed text/view, web badge). Note platform-specific files and new exports.
Styling, tokens & globals
apps/mobile/src/global.css, apps/mobile/src/components/animated-icon.module.css, packages/ui/src/styles/tokens.css, packages/ui/src/styles/globals.css, packages/ui/package.json
Introduces tokens.css, imports tokens into globals, new mobile global CSS and CSS module. Exposes ./tokens.css via packages/ui exports — validate token names and import paths.
Hooks, theming & types
apps/mobile/src/constants/theme.ts, apps/mobile/src/hooks/*, apps/mobile/src/declarations.d.ts, apps/mobile/nativewind-env.d.ts
Adds Colors/Fonts/Spacing, useTheme/useColorScheme (web hydration variant), useBottomTabInset, and CSS module/type declarations. Check hydration behavior and types.
Build tooling & generator
packages/cli/scripts/generate-cli.mjs, turbo.json
Switched OpenAPI input path from apps/fastify/... to apps/api/...; also expanded lint env vars in turbo. Ensure generator consumers and paths align.
Cursor SKILLs & EAS tooling scripts
.cursor/skills/expo-cicd-workflows-v55/*, .cursor/skills/expo-deployment-v55/*, .cursor/skills/expo-*, .cursor/skills/.../scripts/{fetch.js,validate.js,package.json}, skills-lock.json
Adds many SKILL.md docs, a cached fetch utility (fetch.js), YAML validator CLI (validate.js), and skill package.json; new skills lock file. Review cache semantics, schema fetch/validation, AJV usage, and CLI behavior.
Cursor rules / frontend adjustments
.cursor/rules/frontend/expo.mdc, .cursor/rules/frontend/*.mdc
Adds Expo frontend rule and narrows/adjusts glob patterns for existing frontend MDC rules (nextjs, mobile-first, design, shadcnui). Verify glob scopes and alwaysApply settings.
ESLint / TypeScript tooling
tools/eslint/expo.js, tools/eslint/package.json, tools/typescript/expo.json, tools/typescript/package.json, tools/typescript/README.md, biome.json
Adds exported Expo ESLint config, new Expo tsconfig, README updates, Biome overrides for apps/mobile, and new package exports. Review rule overrides and exported files.
Docs & dev environment updates
apps/docu/content/docs/development/dev-environments.mdx, apps/docu/content/docs/development/dev-tooling.mdx, apps/docu/content/docs/development/index.mdx, apps/docu/content/docs/architecture/monorepo.mdx, README.md
Adds Dev Environments guide (local vs remote, ports, tunneling), updates dev-tooling and architecture docs to include Mobile and new run commands. Verify example commands and port lists.
Workspace & package config
pnpm-workspace.yaml, package.json, skills-lock.json
Formatting tweaks to workspace globs, adds nodeLinker: hoisted, pins lightningcss in pnpm.overrides, and adds skills lock. Confirm workspace matching and pinned dependency.

Sequence Diagram(s)

sequenceDiagram
  participant CLI as CLI (validate.js)
  participant Fetch as fetchCached()
  participant Remote as Schema Server (remote URL)
  participant Cache as Local Cache (.cache)
  participant AJV as AJV Validator
  participant FS as Workflow Files

  CLI->>Fetch: request schema URL
  Fetch->>Cache: lookup hashed entry
  alt cache hit valid
    Cache-->>Fetch: cached data (ETag, expires)
  else cache miss or expired
    Fetch->>Remote: HTTP GET (If-None-Match)
    alt 304 Not Modified
      Remote-->>Fetch: 304 (no body)
      Fetch->>Cache: update expires
    else 200 OK
      Remote-->>Fetch: schema JSON + ETag/Cache-Control
      Fetch->>Cache: save entry (data, etag, expires)
    end
  end
  Fetch-->>CLI: schema JSON
  CLI->>AJV: compile + validate FS files (from FS)
  AJV-->>CLI: validation result (✓/✗)
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~55 minutes

Possibly related PRs

Poem

🐰 I hopped a code path, tidy and fleet,
Tabs and tokens now line my small street,
Fetch caches a schema, validator hums,
Docs, hooks, and badges — the orchard becomes,
A tiny rabbit cheers: "Build, run, repeat!"

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 6.45% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the primary change: adding a mobile Expo app with Tailwind and UI tokens, plus fixing the CLI API path.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch other-apps
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Note

Due to the large number of review comments, Critical severity comments were prioritized as inline comments.

🟠 Major comments (23)
.cursor/skills/expo-deployment-v55/references/testflight.md-7-11 (1)

7-11: ⚠️ Potential issue | 🟠 Major

Clarify the npx testflight command—it doesn't appear to exist without additional setup.

The command npx testflight is presented as a straightforward solution ("That's it. One command builds and submits to TestFlight") but cannot be found in the repository's package.json scripts, and it is not a standard Expo CLI command (which uses eas build and eas submit).

Either:

  1. It requires an external package to be installed (document which one and how)
  2. It is a custom wrapper that needs to be set up first (provide setup instructions)
  3. It is environment-specific or CI/CD-only (clarify scope)

Without this context, developers following this guide will encounter command-not-found errors. Add a brief explanation of what npx testflight is and how to configure it.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.cursor/skills/expo-deployment-v55/references/testflight.md around lines 7 -
11, The docs show running `npx testflight` but don’t explain what provides that
command; update the note around `npx testflight` to state whether it is an
external npm package (name and install command), a project script (add
instructions to add a "testflight" script to package.json and reference the
script), or a CI-only wrapper (describe CI setup/environment variables
required); in short, explicitly identify the source of `npx testflight`, give
the minimal setup steps to make it runnable (install or add script or CI
config), and clarify scope (local vs CI) so users won’t hit “command not found.”
.cursor/skills/expo-upgrading-v55/references/react-compiler.md-3-3 (1)

3-3: ⚠️ Potential issue | 🟠 Major

Remove incorrect New Architecture requirement from the Requirements section.

Line 3 is accurate—React Compiler is indeed stable in Expo SDK 54 and later. However, lines 44–45 incorrectly state that New Architecture is a requirement for React Compiler. According to official Expo documentation, React Compiler does not depend on New Architecture; it's configured separately via expo.experiments.reactCompiler and works with both Legacy and New Architecture. In SDK 54, you can use React Compiler with the Legacy Architecture by setting newArchEnabled: false.

Update the Requirements section to list only: "Expo SDK 54 or later" and remove the New Architecture reference, or clarify that it is not a requirement for React Compiler itself.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.cursor/skills/expo-upgrading-v55/references/react-compiler.md at line 3,
Update the Requirements section to remove the incorrect New Architecture
dependency: change the requirements text to only state "Expo SDK 54 or later"
(or clarify that React Compiler works with both Legacy and New Architecture) and
remove any claim that New Architecture is required for React Compiler; mention
that React Compiler is enabled via the expo.experiments.reactCompiler setting
and can be used with newArchEnabled set to false in SDK 54 if you need to
support the Legacy Architecture.
.cursor/skills/expo-deployment-v55/references/ios-app-store.md-68-70 (1)

68-70: ⚠️ Potential issue | 🟠 Major

Use --auto-submit here, not --submit.

Expo's current iOS submission docs use eas build --platform ios --auto-submit for the combined build+submit flow. The flag --submit does not exist in EAS CLI.

Proposed fix
 # Build and submit to App Store Connect
-eas build -p ios --profile production --submit
+eas build -p ios --profile production --auto-submit
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.cursor/skills/expo-deployment-v55/references/ios-app-store.md around lines
68 - 70, The command shown uses a non-existent flag (--submit); update the
build+submit command to use EAS CLI's correct flag (--auto-submit) by replacing
the existing invocation (eas build -p ios --profile production --submit) with
the combined build-and-submit form (eas build -p ios --profile production
--auto-submit) so the docs match Expo's current iOS submission flow.
.cursor/skills/expo-deployment-v55/references/ios-app-store.md-55-64 (1)

55-64: ⚠️ Potential issue | 🟠 Major

Complete the Apple ID authentication documentation with proper eas.json configuration.

The current section omits the required eas.json setup. Per Expo's iOS submit documentation, the Apple ID fallback requires both the configuration file and the app-specific password environment variable. Users following only the environment variable snippet will lack the necessary configuration to authenticate successfully.

Proposed fix
 ### Apple ID Authentication (Alternative)
 
-For manual submissions, you can use Apple ID:
+For non-API-key submissions, configure `appleId` in `eas.json` and provide an app-specific password:
 
-```bash
-EXPO_APPLE_ID=your@email.com
-EXPO_APPLE_TEAM_ID=XXXXXXXXXX
+```json
+{
+  "submit": {
+    "production": {
+      "ios": {
+        "appleId": "your@email.com"
+      }
+    }
+  }
+}
+```
+
+```bash
+EXPO_APPLE_APP_SPECIFIC_PASSWORD=xxxx-xxxx-xxxx-xxxx

-Note: Requires app-specific password for accounts with 2FA.
+Note: This fallback requires an app-specific password.

</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against the current code and only fix it if needed.

In @.cursor/skills/expo-deployment-v55/references/ios-app-store.md around lines
55 - 64, The Apple ID authentication doc is missing the required eas.json submit
configuration and the correct env var name for app-specific passwords; update
the section to show adding a submit.production.ios.appleId key in eas.json
(referencing "submit" -> "production" -> "ios" -> "appleId") and replace the
EXPO_APPLE_ID/EXPO_APPLE_TEAM_ID snippet with the correct environment variable
EXPO_APPLE_APP_SPECIFIC_PASSWORD (and note that an app-specific password is
required for 2FA) so readers have both the file-based config and the env var
needed for fallback authentication.


</details>

</blockquote></details>
<details>
<summary>.cursor/skills/expo-deployment-v55/references/ios-app-store.md-333-345 (1)</summary><blockquote>

`333-345`: _⚠️ Potential issue_ | _🟠 Major_

**Add required `build_id` parameter to submit job.**

EAS Workflows require `build_id` as a required parameter for `type: submit` jobs ([docs.expo.dev](https://docs.expo.dev/eas/workflows/pre-packaged-jobs/)). Without it, the workflow will fail with a "`build_id` required parameter" error. Pass the build ID output from the upstream build job.

<details>
<summary>Proposed fix</summary>

```diff
   submit:
     type: submit
     needs: [build]
     params:
-      platform: ios
+      build_id: ${{ needs.build.outputs.build_id }}
       profile: production
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.cursor/skills/expo-deployment-v55/references/ios-app-store.md around lines
333 - 345, The submit job is missing the required build_id parameter; update the
submit job (type: submit) to include a build_id param and pass the build job's
output (the build job's build_id output) as its value so submit receives the
upstream build ID (i.e., add params.build_id to the submit job and set it from
the build job's outputs).
.cursor/skills/expo-deployment-v55/references/ios-app-store.md-249-253 (1)

249-253: ⚠️ Potential issue | 🟠 Major

Fix inaccurate distribution certificate limit documentation.

The stated limit of "3 per Apple Developer account" is incorrect. Apple's current documentation confirms distribution certificates are team-level credentials, with only one of each distribution certificate type allowed per team. Update the line to reflect this:

Proposed fix
 ### Distribution Certificate
 
 - Required for App Store submissions
-- Limited to 3 per Apple Developer account
+- Team-level credential; only one of each distribution certificate type is allowed per team
 - Valid for 1 year
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.cursor/skills/expo-deployment-v55/references/ios-app-store.md around lines
249 - 253, Update the "Distribution Certificate" section: replace the inaccurate
line "Limited to 3 per Apple Developer account" with a statement that mirrors
Apple's docs—e.g., "Only one active distribution certificate of each type is
allowed per Apple Developer team (team-level credential)"; ensure the heading
"### Distribution Certificate" and surrounding bullets remain intact and the new
line clearly communicates the one-per-team limit.
apps/mobile/app.json-10-12 (1)

10-12: ⚠️ Potential issue | 🟠 Major

iOS icon path references non-existent file and will cause build failures.

The iOS configuration at line 11 sets icon to ./assets/expo.icon, which does not exist in the repository. The file extension .icon is also non-standard for image formats. The correct icon file is located at ./assets/images/icon.png (already properly configured at the root level on line 7). Remove the iOS-specific icon override to inherit from the root configuration, or update it to point to the correct file.

Proposed fix
     "ios": {
-      "icon": "./assets/expo.icon"
     },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/mobile/app.json` around lines 10 - 12, The ios-specific icon override
("ios" -> "icon") points to a non-existent and incorrectly named file
("./assets/expo.icon"); remove the "icon" key from the "ios" object so the app
will inherit the root-level icon, or update the "ios.icon" value to the correct
existing asset ("./assets/images/icon.png") to prevent iOS build failures.
apps/mobile/app.json-39-42 (1)

39-42: ⚠️ Potential issue | 🟠 Major

Install the React Compiler package to complete the setup.

The reactCompiler experiment is enabled in app.json, which is correct for Expo SDK 55. However, the babel-plugin-react-compiler package is not installed as a dependency. Expo SDK 55 automatically configures the Babel plugin through babel-preset-expo, but the compiler package itself must be explicitly added to devDependencies. Install it with:

pnpm add -D babel-plugin-react-compiler@beta

Optionally, also add react-compiler-runtime@beta if needed by your project setup.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/mobile/app.json` around lines 39 - 42, app.json enables the
"reactCompiler" experiment but the required package is missing; add the Babel
compiler package as a devDependency by running the installer and include the
package name "babel-plugin-react-compiler" (use pnpm add -D
babel-plugin-react-compiler@beta) and optionally add
"react-compiler-runtime@beta" if your setup needs it so the reactCompiler
experiment functions correctly.
.cursor/skills/expo-tailwind-setup-v55/SKILL.md-128-250 (1)

128-250: ⚠️ Potential issue | 🟠 Major

Re-export Image before documenting import { Image } from "@/tw".

The src/tw/index.tsx snippet never re-exports the wrapper from src/tw/image.tsx, so the usage example on Line 310 will not resolve as written. Either add a barrel export to index.tsx or change the example import path.

📝 Proposed doc fix
 // TouchableHighlight with underlayColor extraction
 function XXTouchableHighlight(
   props: React.ComponentProps<typeof RNTouchableHighlight>
 ) {
@@
 };
 TouchableHighlight.displayName = "CSS(TouchableHighlight)";
+
+export { Image } from "./image";

Also applies to: 252-291, 309-310

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.cursor/skills/expo-tailwind-setup-v55/SKILL.md around lines 128 - 250, The
docs reference importing Image from "@/tw" but src/tw/index.tsx never re-exports
the Image wrapper from src/tw/image.tsx; open src/tw/index.tsx and add a barrel
export for that component (e.g., export the Image symbol from "./image") so the
documented import import { Image } from "@/tw" resolves; ensure the export
appears alongside the other public exports (View, Text, ScrollView, Pressable,
TextInput, TouchableHighlight, AnimatedScrollView, Link, useCSSVariable) and
preserves the Image displayName if present.
.cursor/skills/expo-cicd-workflows-v55/scripts/fetch.js-5-8 (1)

5-8: ⚠️ Potential issue | 🟠 Major

Add timeout to prevent indefinite blocking on network requests.

This script fetches live schema/docs but the fetch() call on line 24 lacks an explicit timeout. If the remote endpoint hangs, the entire CI/CD workflow blocks indefinitely. Add an AbortSignal with a reasonable timeout:

♻️ Example timeout pattern
 const response = await fetch(url, {
+  signal: AbortSignal.timeout(30_000), // 30s timeout
   headers: {
     'Cache-Control': 'max-age=0',
     ...(cached?.etag && { 'If-None-Match': cached.etag }),
   },
 })

Also applies to: line 95

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.cursor/skills/expo-cicd-workflows-v55/scripts/fetch.js around lines 5 - 8,
The two fetch calls in this script currently have no timeout and can hang CI;
wrap each call with an AbortController: create a controller (or use a
FETCH_TIMEOUT_MS env with a default like 10000), set a setTimeout that calls
controller.abort() after the timeout, pass controller.signal into fetch(..., {
signal }), and ensure you clear the timer in a finally block so timers don't
leak; apply this pattern to both fetch invocations (the standalone fetch(...)
calls in this file) so network requests are aborted deterministically on
timeout.
.cursor/skills/expo-cicd-workflows-v55/scripts/fetch.js-20-45 (1)

20-45: ⚠️ Potential issue | 🟠 Major

Give remote fetches a deadline.

Lines 22-27 call external endpoints without any timeout. If the upstream stalls, this utility hangs indefinitely even when a stale cache exists locally. Add an AbortController deadline and fall back to cached data on abort/network failure.

🛡️ Proposed fix
-  const response = await fetch(url, {
-    headers: {
-      'Cache-Control': 'max-age=0',
-      ...(cached?.etag && { 'If-None-Match': cached.etag }),
-    },
-  })
+  const controller = new AbortController()
+  const timeout = setTimeout(() => controller.abort(), 30_000)
+  let response
+  try {
+    response = await fetch(url, {
+      signal: controller.signal,
+      headers: {
+        'Cache-Control': 'max-age=0',
+        ...(cached?.etag && { 'If-None-Match': cached.etag }),
+      },
+    })
+  } finally {
+    clearTimeout(timeout)
+  }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.cursor/skills/expo-cicd-workflows-v55/scripts/fetch.js around lines 20 -
45, Add a deadline using AbortController before calling fetch(url, ...) and pass
controller.signal into the fetch options; start a setTimeout to call
controller.abort() after a short timeout (e.g., configurable ms) and clear the
timer when fetch resolves. Catch AbortError or other network errors around the
fetch call and, if cached exists, refresh its expires (use getExpires if you can
derive headers else keep existing expires), call saveCacheEntry(cacheFile,
entry) and return cached.data; if no cached entry rethrow the error. Ensure you
still read etag/response/text when fetch succeeds and save the new cache as
before.
.cursor/skills/expo-tailwind-setup-v55/SKILL.md-149-159 (1)

149-159: ⚠️ Potential issue | 🟠 Major

The Link.* snippet does not type-check as written.

Link is inferred as a plain function component, so lines 156-159 add properties its type does not declare. Anyone copying this into a TSX file will get Property 'Trigger' does not exist... errors in strict TypeScript mode. Use Object.assign to properly type this pattern:

🛠️ Proposed fix
-// CSS-enabled Link
-export const Link = (
-  props: React.ComponentProps<typeof RouterLink> & { className?: string }
-) => {
-  return useCssElement(RouterLink, props, { className: "style" });
-};
-
-Link.Trigger = RouterLink.Trigger;
-Link.Menu = RouterLink.Menu;
-Link.MenuAction = RouterLink.MenuAction;
-Link.Preview = RouterLink.Preview;
+// CSS-enabled Link
+const LinkBase = (
+  props: React.ComponentProps<typeof RouterLink> & { className?: string }
+) => {
+  return useCssElement(RouterLink, props, { className: "style" });
+};
+
+export const Link = Object.assign(LinkBase, {
+  Trigger: RouterLink.Trigger,
+  Menu: RouterLink.Menu,
+  MenuAction: RouterLink.MenuAction,
+  Preview: RouterLink.Preview,
+});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.cursor/skills/expo-tailwind-setup-v55/SKILL.md around lines 149 - 159, The
function component Link (created via useCssElement and RouterLink) is inferred
as a plain function so assigning Link.Trigger/Menu/... later fails
type-checking; change the export to create Link with Object.assign so the static
members are attached with proper typing: build Link as a const function
component (using useCssElement(RouterLink, props, ...)) and then do
Object.assign(Link, { Trigger: RouterLink.Trigger, Menu: RouterLink.Menu,
MenuAction: RouterLink.MenuAction, Preview: RouterLink.Preview }), and annotate
Link's type to combine React.ComponentType<Props> with the static members (or
use typeof RouterLink for the static part) so TypeScript recognizes the added
properties; refer to symbols Link, RouterLink, and useCssElement to locate and
update the code.
apps/mobile/src/components/external-link.tsx-6-23 (1)

6-23: ⚠️ Potential issue | 🟠 Major

Guard against non-external URLs on native before intercepting navigation.

Line 6 accepts any Href type (including internal routes like /explore and relative paths), but lines 15-20 unconditionally prevent default and pass the value to openBrowserAsync. This creates a silent failure: internal routes work on web but break on iOS/Android. Add a check to ensure only external URLs (those with URI schemes) trigger the in-app browser behavior.

🐛 Proposed fix
 export function ExternalLink({ href, ...rest }: Props) {
   return (
     <Link
       target="_blank"
       {...rest}
       href={href}
       onPress={async event => {
-        if (process.env.EXPO_OS !== 'web') {
+        const isExternal = /^[a-z][a-z0-9+.-]*:/.test(href)
+        if (process.env.EXPO_OS !== 'web' && isExternal) {
           // Prevent the default behavior of linking to the default browser on native.
           event.preventDefault()
           // Open the link in an in-app browser.
           await openBrowserAsync(href, {
             presentationStyle: WebBrowserPresentationStyle.AUTOMATIC,
           })
         }
       }}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/mobile/src/components/external-link.tsx` around lines 6 - 23, The
onPress handler in ExternalLink currently intercepts all Href values (including
internal routes) and always calls event.preventDefault() and openBrowserAsync;
change it to first detect whether href is an external URI (has a scheme like
https:// or any scheme://) and only in that case preventDefault and call
openBrowserAsync; if href is a path/relative/internal route (e.g., starts with
"/" or lacks a scheme) do not call preventDefault so Link can handle navigation
natively. Update the onPress logic that references href, openBrowserAsync, and
WebBrowserPresentationStyle.AUTOMATIC accordingly.
.cursor/skills/expo-upgrading-v55/SKILL.md-10-12 (1)

10-12: ⚠️ Potential issue | 🟠 Major

Correct the React 19 migration note to reflect optional alternatives, not breaking changes.

Line 11 mischaracterizes React 19 changes as forced migrations. In reality:

  • use(Context) is a new optional alternative; useContext() still works normally
  • <Context> is a new provider syntax; <Context.Provider> still works (marked legacy, not removed)
  • ref as a prop is new; forwardRef is deprecated but not removed

The current phrasing (useContext → use, Context.Provider → Context, forwardRef removal) will mislead developers to rewrite code unnecessarily. A skill file must guide upgrades accurately.

📝 Proposed fix
-- ./references/react-19.md -- SDK +54: React 19 changes (useContext → use, Context.Provider → Context, forwardRef removal)
+- ./references/react-19.md -- SDK +54: React 19 changes (use() can consume Context, <Context> is supported as provider alternative to <Context.Provider>, ref can be passed as a prop instead of forwardRef)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.cursor/skills/expo-upgrading-v55/SKILL.md around lines 10 - 12, Update the
React 19 migration note to avoid implying breaking changes: change the phrasing
around useContext → use to state that use(Context) is an optional alternative
and useContext() continues to work; change Context.Provider → Context to note
that <Context> is a new provider syntax while <Context.Provider> remains
supported (legacy) and not removed; and replace "forwardRef removal" with a note
that ref as a prop is promoted and forwardRef is deprecated/legacy but not
removed, so developers can opt-in to the new patterns rather than being forced
to rewrite existing code.
.cursor/skills/expo-cicd-workflows-v55/scripts/validate.js-27-35 (1)

27-35: ⚠️ Potential issue | 🟠 Major

Handle schema and file I/O failures without crashing the whole run.

A missing workflow file, a bad cached schema, or a transient fetch failure currently throws out of the CLI and skips the remaining files. This should be reported as a normal validation failure so CI still gets deterministic output for every input.

Suggested hardening
 async function validateFile(validator, filePath) {
-  const content = await readFile(filePath, 'utf-8')
+  let content
+  try {
+    content = await readFile(filePath, 'utf-8')
+  } catch (error) {
+    const message = error instanceof Error ? error.message : String(error)
+    return { valid: false, error: `Unable to read file: ${message}` }
+  }
 
   let doc
   try {
     doc = yaml.load(content)
@@
 if (import.meta.main) {
   const args = process.argv.slice(2)
   const files = args.filter(a => !a.startsWith('-'))
@@
-  const schema = await fetchSchema()
-  const validator = createValidator(schema)
+  let validator
+  try {
+    validator = createValidator(await fetchSchema())
+  } catch (error) {
+    const message = error instanceof Error ? error.message : String(error)
+    console.error(`✗ Failed to load workflow schema\n${message}`)
+    process.exit(1)
+  }
@@
   for (const file of files) {
     const filePath = resolve(process.cwd(), file)
-    const result = await validateFile(validator, filePath)
+    const result = await validateFile(validator, filePath)
 
     if (result.valid) {
       console.log(`✓ ${file}`)

Also applies to: 66-83

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.cursor/skills/expo-cicd-workflows-v55/scripts/validate.js around lines 27 -
35, The validateFile function currently lets file I/O, YAML parsing, schema
fetching, or schema validation errors throw and abort the run; change
validateFile (and the related validation block around lines 66-83) to catch
errors from readFile, yaml.load, validator.fetchSchema (or equivalent), and
validator.validate calls and convert them into a deterministic result object
(e.g., return { valid: false, error: '...' }) instead of throwing; include the
actionable error message from the caught exception in the returned error string
so each file produces a normal validation failure rather than crashing the CLI.
apps/mobile/src/constants/theme.ts-62-62 (1)

62-62: ⚠️ Potential issue | 🟠 Major

Don’t hardcode the bottom tab inset.

A fixed 50/80 spacer will be wrong on devices with different safe-area bottoms or tab bar heights, so some screens will end up clipped and others over-padded. This needs to come from runtime safe-area data instead of a compile-time constant.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/mobile/src/constants/theme.ts` at line 62, BottomTabInset is a
compile-time constant and must be replaced with a runtime value derived from
safe-area insets; remove the hardcoded export and either (A) export a function
like getBottomTabInset(insets: EdgeInsets) that returns Platform.select({ ios:
insets.bottom + baseIosOffset, android: insets.bottom + baseAndroidOffset }) or
(B) add a hook useBottomTabInset() that calls useSafeAreaInsets() from
react-native-safe-area-context and returns the computed inset; update callers to
use the function/hook instead of the BottomTabInset constant (reference
BottomTabInset, getBottomTabInset, useBottomTabInset, and useSafeAreaInsets to
locate and replace usages).
apps/mobile/src/components/ui/collapsible.tsx-18-21 (1)

18-21: ⚠️ Potential issue | 🟠 Major

Expose the toggle state to accessibility APIs.

Right now the open/closed state is only visible on screen. Add button semantics and an expanded accessibility state so screen-reader users know this control is interactive and whether the section is open.

Minimal fix
       <Pressable
+        accessibilityRole="button"
+        accessibilityState={{ expanded: isOpen }}
         style={({ pressed }) => [styles.heading, pressed && styles.pressedHeading]}
         onPress={() => setIsOpen(value => !value)}
       >
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/mobile/src/components/ui/collapsible.tsx` around lines 18 - 21, The
Pressable used for the collapsible header should expose its interactive role and
current open/closed state to accessibility APIs: add accessibilityRole="button"
and pass accessibilityState={{ expanded: isOpen }} (or expanded:
Boolean(isOpen)) to the Pressable that currently uses setIsOpen in the onPress
handler; ensure the Pressable references the component's isOpen state so screen
readers can announce whether the section is expanded.
apps/mobile/src/components/themed-view.tsx-3-15 (1)

3-15: ⚠️ Potential issue | 🟠 Major

Implement or remove lightColor / darkColor.

These props are part of the public API but never affect the rendered style, so consumers cannot override the background the way the type suggests. Either honor them here or drop them from ThemedViewProps.

One way to honor the overrides
 import type { ThemeColor } from '@/constants/theme'
+import { useColorScheme } from '@/hooks/use-color-scheme'
 import { useTheme } from '@/hooks/use-theme'
@@
 export function ThemedView({ style, lightColor, darkColor, type, ...otherProps }: ThemedViewProps) {
+  const scheme = useColorScheme()
   const theme = useTheme()
+  const backgroundColor =
+    scheme === 'dark' ? (darkColor ?? theme[type ?? 'background']) : (lightColor ?? theme[type ?? 'background'])
 
-  return <View style={[{ backgroundColor: theme[type ?? 'background'] }, style]} {...otherProps} />
+  return <View style={[{ backgroundColor }, style]} {...otherProps} />
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/mobile/src/components/themed-view.tsx` around lines 3 - 15, The props
lightColor and darkColor on ThemedViewProps are declared but never used; either
remove them from ThemedViewProps and the ThemedView parameter list, or apply
them when rendering: inside ThemedView (which uses useTheme()), determine
whether the theme is dark (e.g., theme.mode === 'dark' or theme.isDark — inspect
theme shape) and choose backgroundColor = darkColor ?? theme[type ??
'background'] when dark or backgroundColor = lightColor ?? theme[type ??
'background'] when light, then use that computed backgroundColor in the style
prop instead of directly using theme[type ?? 'background'].
apps/mobile/src/hooks/use-theme.ts-9-13 (1)

9-13: ⚠️ Potential issue | 🟠 Major

Guard this lookup against any non-light/dark scheme.

If the wrapper hook ever returns null or another sentinel, Colors[theme] becomes undefined and every themed component downstream breaks. A safer fallback here is to treat anything other than 'dark' as 'light'.

Small defensive fix
 export function useTheme() {
   const scheme = useColorScheme()
-  const theme = scheme === 'unspecified' ? 'light' : scheme
+  const theme = scheme === 'dark' ? 'dark' : 'light'
 
   return Colors[theme]
 }
#!/bin/bash
# Verify what the local wrapper can return before deciding whether this is already safe.
fd '^use-color-scheme(\.web)?\.ts$' apps/mobile/src/hooks -x sh -c '
  echo "### $1"
  sed -n "1,160p" "$1"
' sh {}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/mobile/src/hooks/use-theme.ts` around lines 9 - 13, The hook useTheme
uses useColorScheme and currently maps 'unspecified' to 'light' but doesn't
guard other unexpected returns, causing Colors[theme] to be undefined; change
the lookup so any value other than 'dark' is treated as 'light' (e.g. derive a
normalizedTheme = theme === 'dark' ? 'dark' : 'light') and return
Colors[normalizedTheme], ensuring the fallback is always a valid key for the
Colors object (reference: useTheme, useColorScheme, Colors, theme).
apps/mobile/src/components/web-badge.tsx-1-15 (1)

1-15: ⚠️ Potential issue | 🟠 Major

Use a default import for the Expo JSON module.

Named imports are not supported from JSON modules in TypeScript ESM. Change to a default import and access the .version property.

🔧 Proposed fix
-import { version } from 'expo/package.json'
+import expoPackage from 'expo/package.json'
@@
-        v{version}
+        v{expoPackage.version}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/mobile/src/components/web-badge.tsx` around lines 1 - 15, The current
named import "import { version } from 'expo/package.json'" is invalid for JSON
ESM; change it to a default import (e.g. import expoPkg from
'expo/package.json') and then use expoPkg.version where the component references
version (inside the WebBadge component and its JSX, e.g. v{expoPkg.version});
update any references to the symbol "version" accordingly so WebBadge uses the
default-imported object.
apps/mobile/src/components/app-tabs.web.tsx-44-45 (1)

44-45: ⚠️ Potential issue | 🟠 Major

Handle the actual null return value from useColorScheme().

useColorScheme() returns 'light' | 'dark' | null—never 'unspecified'. When scheme is null, the ternary expression scheme === 'unspecified' ? 'light' : scheme evaluates to scheme, leaving Colors[null] undefined. This causes colors.text on line 60 to throw at runtime when the OS has no theme preference. Use scheme ?? 'light' to handle both the null case and provide a sensible default.

🔧 Proposed fix
   const scheme = useColorScheme()
-  const colors = Colors[scheme === 'unspecified' ? 'light' : scheme]
+  const colors = Colors[scheme ?? 'light']
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/mobile/src/components/app-tabs.web.tsx` around lines 44 - 45, The code
uses useColorScheme() into scheme and indexes Colors with it, but
useColorScheme() can return null (not 'unspecified') which makes Colors[null]
undefined; update the lookup in app-tabs.web.tsx to default scheme to 'light'
(e.g., use the nullish coalescing pattern: scheme ?? 'light') so Colors is
always indexed by 'light' or 'dark' and colors.text won't throw; change the line
that sets colors (the Colors[...] expression) to use scheme ?? 'light'.
tools/eslint/expo.js-185-193 (1)

185-193: ⚠️ Potential issue | 🟠 Major

Contradictory rule configuration effectively disables import/no-default-export.

This final override block applies to all **/*.{ts,tsx} files and sets 'import/no-default-export': 'off'. However, line 102 sets this rule to 'error' for the same file pattern. Since ESLint applies overrides in order, this final block effectively disables the rule for all TypeScript files, making the earlier 'error' setting and the specific allow-list overrides (lines 122-140) redundant.

If the intent is to enforce named exports by default with specific exceptions, remove this line from the final override block.

🐛 Proposed fix
   // RN/Expo: require() for assets, process.env, default exports, naming (INITIAL_SCALE_FACTOR, experimental_*)
   {
     files: ['**/*.{ts,tsx}'],
     rules: {
       '@typescript-eslint/no-require-imports': 'off',
       'no-restricted-properties': 'off',
-      'import/no-default-export': 'off',
       '@typescript-eslint/naming-convention': 'off',
     },
   },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tools/eslint/expo.js` around lines 185 - 193, The final override block in
tools/eslint/expo.js currently sets the ESLint rule 'import/no-default-export'
to 'off', which contradicts the earlier override that sets it to 'error' and
nullifies the allow-list exceptions; remove the "'import/no-default-export':
'off'" entry from that final override (the object with files: ['**/*.{ts,tsx}']
and rules {...}) so the earlier 'error' default and the specific allow-list
exceptions (the earlier override for 'import/no-default-export') remain
effective.
apps/docu/content/docs/development/dev-environments.mdx-192-195 (1)

192-195: ⚠️ Potential issue | 🟠 Major

Fix relative link path to .cursor/ file.

The link (.cursor/commands/onboard-new-developer.md) uses an incorrect relative path. From apps/docu/content/docs/development/, this resolves to apps/docu/content/docs/development/.cursor/commands/onboard-new-developer.md, which doesn't exist. Use the correct relative path: ../../../../.cursor/commands/onboard-new-developer.md (following the pattern in other MDX files like frontend-testing.mdx).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/docu/content/docs/development/dev-environments.mdx` around lines 192 -
195, The relative link to the onboard guide is incorrect; update the link target
in the "Related" list (the markdown link currently pointing to
"(.cursor/commands/onboard-new-developer.md)") to the correct relative path
"../../../../.cursor/commands/onboard-new-developer.md" so it resolves from the
current docs folder (match the pattern used in other MDX files like
frontend-testing.mdx).
🟡 Minor comments (16)
apps/docu/content/docs/architecture/monorepo.mdx-39-57 (1)

39-57: ⚠️ Potential issue | 🟡 Minor

Mobile node is disconnected in the dependency graph.

The Mobile node (line 42) is defined but has no edges connecting it to any packages. This makes it an orphan in the diagram, which doesn't accurately represent the architecture. The Expo mobile app likely depends on shared packages such as React, Core, or UI.

Consider adding the appropriate dependency edges, for example:

📝 Suggested diagram update
   Email --> API
   Utils --> Web
   Web -->|HTTP| API
+  React --> Mobile
+  Core --> Mobile
+  UI --> Mobile
+  Mobile -->|HTTP| API

As per coding guidelines, documentation should follow standards defined in .cursor/rules/base/docs.mdc to accurately represent the system architecture.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/docu/content/docs/architecture/monorepo.mdx` around lines 39 - 57, The
Mobile node is defined but has no dependency edges; update the diagram to
connect Mobile to the shared packages it depends on (e.g., add edges such as
Mobile --> React, Mobile --> Core and/or Mobile --> UI) so it is not an orphan;
locate the Mobile node in the graph and add the appropriate arrow(s) referencing
the Mobile, React, Core, and UI node names to reflect the Expo app's
dependencies and comply with the docs rules.
.cursor/commands/onboard-new-developer.md-6-6 (1)

6-6: ⚠️ Potential issue | 🟡 Minor

Update reference to align with renamed API directory.

The step still mentions "Fastify + Next.js" but the PR renames apps/fastifyapps/api. Consider updating to "API + Next.js" or "API server + Next.js" for clarity and consistency with the new naming convention.

📝 Proposed fix
-4. **Run web/API**: `pnpm dev` (Fastify + Next.js)
+4. **Run web/API**: `pnpm dev` (API + Next.js)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.cursor/commands/onboard-new-developer.md at line 6, Update the onboarding
step that currently reads "Run web/API: `pnpm dev` (Fastify + Next.js)" to
reflect the renamed directory by replacing "Fastify + Next.js" with a clearer
label such as "API + Next.js" or "API server + Next.js"; edit the line
containing "Run web/API" so the parenthetical accurately references the new
naming convention instead of "Fastify".
.cursor/skills/expo-upgrading-v55/references/react-19.md-75-79 (1)

75-79: ⚠️ Potential issue | 🟡 Minor

SDK version consistency: checklist mentions SDK 54.

The checklist header says "When upgrading to SDK 54" but this file is in the expo-upgrading-v55 folder. Ensure the version reference matches the intended upgrade target.

🔧 Suggested fix (if SDK 55 is correct)
-When upgrading to SDK 54:
+When upgrading to SDK 55:
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.cursor/skills/expo-upgrading-v55/references/react-19.md around lines 75 -
79, The checklist header "When upgrading to SDK 54" is inconsistent with this
file being under expo-upgrading-v55; update the header text to "When upgrading
to SDK 55" (or, if the checklist is meant for SDK 54, move the file to the
correct folder) and verify any version-specific notes in the checklist items
(the lines referencing useContext/use/.Provider/forwardRef) reflect SDK 55
behavior.
.cursor/skills/expo-upgrading-v55/references/react-19.md-22-22 (1)

22-22: ⚠️ Potential issue | 🟡 Minor

Fix grammar: comma splice creates a run-on sentence.

The sentence contains a comma splice. Consider restructuring for clarity.

✏️ Suggested fix

Choose one of these options:

-- `use` can be called conditionally, this simplifies components that consume multiple contexts.
+- `use` can be called conditionally, which simplifies components that consume multiple contexts.

Or:

-- `use` can be called conditionally, this simplifies components that consume multiple contexts.
+- `use` can be called conditionally. This simplifies components that consume multiple contexts.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.cursor/skills/expo-upgrading-v55/references/react-19.md at line 22, The
sentence "`use` can be called conditionally, this simplifies components that
consume multiple contexts." contains a comma splice; fix it by either splitting
into two sentences ("`use` can be called conditionally. This simplifies
components that consume multiple contexts."), using a semicolon ("`use` can be
called conditionally; this simplifies components that consume multiple
contexts."), or rephrasing to a single clause ("Because `use` can be called
conditionally, components that consume multiple contexts are simplified.").
Choose one option and replace the current sentence accordingly.
.cursor/skills/expo-upgrading-v55/references/react-19.md-3-3 (1)

3-3: ⚠️ Potential issue | 🟡 Minor

Correct the React 19 SDK version reference.

React 19 was first included in Expo SDK 53, not SDK 54. Update line 3 to accurately reflect this: either state "React 19 is included in Expo SDK 53 and later" or reference SDK 53 as the introduction point.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.cursor/skills/expo-upgrading-v55/references/react-19.md at line 3, Update
the incorrect SDK version mention in the sentence "React 19 is included in Expo
SDK 54. This release simplifies several common patterns." Replace "Expo SDK 54"
with the correct introduction SDK ("Expo SDK 53") or rephrase to "Expo SDK 53
and later" so the statement accurately reflects that React 19 was first included
in SDK 53; edit the exact string in the document to one of these corrected
variants.
.cursor/skills/expo-deployment-v55/references/testflight.md-52-53 (1)

52-53: ⚠️ Potential issue | 🟡 Minor

Update the autoIncrement configuration to specify the correct location and structure.

The suggestion autoIncrement: true is incomplete and misleading. For Expo SDK 55, autoIncrement must be placed in a build profile under the ios section:

Correct configuration
{
  "build": {
    "production": {
      "ios": {
        "autoIncrement": "buildNumber"
      }
    }
  }
}

Valid values: false, true, "version", or "buildNumber".

Alternatively, with remote versioning, set cli.appVersionSource: "remote" at the root level and use autoIncrement: true in the profile.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.cursor/skills/expo-deployment-v55/references/testflight.md around lines 52
- 53, The suggestion to use `autoIncrement: true` is incomplete; update
`eas.json` so `autoIncrement` is placed inside a build profile's `ios` section
(e.g., under `"build" -> "<profile>" -> "ios"`) and use a valid value (`false`,
`true`, "version", or "buildNumber") such as `"autoIncrement": "buildNumber"`;
alternatively, if using remote versioning set `cli.appVersionSource: "remote"`
at the root of `eas.json` and then you may use `autoIncrement: true` in the
profile—ensure you modify the `build` profile for the relevant profile name and
the `ios` key rather than placing `autoIncrement` at the top level.
.cursor/skills/expo-upgrading-v55/references/react-compiler.md-1-1 (1)

1-1: ⚠️ Potential issue | 🟡 Minor

Add MDC frontmatter to the documentation file.

Cursor documentation files should include frontmatter metadata for proper categorization and tooling integration. As per coding guidelines, ensure rules follow MDC format with frontmatter.

📋 Suggested frontmatter structure
+---
+title: React Compiler
+description: Guide to enabling and using React Compiler in Expo SDK 54+
+category: expo-upgrading
+sdk: 54+
+---
+
 # React Compiler
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.cursor/skills/expo-upgrading-v55/references/react-compiler.md at line 1,
This file is missing MDC frontmatter metadata; add a frontmatter block at the
top of the "React Compiler" document containing MDC-compliant keys such as id
(slug), title ("React Compiler"), description, tags (array), category, and any
mdc-specific fields required by our tooling (e.g., draft: false, published: true
or locale if used); ensure the frontmatter is the first content in the file so
tools can parse it and that the existing "React Compiler" header remains after
the frontmatter.
.cursor/skills/expo-deployment-v55/references/ios-app-store.md-283-283 (1)

283-283: ⚠️ Potential issue | 🟡 Minor

Use the repo’s @ cross-reference format here.

This relative path won’t satisfy the Cursor docs convention for cross-references inside .cursor/**. Switch it to the required @... form so tooling can resolve it consistently.

As per coding guidelines, "Verify cross-references use @ syntax correctly."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.cursor/skills/expo-deployment-v55/references/ios-app-store.md at line 283,
Replace the relative link "./app-store-metadata.md" with the repo's Cursor
cross-reference syntax using an `@-prefixed` reference (e.g., change the string
"See ./app-store-metadata.md for detailed configuration." to use the required
"@..." cross-reference form); update the line that contains
"./app-store-metadata.md" so tooling can resolve it consistently and adhere to
the Cursor docs convention.
.cursor/skills/expo-deployment-v55/references/ios-app-store.md-225-225 (1)

225-225: ⚠️ Potential issue | 🟡 Minor

Avoid a past release date in a copy-paste example.

2025-03-01T10:00:00Z is already in the past as of March 12, 2026, so this reads as stale documentation. Use a placeholder or obviously future sample instead.

Proposed fix
-      "automaticRelease": "2025-03-01T10:00:00Z"
+      "automaticRelease": "YYYY-MM-DDTHH:mm:ssZ"

As per coding guidelines, "Check documentation is up to date."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.cursor/skills/expo-deployment-v55/references/ios-app-store.md at line 225,
The example uses a past timestamp for the "automaticRelease" field
("2025-03-01T10:00:00Z"), making the documentation look stale; update the sample
in ios-app-store.md by replacing that hard-coded past datetime with either an
obviously future sample (e.g., a date > now) or a neutral placeholder like
"YYYY-MM-DDTHH:MM:SSZ" so readers see a valid, non-stale value for the
automaticRelease field.
tools/typescript/README.md-82-100 (1)

82-100: ⚠️ Potential issue | 🟡 Minor

Add explicit subpath exports to the @repo/typescript-config package.json.

The documentation references @repo/typescript-config/expo.json, which currently works due to workspace dependency resolution, but the package.json lacks an explicit exports field to declare these subpaths. Add an exports field to document and guarantee the availability of base.json, expo.json, nextjs.json, and react-library.json:

{
  "exports": {
    "./base.json": "./base.json",
    "./expo.json": "./expo.json",
    "./nextjs.json": "./nextjs.json",
    "./react-library.json": "./react-library.json"
  }
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tools/typescript/README.md` around lines 82 - 100, The package
`@repo/typescript-config` is missing explicit subpath exports, so add an "exports"
field in that package's package.json that maps "./base.json", "./expo.json",
"./nextjs.json", and "./react-library.json" to their respective files
(base.json, expo.json, nextjs.json, react-library.json) so imports like
`@repo/typescript-config/expo.json` are guaranteed; update package.json in the
`@repo/typescript-config` package to include this exports object and
publish/update the workspace so the subpaths are resolvable.
.cursor/skills/expo-dev-client-v55/SKILL.md-160-164 (1)

160-164: ⚠️ Potential issue | 🟡 Minor

Incorrect command for updating EAS CLI.

eas update is used for publishing OTA updates to your app, not for updating the EAS CLI itself. To update the CLI, use npm/pnpm.

📝 Proposed fix
 **Check EAS CLI version:**
 ```bash
 eas --version
-eas update
+npm install -g eas-cli@latest
</details>

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against the current code and only fix it if needed.

In @.cursor/skills/expo-dev-client-v55/SKILL.md around lines 160 - 164, Replace
the incorrect CLI update instruction eas update with the proper package
manager command to upgrade the EAS CLI (e.g., use npm install -g eas-cli@latest or the equivalent pnpm/yarn global install), and update the
"Check EAS CLI version" section so it shows the version check eas --version
followed by the correct installation command for updating the EAS CLI.


</details>

</blockquote></details>
<details>
<summary>.cursor/skills/expo-deployment-v55/references/app-store-metadata.md-44-53 (1)</summary><blockquote>

`44-53`: _⚠️ Potential issue_ | _🟡 Minor_

**Make the `keywords` examples consistent.**

Line 48 shows `keywords` as an array of individual values, but Lines 130-132 and 219-224 switch to a single comma-delimited blob inside that array. Please pick one representation and update every snippet to match; right now readers cannot safely copy/paste these examples.



Also applies to: 124-134, 215-224

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against the current code and only fix it if needed.

In @.cursor/skills/expo-deployment-v55/references/app-store-metadata.md around
lines 44 - 53, The examples use two different formats for the "keywords" field;
pick one consistent representation (preferably an array of individual strings
like "keywords": ["keyword1","keyword2","keyword3"]) and update every snippet
that defines "keywords" so they all match that format — specifically update the
instances shown around the current snippet and the other occurrences (the blocks
referenced at 124-134 and 215-224) so copy/paste works reliably and all examples
use the same array-of-strings style.


</details>

</blockquote></details>
<details>
<summary>.cursor/skills/expo-deployment-v55/SKILL.md-16-21 (1)</summary><blockquote>

`16-21`: _⚠️ Potential issue_ | _🟡 Minor_

**Fix the skill references before merge.**

These links are inconsistent and some point to a non-existent `./reference/...` directory, so readers will hit dead references. In Cursor skills, use the expected reference syntax consistently and fix the directory name everywhere.  


As per coding guidelines, "Verify cross-references use @ syntax correctly" and "Check documentation is up to date".


Also applies to: 123-136, 165-165

<details>
<summary>🤖 Prompt for AI Agents</summary>

Verify each finding against the current code and only fix it if needed.

In @.cursor/skills/expo-deployment-v55/SKILL.md around lines 16 - 21, Update the
broken reference links in SKILL.md so they use the Cursor expected @ syntax and
the correct directory name: replace any occurrences of "./references/..." or
"./reference/..." with "@references/..." for entries like workflows.md,
testflight.md, app-store-metadata.md, play-store.md and ios-app-store.md; also
sweep the file (including the other affected ranges around lines 123-136 and
line 165) and fix any remaining inconsistent reference forms so all
cross-references use the same "@references/.md" syntax.


</details>

</blockquote></details>
<details>
<summary>apps/mobile/src/components/hint-row.tsx-7-17 (1)</summary><blockquote>

`7-17`: _⚠️ Potential issue_ | _🟡 Minor_

**Narrow `hint` prop type to match `ThemedText` rendering constraints.**

`hint` is typed as `ReactNode` but is always rendered inside `ThemedText`. React Native's `<Text>` component primarily supports text nodes and nested `<Text>` elements. While `<View>` inside `<Text>` is supported since React Native 0.63, embedding interactive components like `Pressable` can cause layout and interaction issues. Restrict the prop to `string | number`, or refactor to render rich content outside the text component.

<details>
<summary>🔧 Proposed fix</summary>

```diff
 type HintRowProps = {
   title?: string
-  hint?: ReactNode
+  hint?: string | number
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/mobile/src/components/hint-row.tsx` around lines 7 - 17, The hint prop
is currently typed as ReactNode but is always rendered inside ThemedText; narrow
HintRowProps.hint to only allow text-like values (string | number) or refactor
HintRow to render non-text content outside ThemedText; update the HintRowProps
type definition and the HintRow signature (HintRowProps, HintRow, hint) to use
hint: string | number (or change the render to place hint into a View instead of
ThemedText) so ThemedText only receives supported text values.
.cursor/skills/expo-upgrading-v55/references/expo-av-to-audio.md-62-75 (1)

62-75: ⚠️ Potential issue | 🟡 Minor

Update recorder example to use non-deprecated record() calling convention.

The expo-audio recorder API usage is correct. However, the record() call uses the deprecated no-arg form. Update to record({ forDuration: seconds }) or use recordForDuration(seconds) to align with current best practices documented in expo-audio.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.cursor/skills/expo-upgrading-v55/references/expo-av-to-audio.md around
lines 62 - 75, The recorder example uses the deprecated no-arg recorder.record()
call; update startRecording to call either recorder.recordForDuration(seconds)
or recorder.record({ forDuration: seconds }) after prepareToRecordAsync(),
passing an explicit duration value; ensure the stopRecording logic still awaits
recorder.stop() and reads recorder.uri as before. Reference: update the
startRecording function and the recorder.record invocation (and choose either
recordForDuration or record({ forDuration })) to remove the deprecated no-arg
call.
.cursor/skills/expo-upgrading-v55/references/native-tabs.md-1-4 (1)

1-4: ⚠️ Potential issue | 🟡 Minor

Missing MDC frontmatter.

Per coding guidelines for .cursor/** files, rules/skills documentation should follow MDC format with frontmatter. This reference document lacks the expected frontmatter metadata (e.g., title, description, globs).

📝 Proposed fix to add frontmatter
+---
+title: "Native Tabs Migration (SDK 55)"
+description: "Migration guide for expo-router native tabs from SDK 53/54 to SDK 55"
+---
+
 # Native Tabs Migration (SDK 55)

As per coding guidelines: "Ensure rules follow MDC format with frontmatter" for files matching .cursor/**.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.cursor/skills/expo-upgrading-v55/references/native-tabs.md around lines 1 -
4, The file is missing MDC frontmatter required for .cursor/** docs; add a
frontmatter block at the top containing at minimum title, description, and globs
(e.g., a descriptive title like "Native Tabs Migration (SDK 55)", a short
description mentioning `NativeTabs.Trigger` and the static props `Label`,
`Icon`, `Badge`, `VectorIcon`, and globs that match this document), ensuring the
metadata follows your project's MDC frontmatter schema so the doc is recognized
and indexed correctly.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 19

🧹 Nitpick comments (5)
biome.json (1)

116-125: Correct rule override, but glob pattern is inconsistent with line 191.

Disabling useNodejsImportProtocol is appropriate since React Native/Metro doesn't support node: prefixed imports. However, this uses apps/mobile/** while line 191 uses **/apps/mobile/** for the same path.

♻️ Align pattern with the rest of the file
     {
-      "includes": ["apps/mobile/**"],
+      "includes": ["**/apps/mobile/**"],
       "linter": {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@biome.json` around lines 116 - 125, The glob for the override currently uses
"apps/mobile/**" which is inconsistent with the other entry that uses
"**/apps/mobile/**"; update the includes entry to "**/apps/mobile/**" so the
rule override for "useNodejsImportProtocol" under the linter applies
consistently to the mobile app path (reference the "includes" array and the
"useNodejsImportProtocol" rule).
apps/mobile/src/components/app-tabs.web.tsx (1)

30-33: Merge forwarded style props in the asChild wrappers.

TabList/TabTrigger in asChild mode forward their props to the immediate child, and those components inherit normal View/Pressable props. Setting style= after {...props} drops any forwarded or caller-supplied styles, which makes these wrappers brittle and can silently discard future library styling. Merge props.style instead. (docs.expo.dev)

♻️ Proposed fix
 export function TabButton({ children, isFocused, ...props }: TabTriggerSlotProps) {
   return (
-    <Pressable {...props} style={({ pressed }) => pressed && styles.pressed}>
+    <Pressable
+      {...props}
+      style={(state) => [
+        typeof props.style === 'function' ? props.style(state) : props.style,
+        state.pressed ? styles.pressed : undefined,
+      ]}
+    >
       <ThemedView
         type={isFocused ? 'backgroundSelected' : 'backgroundElement'}
         style={styles.tabButtonView}
       >
         <ThemedText type="small" themeColor={isFocused ? 'text' : 'textSecondary'}>
@@
 export function CustomTabList(props: TabListProps) {
   const scheme = useColorScheme()
   const colors = Colors[scheme === 'dark' ? 'dark' : 'light']

   return (
-    <View {...props} style={styles.tabListContainer}>
+    <View {...props} style={[styles.tabListContainer, props.style]}>
       <ThemedView type="backgroundElement" style={styles.innerContainer}>

Also applies to: 48-49

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/mobile/src/components/app-tabs.web.tsx` around lines 30 - 33, The
Pressable and ThemedView wrappers (the Pressable with {...props} and style={({
pressed }) => pressed && styles.pressed} and the ThemedView using
style={styles.tabButtonView}) are currently overwriting any caller-provided or
forwarded props.style; instead merge props.style with the existing styles: read
props.style (or props?.style) and compose it with
styles.pressed/styles.tabButtonView and the pressed callback so forwarded styles
are preserved; apply the same change to the second occurrence around the other
TabList/TabTrigger wrapper noted (the block at ~48-49) so both asChild wrappers
merge rather than replace styles.
.cursor/skills/expo-tailwind-setup-v55/SKILL.md (2)

233-244: Consider more descriptive naming for internal component.

The XXTouchableHighlight name uses an unconventional double-X prefix. Consider using a clearer naming pattern like _TouchableHighlight, BaseTouchableHighlight, or TouchableHighlightInternal to better communicate its purpose as an internal wrapper.

♻️ Suggested naming improvement
-function XXTouchableHighlight(
+// Internal wrapper to extract underlayColor from style object
+function BaseTouchableHighlight(
   props: React.ComponentProps<typeof RNTouchableHighlight>
 ) {
   const { underlayColor, ...style } = StyleSheet.flatten(props.style) || {};
   return (
     <RNTouchableHighlight
       underlayColor={underlayColor}
       {...props}
       style={style}
     />
   );
 }
 
 export const TouchableHighlight = (
   props: React.ComponentProps<typeof RNTouchableHighlight>
 ) => {
-  return useCssElement(XXTouchableHighlight, props, { className: "style" });
+  return useCssElement(BaseTouchableHighlight, props, { className: "style" });
 };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.cursor/skills/expo-tailwind-setup-v55/SKILL.md around lines 233 - 244, The
internal wrapper component currently named XXTouchableHighlight should be
renamed to a clearer internal name (e.g., _TouchableHighlight,
BaseTouchableHighlight, or TouchableHighlightInternal) to communicate intent;
update the component definition and all usages/references of
XXTouchableHighlight accordingly (ensure prop types React.ComponentProps<typeof
RNTouchableHighlight> and behavior that extracts underlayColor via
StyleSheet.flatten(props.style) remain unchanged).

1-484: Consider adding cross-references to related Expo skills.

The documentation is comprehensive and well-structured. To improve navigation within the skill library, consider adding cross-references to related skills mentioned in the PR (e.g., @expo-deployment-v55, @expo-cicd-workflows-v55) in relevant sections like deployment or CI/CD context.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.cursor/skills/expo-tailwind-setup-v55/SKILL.md around lines 1 - 484, Add
explicit cross-reference links to the related Expo skills (`@expo-deployment-v55`,
`@expo-cicd-workflows-v55`) in the SKILL.md by inserting brief "See also" or
"Related skills" pointers under relevant sections such as Usage,
Troubleshooting, and Key Differences from NativeWind v4 / Tailwind v3; update
the headings "Usage", "Troubleshooting", or "Key Differences from NativeWind v4
/ Tailwind v3" to include those links so readers can easily navigate to
deployment and CI/CD skills.
apps/mobile/package.json (1)

55-55: Pin the React Compiler plugin to an exact prerelease.

"beta" is a moving dist-tag, so fresh installs can pick up different compiler transforms than the lockfile/CI was validated against. That is extra risky here because apps/mobile/app.json also enables experiments.reactCompiler. Use a concrete version once you confirm the Expo SDK 55-compatible release.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/mobile/package.json` at line 55, The dependency
"babel-plugin-react-compiler": "beta" in apps/mobile package.json uses a
floating dist-tag; replace it with a concrete prerelease version (for example
"babel-plugin-react-compiler": "x.y.z-canary.0") that you verify is compatible
with Expo SDK 55, update package.json to that exact version, run install and
lockfile update, and ensure apps/mobile/app.json (experiments.reactCompiler)
remains aligned with the pinned compiler release.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.cursor/commands/onboard-new-developer.md:
- Line 5: Update the "Decide context: Local only, or remote VPC?" step to
include a short clarifying sentence and/or a link to the Dev Environments
documentation so new developers understand what "remote VPC" means, the
trade-offs (e.g., networking, access, cost, and latency), and how that choice
affects later steps; specifically edit the step text "Decide context: Local
only, or remote VPC?" to append a one-line definition of remote VPC vs local
plus a pointer to the Dev Environments docs (matching the style of the existing
link on line 7).
- Line 7: Replace the external Dev Environments link with the internal
documentation reference: change the URL after the "Run mobile (optional)"
command so the sentence reads "See
[`@apps/docu/content/docs/development/dev-environments`]" instead of the external
basilic-docs.vercel.app link; keep the existing package name and command (`pnpm
--filter `@repo/mobile` start`) unchanged.

In @.cursor/skills/expo-deployment-v55/references/ios-app-store.md:
- Around line 214-254: Add the required top-level "configVersion": 0 to each
apple.release JSON example and clarify these examples belong in
store.config.json (or the file referenced by submit.ios.metadataPath in
eas.json) rather than eas.json/app.json; update the Automatic Release, Scheduled
Release (automaticRelease with timestamp), and Phased Release examples to
include this configVersion and add a short note above the Scheduled and Phased
sections stating "In store.config.json" (or similar) and reference the
apple.release keys (automaticRelease, phasedRelease) so readers know where to
place them.
- Around line 336-358: Remove the invalid platform: ios parameter from the
submit job in the workflow example (the block where type: submit and params:
include build_id and profile); update params to only include supported keys
(build_id, profile, and optionally groups) and, if the intent is TestFlight
distribution (per the Tips), consider changing type: submit to type: testflight
and use TestFlight-specific params (internal_groups/external_groups) instead;
also remove the same invalid platform parameter occurrences in the workflows.md
Production Release section.
- Around line 47-53: Update the environment variable names to match current Expo
EAS docs: replace EXPO_ASC_API_KEY_ISSUER_ID with EXPO_ASC_ISSUER_ID and replace
EXPO_ASC_API_KEY_ID with EXPO_ASC_KEY_ID (keep EXPO_ASC_API_KEY_PATH as-is);
ensure the updated names appear where the example env vars are defined so CI/EAS
can read the ASC credentials correctly.

In @.cursor/skills/expo-deployment-v55/SKILL.md:
- Line 64: Replace the legacy invocation "npx testflight" with the modern EAS
submit command used by Expo: update occurrences of the string "npx testflight"
in SKILL.md to "eas submit --platform ios" or, when you intend to submit the
latest build, "eas submit -p ios --latest" so docs and instructions reflect the
current Apple/TestFlight workflow via EAS CLI.
- Line 87: Update the EAS CLI minimum version string in SKILL.md: replace the
current JSON/manifest "version" value ">= 18.0.5" with ">= 18.3.0" so it matches
the Expo SDK 55 requirement; locate the "version" field in the dependency block
(the entry shown as "version": ">= 18.0.5") and change it to ">= 18.3.0".

In @.cursor/skills/expo-dev-client-v55/SKILL.md:
- Around line 82-84: Update the "Local builds output:" list to match the install
steps: replace the iOS entry "iOS: `.ipa` file" with "iOS simulator: `.tar.gz`
archive" (to match the simulator build description) and change the Android entry
from "Android: `.apk` or `.aab` file" to "Android: `.apk` file" (AAB is
store-only). Locate and edit the list items that currently read "iOS: `.ipa`
file" and "Android: `.apk` or `.aab` file" so the outputs align with the later
simulator build and development build instructions.
- Around line 56-58: The documented EAS CLI command uses a nonexistent flag
`--submit`; update the command snippet (the bash line `eas build -p ios
--profile development --submit`) to use the correct `--auto-submit` flag (`eas
build -p ios --profile development --auto-submit`) and ensure any surrounding
text in SKILL.md that references `--submit` is replaced with `--auto-submit` so
the example matches the official EAS CLI options.

In @.cursor/skills/expo-tailwind-setup-v55/SKILL.md:
- Around line 82-84: The documentation currently shows granular Tailwind imports
(`@import` "tailwindcss/theme.css" layer(theme);, `@import`
"tailwindcss/preflight.css" layer(base);, `@import` "tailwindcss/utilities.css";)
— replace these with the recommended Tailwind v4 single import (`@import`
"tailwindcss";) for clarity and consistency, and add a brief note that the
granular layer imports may be used only when deliberately omitting or
customizing Preflight or other layers (e.g., when the skill specifically
requires granular control).
- Around line 23-26: Add a brief note above the installation command clarifying
that react-native-css@0.0.0-nightly.5ce6396 and nativewind@5.0.0-preview.2 are
pre-release/experimental versions and may be unstable or change; explicitly
state this setup is for experimental projects and suggest checking for newer
stable releases before using the provided npx expo install command (refer to the
installation line containing tailwindcss@^4 nativewind@5.0.0-preview.2
react-native-css@0.0.0-nightly.5ce6396).
- Around line 388-403: The CSS uses the unsupported light-dark() function for
several custom properties (e.g., --sf-blue, --sf-green, --sf-red, --sf-gray,
--sf-text, --sf-bg) which react-native-css/Color Module Level 5 doesn't support;
replace these light-dark(...) declarations by defining explicit light and dark
custom-property values and switching them via a theme class or the native
colorScheme API: create root-level sets like :root { --sf-blue: <light-value>;
... } and a .dark (or [data-theme="dark"]) override { --sf-blue: <dark-value>;
... }, or populate platform-aware tokens using react-native-css supported
colorScheme/platformColor and tie them to Appearance colorScheme; also keep the
`@media` ios/platformColor fallback for iOS but remove all light-dark(...) usages
so web/Android build no longer fails.

In @.cursor/skills/expo-upgrading-v55/references/react-19.md:
- Around line 42-65: Change the "Removing forwardRef" section to present it as
an optional modernization rather than a required migration: rename the heading
to something like "Optional: Modernizing away forwardRef", update the checklist
item (line ~79) to "Optional: Remove forwardRef wrapper" and add a short note
that existing forwardRef usage remains supported in React 19 (but is
deprecated), and show the suggested pattern using the Input function signature
and React.Ref<T> typing as an example rather than a mandatory step; keep
references to forwardRef, Input, TextInput, Props and React.Ref to guide
readers.
- Around line 7-38: Update the React 19 guidance to present these as optional
improvements rather than required SDK 55 migrations: change the "useContext →
use" paragraph to say that useContext remains supported and that use is an
alternative that can also read promises (mention both symbols: useContext and
use), reword the "Context.Provider → Context" example to note that
Context.Provider continues to work and the new shorthand (e.g., ThemeContext) is
a modernization option, and adjust the forwardRef guidance to state that
forwardRef is still supported while passing ref as a prop is an alternative
pattern; also update the checklist items that mention these changes (the items
referencing Context.Provider and forwardRef) to flag them as optional
best-practice modernization steps rather than required migration tasks.

In `@apps/docu/content/docs/architecture/monorepo.mdx`:
- Around line 39-61: The page's architecture diagrams are inconsistent: update
the earlier "apps/" summary block and the "Dependency Direction" diagram to
include the new Mobile node and its relations; specifically add
Mobile["mobile<br/>(Expo)"] to the apps/ overview (matching the new subgraph
that contains Mobile) and ensure arrows showing React --> Mobile, Core -->
Mobile, UI --> Mobile and Mobile -->|HTTP| API are present in the Dependency
Direction block so both diagrams consistently reference Mobile and the same node
names (Apps, API, Web, Mobile, Core, React, UI, Docu, Email, Utils, Error).

In `@apps/mobile/app.json`:
- Line 8: The "scheme" value in app.json is currently set to the generic
"mobile" and must be replaced with an app-specific deep-link scheme to avoid
collisions; update the "scheme" key to a reverse-DNS or unique identifier (e.g.,
"com.blockmatic.basilic" or "basilic-mobile") so OAuth callbacks and deep links
target this app instance reliably, and ensure any platform config or
URL/redirect settings (e.g., in OAuth providers) are updated to match the new
scheme.

In `@apps/mobile/scripts/reset-project.cjs`:
- Around line 14-16: The script's oldDirs array includes 'scripts', which causes
the removal/rename loop (the code iterating over oldDirs in reset-project.cjs)
to attempt to modify the directory the script is running from; remove 'scripts'
from the oldDirs array (or alternatively defer any deletion/rename of that
directory until after the process exits by scheduling it on process.on('exit')
or with setImmediate) so the script never tries to delete/rename
apps/mobile/scripts while reset-project.cjs is executing.

In `@apps/mobile/src/components/app-tabs.web.tsx`:
- Around line 50-65: The visible "Expo Starter" chrome and permanent Expo docs
CTA should not ship as-is; either wrap the block that renders ThemedText
type="smallBold" with "Expo Starter" plus the ExternalLink/Pressable/SymbolView
into a development-only guard (e.g., conditional on __DEV__) or replace that
markup with real app branding or navigation components; update the render around
props.children so the ThemedText, ExternalLink, Pressable, and SymbolView are
only shown in dev or swapped for production UI.

In `@apps/mobile/src/hooks/use-bottom-tab-inset.ts`:
- Around line 4-15: The custom hook useBottomTabInset and the hardcoded
baseTabBarHeight (50/80) duplicate Expo Router NativeTabs' automatic inset
handling; either remove useBottomTabInset and stop using its full/tabBarOnly
values in the screens referenced (where index.tsx uses it at line ~35 and
explore.tsx at ~20) so components rely on NativeTabs' automatic content insets,
or if you truly need manual insets set disableAutomaticContentInsets on the
NativeTabs and implement inset calculation following Expo Router docs (remove
baseTabBarHeight and any platform-guessing values and sync to the documented
API) — update usages of useBottomTabInset accordingly or delete the hook if
unused.

---

Nitpick comments:
In @.cursor/skills/expo-tailwind-setup-v55/SKILL.md:
- Around line 233-244: The internal wrapper component currently named
XXTouchableHighlight should be renamed to a clearer internal name (e.g.,
_TouchableHighlight, BaseTouchableHighlight, or TouchableHighlightInternal) to
communicate intent; update the component definition and all usages/references of
XXTouchableHighlight accordingly (ensure prop types React.ComponentProps<typeof
RNTouchableHighlight> and behavior that extracts underlayColor via
StyleSheet.flatten(props.style) remain unchanged).
- Around line 1-484: Add explicit cross-reference links to the related Expo
skills (`@expo-deployment-v55`, `@expo-cicd-workflows-v55`) in the SKILL.md by
inserting brief "See also" or "Related skills" pointers under relevant sections
such as Usage, Troubleshooting, and Key Differences from NativeWind v4 /
Tailwind v3; update the headings "Usage", "Troubleshooting", or "Key Differences
from NativeWind v4 / Tailwind v3" to include those links so readers can easily
navigate to deployment and CI/CD skills.

In `@apps/mobile/package.json`:
- Line 55: The dependency "babel-plugin-react-compiler": "beta" in apps/mobile
package.json uses a floating dist-tag; replace it with a concrete prerelease
version (for example "babel-plugin-react-compiler": "x.y.z-canary.0") that you
verify is compatible with Expo SDK 55, update package.json to that exact
version, run install and lockfile update, and ensure apps/mobile/app.json
(experiments.reactCompiler) remains aligned with the pinned compiler release.

In `@apps/mobile/src/components/app-tabs.web.tsx`:
- Around line 30-33: The Pressable and ThemedView wrappers (the Pressable with
{...props} and style={({ pressed }) => pressed && styles.pressed} and the
ThemedView using style={styles.tabButtonView}) are currently overwriting any
caller-provided or forwarded props.style; instead merge props.style with the
existing styles: read props.style (or props?.style) and compose it with
styles.pressed/styles.tabButtonView and the pressed callback so forwarded styles
are preserved; apply the same change to the second occurrence around the other
TabList/TabTrigger wrapper noted (the block at ~48-49) so both asChild wrappers
merge rather than replace styles.

In `@biome.json`:
- Around line 116-125: The glob for the override currently uses "apps/mobile/**"
which is inconsistent with the other entry that uses "**/apps/mobile/**"; update
the includes entry to "**/apps/mobile/**" so the rule override for
"useNodejsImportProtocol" under the linter applies consistently to the mobile
app path (reference the "includes" array and the "useNodejsImportProtocol"
rule).

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 389dc21e-d704-4b48-9fc6-1a9d274e1942

📥 Commits

Reviewing files that changed from the base of the PR and between 4e68670 and 7e767c0.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml, !**/pnpm-lock.yaml
📒 Files selected for processing (34)
  • .cursor/commands/onboard-new-developer.md
  • .cursor/skills/expo-cicd-workflows-v55/scripts/fetch.js
  • .cursor/skills/expo-cicd-workflows-v55/scripts/validate.js
  • .cursor/skills/expo-deployment-v55/SKILL.md
  • .cursor/skills/expo-deployment-v55/references/app-store-metadata.md
  • .cursor/skills/expo-deployment-v55/references/ios-app-store.md
  • .cursor/skills/expo-deployment-v55/references/testflight.md
  • .cursor/skills/expo-deployment-v55/references/workflows.md
  • .cursor/skills/expo-dev-client-v55/SKILL.md
  • .cursor/skills/expo-tailwind-setup-v55/SKILL.md
  • .cursor/skills/expo-upgrading-v55/SKILL.md
  • .cursor/skills/expo-upgrading-v55/references/expo-av-to-audio.md
  • .cursor/skills/expo-upgrading-v55/references/native-tabs.md
  • .cursor/skills/expo-upgrading-v55/references/react-19.md
  • .cursor/skills/expo-upgrading-v55/references/react-compiler.md
  • apps/docu/content/docs/architecture/monorepo.mdx
  • apps/docu/content/docs/development/dev-environments.mdx
  • apps/mobile/app.json
  • apps/mobile/package.json
  • apps/mobile/scripts/reset-project.cjs
  • apps/mobile/src/app/explore.tsx
  • apps/mobile/src/app/index.tsx
  • apps/mobile/src/components/animated-icon.web.tsx
  • apps/mobile/src/components/app-tabs.web.tsx
  • apps/mobile/src/components/external-link.tsx
  • apps/mobile/src/components/themed-view.tsx
  • apps/mobile/src/components/ui/collapsible.tsx
  • apps/mobile/src/components/web-badge.tsx
  • apps/mobile/src/constants/theme.ts
  • apps/mobile/src/hooks/use-bottom-tab-inset.ts
  • apps/mobile/src/hooks/use-theme.ts
  • biome.json
  • tools/eslint/expo.js
  • tools/typescript/package.json
🚧 Files skipped from review as they are similar to previous changes (16)
  • apps/mobile/src/constants/theme.ts
  • apps/mobile/src/components/web-badge.tsx
  • tools/eslint/expo.js
  • .cursor/skills/expo-deployment-v55/references/app-store-metadata.md
  • .cursor/skills/expo-upgrading-v55/references/react-compiler.md
  • .cursor/skills/expo-deployment-v55/references/workflows.md
  • .cursor/skills/expo-cicd-workflows-v55/scripts/validate.js
  • .cursor/skills/expo-upgrading-v55/references/expo-av-to-audio.md
  • apps/mobile/src/components/ui/collapsible.tsx
  • .cursor/skills/expo-deployment-v55/references/testflight.md
  • apps/mobile/src/components/external-link.tsx
  • apps/mobile/src/components/themed-view.tsx
  • apps/docu/content/docs/development/dev-environments.mdx
  • .cursor/skills/expo-upgrading-v55/references/native-tabs.md
  • apps/mobile/src/hooks/use-theme.ts
  • .cursor/skills/expo-upgrading-v55/SKILL.md

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

♻️ Duplicate comments (3)
.cursor/commands/onboard-new-developer.md (2)

5-5: 🛠️ Refactor suggestion | 🟠 Major

Use @ syntax for internal documentation cross-reference.

The documentation link uses a relative path instead of the required @ syntax for cross-referencing internal documentation. As per coding guidelines, .cursor files must use @ syntax for cross-references.

📋 Suggested improvement
-3. **Decide context**: Local only, or remote VPC? (Remote VPC = dev machine in cloud; trade-offs: networking, access, cost, latency. See [Dev Environments](/docs/development/dev-environments).)
+3. **Decide context**: Local only, or remote VPC? (Remote VPC = dev machine in cloud; trade-offs: networking, access, cost, latency. See [`@apps/docu/content/docs/development/dev-environments`].)

As per coding guidelines: "Verify cross-references use @ syntax correctly" for files matching .cursor/**.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.cursor/commands/onboard-new-developer.md at line 5, Replace the relative
markdown link "[Dev Environments](/docs/development/dev-environments)" with the
internal cross-reference using the @ syntax required for .cursor files (e.g.,
change the link target to use the appropriate @ reference token for the "Dev
Environments" doc), ensuring the line that starts "3. **Decide context**" now
references the internal doc via @ instead of the /docs/... path; update only the
link target so formatting and surrounding text remain unchanged.

7-7: ⚠️ Potential issue | 🟠 Major

Use @ syntax for internal documentation cross-reference.

The link to Dev Environments should use the @ syntax as required by .cursor/** guidelines. The documentation file exists at apps/docu/content/docs/development/dev-environments.mdx. Update the cross-reference accordingly.

📋 Suggested improvement
-5. **Run mobile (optional)**: `pnpm --filter `@repo/mobile` start` (or `start:localhost` / `start:tunnel` for remote). See [Dev Environments](/docs/development/dev-environments)
+5. **Run mobile (optional)**: `pnpm --filter `@repo/mobile` start` (or `start:localhost` / `start:tunnel` for remote). See [Dev Environments](`@apps/docu/content/docs/development/dev-environments.mdx`)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.cursor/commands/onboard-new-developer.md at line 7, Update the "Run mobile
(optional)" line to use the internal docs cross-reference syntax: replace the
existing Markdown link target "Dev Environments" URL with the `@-style` reference
that points to the docs page (e.g., `@docs/development/dev-environments`) so the
link uses the .cursor recommended internal reference and resolves to
apps/docu/content/docs/development/dev-environments.mdx; keep the link text
("Dev Environments") the same.
.cursor/skills/expo-tailwind-setup-v55/SKILL.md (1)

470-473: ⚠️ Potential issue | 🟡 Minor

Keep the Tailwind import guidance consistent.

Line 472 still says to use @import "tailwindcss/...", but the skill now recommends the single @import "tailwindcss"; form above. Update this bullet so it matches the current guidance and only mention granular imports as an exception. As per coding guidelines, "Check documentation is up to date".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.cursor/skills/expo-tailwind-setup-v55/SKILL.md around lines 470 - 473,
Update the "3. **CSS imports**" bullet so it matches the earlier guidance by
recommending the single form '@import "tailwindcss";' instead of '@import
"tailwindcss/..."', and note that granular imports (e.g. '@import
"tailwindcss/components";') should only be used as an explicit exception; change
the bullet text to use the single import as the default and mention granular
imports only as an exception, replacing the old string '@import
"tailwindcss/..."' accordingly.
🧹 Nitpick comments (2)
biome.json (2)

116-125: Scope the useNodejsImportProtocol override more narrowly.

"**/apps/mobile/**" also matches Node-side files like apps/mobile/scripts/reset-project.cjs (apps/mobile/package.json, Line 10), so this relaxes a Node-only rule in places where it still has value. Limiting the override to mobile runtime source would keep the exception targeted.

♻️ Suggested narrowing
-      "includes": ["**/apps/mobile/**"],
+      "includes": ["**/apps/mobile/src/**"],
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@biome.json` around lines 116 - 125, The override currently applies to the
broad includes pattern "**/apps/mobile/**" which also matches Node-side files
(scripts, package.json) and inadvertently disables the Node-only rule; narrow
the glob in the biome.json override so it only targets mobile runtime source
(for example change the includes to target the mobile src/runtime directories
instead of the whole app) and keep the linter override for
"style.useNodejsImportProtocol" inside that scoped block so Node-side files like
scripts/reset-project.cjs are no longer affected.

190-191: Avoid disabling naming checks for the entire mobile app.

"**/apps/mobile/**" turns off naming-convention lint for every symbol under mobile, not just Expo route files. That is broader than necessary and will hide ordinary hook/component naming drift.

♻️ Suggested narrowing
-        "**/packages/notif/**",
-        "**/apps/mobile/**"
+        "**/packages/notif/**",
+        "**/apps/mobile/src/app/**"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@biome.json` around lines 190 - 191, The glob "**/apps/mobile/**" in
biome.json is too broad and disables naming-convention checks for the whole
mobile app; narrow it to only Expo/Next-style route files by replacing that
entry with globs that target the app route/page files (e.g. match
"app/**/route.*" and "app/**/page.*" under the mobile package) so only routing
files are excluded while preserving linting for components/hooks.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.cursor/skills/expo-deployment-v55/references/ios-app-store.md:
- Around line 31-45: The examples for submit.production.ios in eas.json are
missing the required ascAppId field; update both the API-key example (containing
ascApiKeyPath, ascApiKeyIssuerId, ascApiKeyId) and the Apple ID example
(containing appleId) to include ascAppId with the numeric App Store Connect app
ID (e.g., "ascAppId": "1234567890") so non-interactive runs of eas submit
succeed and CI pipelines won't prompt.

In @.cursor/skills/expo-deployment-v55/references/workflows.md:
- Around line 136-147: The custom job "check-changes" is using unsupported
"type: run" / "params.command" syntax and therefore doesn't expose outputs for
the downstream "build" job; change "check-changes" to use a steps: array with a
run step that writes a value into an output (e.g., echo the result to a file or
use the step output mechanism), declare outputs: { has_changes:
<stepId>.outputs.<name> } on the "check-changes" job, and update the "build" job
to reference needs.check-changes.outputs.has_changes for the conditional; locate
the job definitions named check-changes and build in the diff and convert the
check-changes job to steps + outputs per EAS custom job syntax.
- Around line 117-121: Update the EAS Workflows examples: change any build job's
params.platform value from "all" to the supported values ("ios" and/or
"android") and split into separate build jobs if both platforms are needed
(refer to the build job block and params.platform). Replace invalid custom-job
usage of "type: run" and "params.command" with a custom job that uses "steps:"
and individual "run:" steps (see the check-changes job where type: run and
params.command are used). For the check-changes job, capture the step output via
the run step (e.g., using set-output) and then expose it under the job's
"outputs:" section so downstream jobs (the build jobs) can reference it (ensure
the build job uses needs.<job>.outputs.<name> to consume it). Ensure all example
snippets follow the documented EAS Workflows syntax for job types, steps, and
outputs.

In @.cursor/skills/expo-dev-client-v55/SKILL.md:
- Around line 23-44: The eas.json example uses the same "development" profile
for both dev-client local builds and TestFlight submission; split them by adding
a distinct production (or "testflight") profile with distribution: "store" for
App Store–signed builds and keep "development" with developmentClient: true for
local Metro/dev-client testing, then update the CLI invocation that currently
references the development profile (the command at lines 54-58) to use the new
production/testflight profile for --auto-submit; modify the profiles named
"development" and "production"/"testflight" in eas.json accordingly and ensure
the submission command references the production/testflight profile.

In @.cursor/skills/expo-tailwind-setup-v55/SKILL.md:
- Line 313: Replace the markdown link forms in the "See also" entries so the
skill cross-references use bare @ tokens; specifically change
"[`@expo-deployment-v55`](/skills/expo-deployment-v55)" and
"[`@expo-cicd-workflows-v55`](/skills/expo-cicd-workflows-v55)" to plain
`@expo-deployment-v55` and `@expo-cicd-workflows-v55` (also apply the same
replacement for the occurrences noted at lines 468 and 479) so Cursor can
resolve them as skill references.
- Around line 30-38: Replace the Yarn-only "resolutions" field with pnpm's
"overrides" for the lightningcss pin (change the package.json snippet to use
"overrides": { "lightningcss": "1.30.1" }); update all cross-references that
currently use markdown link syntax to direct reference using the
`@expo-deployment-v55` form (e.g., replace "[...](...)" style links with
`@expo-deployment-v55`); and edit the "Key Differences" section to remove the old
`@import` "tailwindcss/..." wording and instead match the single-import
recommendation described elsewhere in the document (ensure the wording
explicitly references the single-import approach).

In `@apps/mobile/src/components/app-tabs.web.tsx`:
- Line 16: The TabTrigger in the web tabs component uses name="home" which
mismatches the native tabs' name ("index"); update the TabTrigger prop (the
element named TabTrigger) to use name="index" so the route name aligns with the
native implementation (ensure any other TabTrigger instances use the same
"index" name to keep routing/state consistent with the index.tsx route).

---

Duplicate comments:
In @.cursor/commands/onboard-new-developer.md:
- Line 5: Replace the relative markdown link "[Dev
Environments](/docs/development/dev-environments)" with the internal
cross-reference using the @ syntax required for .cursor files (e.g., change the
link target to use the appropriate @ reference token for the "Dev Environments"
doc), ensuring the line that starts "3. **Decide context**" now references the
internal doc via @ instead of the /docs/... path; update only the link target so
formatting and surrounding text remain unchanged.
- Line 7: Update the "Run mobile (optional)" line to use the internal docs
cross-reference syntax: replace the existing Markdown link target "Dev
Environments" URL with the `@-style` reference that points to the docs page (e.g.,
`@docs/development/dev-environments`) so the link uses the .cursor recommended
internal reference and resolves to
apps/docu/content/docs/development/dev-environments.mdx; keep the link text
("Dev Environments") the same.

In @.cursor/skills/expo-tailwind-setup-v55/SKILL.md:
- Around line 470-473: Update the "3. **CSS imports**" bullet so it matches the
earlier guidance by recommending the single form '@import "tailwindcss";'
instead of '@import "tailwindcss/..."', and note that granular imports (e.g.
'@import "tailwindcss/components";') should only be used as an explicit
exception; change the bullet text to use the single import as the default and
mention granular imports only as an exception, replacing the old string '@import
"tailwindcss/..."' accordingly.

---

Nitpick comments:
In `@biome.json`:
- Around line 116-125: The override currently applies to the broad includes
pattern "**/apps/mobile/**" which also matches Node-side files (scripts,
package.json) and inadvertently disables the Node-only rule; narrow the glob in
the biome.json override so it only targets mobile runtime source (for example
change the includes to target the mobile src/runtime directories instead of the
whole app) and keep the linter override for "style.useNodejsImportProtocol"
inside that scoped block so Node-side files like scripts/reset-project.cjs are
no longer affected.
- Around line 190-191: The glob "**/apps/mobile/**" in biome.json is too broad
and disables naming-convention checks for the whole mobile app; narrow it to
only Expo/Next-style route files by replacing that entry with globs that target
the app route/page files (e.g. match "app/**/route.*" and "app/**/page.*" under
the mobile package) so only routing files are excluded while preserving linting
for components/hooks.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 75eaa25d-0134-49e6-9e91-6771a3aa8893

📥 Commits

Reviewing files that changed from the base of the PR and between 7e767c0 and 0001d24.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml, !**/pnpm-lock.yaml
📒 Files selected for processing (14)
  • .cursor/commands/onboard-new-developer.md
  • .cursor/skills/expo-deployment-v55/SKILL.md
  • .cursor/skills/expo-deployment-v55/references/ios-app-store.md
  • .cursor/skills/expo-deployment-v55/references/workflows.md
  • .cursor/skills/expo-dev-client-v55/SKILL.md
  • .cursor/skills/expo-tailwind-setup-v55/SKILL.md
  • .cursor/skills/expo-upgrading-v55/references/react-19.md
  • apps/docu/content/docs/architecture/monorepo.mdx
  • apps/mobile/app.json
  • apps/mobile/package.json
  • apps/mobile/scripts/reset-project.cjs
  • apps/mobile/src/components/app-tabs.web.tsx
  • apps/mobile/src/hooks/use-bottom-tab-inset.ts
  • biome.json
🚧 Files skipped from review as they are similar to previous changes (2)
  • apps/mobile/scripts/reset-project.cjs
  • .cursor/skills/expo-deployment-v55/SKILL.md

- expo-deployment: add ascAppId to iOS submit examples, fix EAS workflows
- expo-dev-client: split development/testflight profiles for TestFlight
- expo-tailwind: use pnpm overrides, @ refs, single-import guidance
- onboard-new-developer: use @ refs for dev-environments
- mobile: align TabTrigger name to index, fix naming conventions
- biome: narrow mobile overrides to src/ and app route files
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (3)
apps/mobile/scripts/reset-project.cjs (2)

61-70: Add braces to nested conditionals for readability.

The nested if-else without braces is syntactically valid but harder to follow. Consider adding braces for clarity.

🧹 Suggested improvement
-      if (fs.existsSync(oldDirPath))
-        if (userInput === 'y') {
+      if (fs.existsSync(oldDirPath)) {
+        if (userInput === 'y') {
           const newDirPath = path.join(root, exampleDir, dir)
           await fs.promises.rename(oldDirPath, newDirPath)
           console.log(`➡️ /${dir} moved to /${exampleDir}/${dir}.`)
         } else {
           await fs.promises.rm(oldDirPath, { recursive: true, force: true })
           console.log(`❌ /${dir} deleted.`)
         }
-      else console.log(`➡️ /${dir} does not exist, skipping.`)
+      } else {
+        console.log(`➡️ /${dir} does not exist, skipping.`)
+      }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/mobile/scripts/reset-project.cjs` around lines 61 - 70, The nested
conditional around fs.existsSync(oldDirPath) and the inner if (userInput ===
'y') should use explicit braces for both the outer and inner branches to improve
readability and avoid ambiguity; update the block that uses
oldDirPath/newDirPath to wrap the outer if and its inner if-else in braces,
keeping the same calls to fs.promises.rename(newDirPath) and
fs.promises.rm(oldDirPath, { recursive: true, force: true }) and the console.log
messages, and ensure the else branch that logs "/${dir} does not exist,
skipping." remains attached to the outer if.

96-98: Consider setting a non-zero exit code on error.

The error is logged but the process will still exit with code 0, which could mislead CI pipelines or automation scripts into thinking the reset succeeded.

🛠️ Suggested improvement
   } catch (error) {
     console.error(`❌ Error during script execution: ${error.message}`)
+    process.exitCode = 1
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/mobile/scripts/reset-project.cjs` around lines 96 - 98, The catch block
in apps/mobile/scripts/reset-project.cjs currently only logs the error, leaving
the process exit code as 0; update the catch handler to set a non-zero exit
status when an error occurs (e.g., set process.exitCode = 1 or call
process.exit(1)) after logging so CI and automation detect failure—modify the
catch around the script execution (the error handling where error.message is
logged) to assign the non-zero exit code.
.cursor/skills/expo-deployment-v55/references/ios-app-store.md (1)

1-375: Excellent documentation with all past issues resolved.

All major issues from previous reviews have been successfully addressed:

  • ascAppId is now included in both credential configuration examples
  • Environment variable names use the correct format (EXPO_ASC_ISSUER_ID, EXPO_ASC_KEY_ID)
  • All store.config.json examples include the required configVersion: 0
  • The invalid platform parameter has been removed from the submit job

The documentation is comprehensive, accurate, and well-structured for Expo SDK 55 iOS App Store submission workflows. Cross-references follow the correct @ syntax pattern, and the content aligns with current EAS documentation.

Optional style refinement

Line 373: Consider hyphenating the compound adjective "up-to-date" when it modifies "credentials":

-Keep demo account credentials up to date
+Keep demo account credentials up-to-date

This is a minor style preference and not required.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.cursor/skills/expo-deployment-v55/references/ios-app-store.md around lines
1 - 375, Summary: Minor style refinement—hyphenate the compound adjective
modifying "credentials". Update the sentence "Keep demo account credentials up
to date" in ios-app-store.md (the line containing that phrase near the end of
the Tips section) to use the hyphenated form "Keep demo account credentials
up-to-date" so the compound adjective is correctly formatted; no other changes
required.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/mobile/src/components/animated-icon.web.tsx`:
- Around line 43-56: The glowKeyframe currently mixes a short entrance
(opacity/scale/easing at waypoint 30) with a very long rotation (240000ms), so
split it into two animations: keep glowKeyframe as a short entrance keyframe
that only animates opacity, scale and the initial rotateZ (using the existing 0
and 30 waypoints and Easing.elastic(0.7)) with a short duration (e.g., ~300ms),
and create a separate longRunningRotation keyframe that only animates continuous
rotation (rotateZ to 7200deg) with the 240000ms duration; update the component
to start both animations where needed so the fade-in finishes quickly while the
slow rotation runs independently.

---

Nitpick comments:
In @.cursor/skills/expo-deployment-v55/references/ios-app-store.md:
- Around line 1-375: Summary: Minor style refinement—hyphenate the compound
adjective modifying "credentials". Update the sentence "Keep demo account
credentials up to date" in ios-app-store.md (the line containing that phrase
near the end of the Tips section) to use the hyphenated form "Keep demo account
credentials up-to-date" so the compound adjective is correctly formatted; no
other changes required.

In `@apps/mobile/scripts/reset-project.cjs`:
- Around line 61-70: The nested conditional around fs.existsSync(oldDirPath) and
the inner if (userInput === 'y') should use explicit braces for both the outer
and inner branches to improve readability and avoid ambiguity; update the block
that uses oldDirPath/newDirPath to wrap the outer if and its inner if-else in
braces, keeping the same calls to fs.promises.rename(newDirPath) and
fs.promises.rm(oldDirPath, { recursive: true, force: true }) and the console.log
messages, and ensure the else branch that logs "/${dir} does not exist,
skipping." remains attached to the outer if.
- Around line 96-98: The catch block in apps/mobile/scripts/reset-project.cjs
currently only logs the error, leaving the process exit code as 0; update the
catch handler to set a non-zero exit status when an error occurs (e.g., set
process.exitCode = 1 or call process.exit(1)) after logging so CI and automation
detect failure—modify the catch around the script execution (the error handling
where error.message is logged) to assign the non-zero exit code.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 683d5e8d-b021-44a3-874a-7ce981762d26

📥 Commits

Reviewing files that changed from the base of the PR and between 0001d24 and 70074e8.

📒 Files selected for processing (10)
  • .cursor/commands/onboard-new-developer.md
  • .cursor/skills/expo-deployment-v55/references/ios-app-store.md
  • .cursor/skills/expo-deployment-v55/references/workflows.md
  • .cursor/skills/expo-dev-client-v55/SKILL.md
  • .cursor/skills/expo-tailwind-setup-v55/SKILL.md
  • apps/mobile/scripts/reset-project.cjs
  • apps/mobile/src/components/animated-icon.tsx
  • apps/mobile/src/components/animated-icon.web.tsx
  • apps/mobile/src/components/app-tabs.web.tsx
  • biome.json
✅ Files skipped from review due to trivial changes (1)
  • .cursor/skills/expo-deployment-v55/references/workflows.md
🚧 Files skipped from review as they are similar to previous changes (3)
  • biome.json
  • .cursor/commands/onboard-new-developer.md
  • apps/mobile/src/components/app-tabs.web.tsx

- animated-icon.web: separate entrance (300ms) from long rotation (240s)
- reset-project: add braces for conditionals, set exitCode on error
- ios-app-store: hyphenate "credentials up-to-date"
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@apps/mobile/scripts/reset-project.cjs`:
- Around line 108-110: The invalid-input branch currently logs an error and
closes the readline interface but exits with status 0; update the branch that
contains console.log("❌ Invalid input. Please enter 'Y' or 'N'.") so it sets
process.exitCode = 1 before closing the readline interface (rl.close()) to
signal failure to callers/CI; ensure you modify the block where rl and
console.log are used so the process exit code reflects the error.
- Around line 59-65: Before calling fs.promises.rename(oldDirPath, newDirPath)
ensure newDirPath does not already exist: inside the loop over oldDirs (where
oldDirPath, newDirPath, exampleDir and userInput are used) add an explicit check
like fs.existsSync(newDirPath) and if it exists, log/throw a clear error message
indicating the target collision (including the paths) and either abort the reset
or skip the move according to intended behavior so the script doesn't crash
mid-reset.

In `@apps/mobile/src/components/animated-icon.web.tsx`:
- Around line 9-11: AnimatedSplashOverlay currently returns null which skips the
startup mask on web; implement a minimal web version that mirrors the native
behavior by rendering an overlay element and dismissing itself after its exit
animation completes (or after a safe timeout) so the caller in _layout.tsx can
rely on the same lifecycle. In the AnimatedSplashOverlay component implement
local state (e.g., visible) and a dismiss handler triggered by an animationend
or setTimeout fallback, expose the same export name AnimatedSplashOverlay, and
ensure it cleans up timers/listeners; alternatively, if you prefer divergence at
the call site, update apps/mobile/src/app/_layout.tsx to branch on platform and
only mount AnimatedSplashOverlay on native, making that platform check explicit.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: d1b89022-58a5-4538-979f-48d059f96548

📥 Commits

Reviewing files that changed from the base of the PR and between 70074e8 and 58e769f.

📒 Files selected for processing (3)
  • .cursor/skills/expo-deployment-v55/references/ios-app-store.md
  • apps/mobile/scripts/reset-project.cjs
  • apps/mobile/src/components/animated-icon.web.tsx
🚧 Files skipped from review as they are similar to previous changes (1)
  • .cursor/skills/expo-deployment-v55/references/ios-app-store.md

- Add eas.json with preview, development, e2e-test profiles (no submit)
- Add mobile-build, mobile-preview, mobile-pr-preview workflows
- Add first Maestro E2E flow (.maestro/flows/home.yml)
- Add test:e2e script for Maestro
- Update docs (mobile-cicd.mdx, github-actions, e2e-testing)
- Update expo rule with EAS/CI pointer
- Update READMEs with mobile CI links
@gaboesquivel gaboesquivel merged commit f89bca4 into main Mar 12, 2026
10 checks passed
@gaboesquivel gaboesquivel deleted the other-apps branch March 12, 2026 21:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant