Skip to content

[PET-42] Replace @expo/vector-icons with lucide-react-native#43

Merged
zigcccc merged 5 commits intomainfrom
PET-42-replace-expo-vector-icons-with-lucide-react-native
Mar 20, 2026
Merged

[PET-42] Replace @expo/vector-icons with lucide-react-native#43
zigcccc merged 5 commits intomainfrom
PET-42-replace-expo-vector-icons-with-lucide-react-native

Conversation

@zigcccc
Copy link
Owner

@zigcccc zigcccc commented Mar 20, 2026

Summary by CodeRabbit

  • New Features

    • App icons updated to a unified icon set for more consistent UI and accessibility.
  • Documentation

    • Large collection of new end-user guides and skills for Expo Router, native UI patterns, animations, media, navigation, Convex workflows (components, migrations, auth, performance), CI/CD, and upgrade/migration paths.
  • Dependencies

    • Upgraded Expo and Convex versions and migrated icon library to lucide-react-native.

@zigcccc zigcccc self-assigned this Mar 20, 2026
@zigcccc zigcccc added enhancement New feature or request dependencies labels Mar 20, 2026
@coderabbitai
Copy link

coderabbitai bot commented Mar 20, 2026

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: ac550826-b80c-490b-bf79-e7f23da9dd21

📥 Commits

Reviewing files that changed from the base of the PR and between d3f73b6 and 4506956.

📒 Files selected for processing (3)
  • .agents/skills/building-native-ui/references/storage.md
  • src/app/(authenticated)/play/training-puzzle-solved.tsx
  • src/components/ui/Card/Card.tsx
✅ Files skipped from review due to trivial changes (1)
  • .agents/skills/building-native-ui/references/storage.md
🚧 Files skipped from review as they are similar to previous changes (2)
  • src/app/(authenticated)/play/training-puzzle-solved.tsx
  • src/components/ui/Card/Card.tsx

Walkthrough

Adds extensive agent-skill documentation for Expo and Convex, creates Claude skill pointer files, migrates the app icon system from @expo/vector-icons to lucide-react-native, updates Jest mocks/tests and tooling configs, and adjusts dependencies and CI/validation scripts accordingly.

Changes

Cohort / File(s) Summary
Agent Skills Documentation
.agents/skills/building-native-ui/*, .agents/skills/convex-create-component/*, .agents/skills/convex-migration-helper/*, .agents/skills/convex-performance-audit/*, .agents/skills/convex-quickstart/*, .agents/skills/convex-setup-auth/*, .agents/skills/expo-cicd-workflows/*, .agents/skills/expo-deployment/*, .agents/skills/expo-dev-client/*, .agents/skills/find-skills/*, .agents/skills/native-data-fetching/*, .agents/skills/upgrading-expo/*
Added many new skill and reference Markdown files and agent YAMLs describing Expo/React Native UI patterns, Convex workflows (components, migrations, auth, performance), CI/CD workflows, deployment, and upgrade guidance. Documentation-only changes.
Claude Skill Pointers
.claude/skills/*
Added pointer files linking Claude skill entries to the new .agents/skills/* implementations.
Icon Library Migration & UI changes
src/.../index.tsx, src/.../history/_layout.tsx, src/.../leaderboards/_layout.tsx, src/.../play/*.tsx, src/components/elements/Keyboard/*, src/components/ui/*
Replaced @expo/vector-icons (Octicons/Ionicons) usage with lucide-react-native components; updated Icon wrapper, Button/Card/Hint/RadioInput components and related props/types; adjusted testIDs and accessibility labels.
Keyboard component behavior
src/components/elements/Keyboard/Keyboard.tsx, .../Keyboard.constants.tsx
Added special-character detection (isSpecialCharacter) to style generation and swapped special-key icons to Lucide components.
Tests & Jest setup
jest.setup.tsx, jest.config.cjs, src/__tests__/index.test.tsx, src/components/ui/Button/Button.test.tsx
Replaced Octicons mock with a dynamic lucide-react-native mock (Proxy), updated Jest transform allowlist to include lucide-react-native, and updated test expectations to new icon names.
Icon component refactor
src/components/ui/Icon/Icon.tsx, src/components/ui/Button/Button.tsx, src/components/ui/Card/Card.tsx
Refactored Icon wrapper to accept/present Lucide components; updated Button testID/accessibility label derivation to use component displayName; changed Card actionsIcon prop to accept Lucide component type.
Tooling & scripts
.agents/skills/expo-cicd-workflows/scripts/fetch.js, .agents/skills/expo-cicd-workflows/scripts/validate.js, .agents/skills/expo-cicd-workflows/scripts/package.json
Added two CLI utilities for fetching/caching remote JSON docs and validating EAS workflow YAMLs with AJV; included a package.json for the scripts.
Dependencies & config
package.json, biome.json, skills-lock.json
Removed @expo/vector-icons, added lucide-react-native, bumped multiple Expo/Convex-related package versions; added skills-lock.json; updated Biome config to exclude .claude and .agents.
Project docs update
CLAUDE.md
Added Convex-specific guidance, an agent-skill install command, and icon naming conventions for lucide-react-native.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

refactor

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch PET-42-replace-expo-vector-icons-with-lucide-react-native
📝 Coding Plan
  • Generate coding plan for human review comments

@github-actions
Copy link

github-actions bot commented Mar 20, 2026

🚀 Expo preview is ready!

  • Project → petka-app
  • Platforms → android, ios
  • Scheme → petkaapp
  • Runtime Version → 1.6
  • More info

Learn more about 𝝠 Expo Github Action

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: 5

Note

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

🟡 Minor comments (18)
.agents/skills/upgrading-expo/references/react-19.md-22-22 (1)

22-22: ⚠️ Potential issue | 🟡 Minor

Minor wording fix needed for sentence clarity.
Line 22 reads awkwardly; consider: “use can be called conditionally, which simplifies components that consume multiple contexts.”

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

In @.agents/skills/upgrading-expo/references/react-19.md at line 22, Update the
awkward sentence about `use`: replace "use can be called conditionally, this
simplifies components that consume multiple contexts." with "use can be called
conditionally, which simplifies components that consume multiple contexts.";
edit the line referencing the `use` hook in react-19.md to use the suggested
wording for clarity.
.agents/skills/upgrading-expo/references/new-architecture.md-72-72 (1)

72-72: ⚠️ Potential issue | 🟡 Minor

Possible typo: xcobra should likely be expo.

The command bunx xcobra expo eval appears incorrect. Should this be bunx expo eval or npx expo eval?

Proposed fix
-Verify from the command line if the currently running app uses the New Architecture: `bunx xcobra expo eval "_IS_FABRIC"` -> `true`
+Verify from the command line if the currently running app uses the New Architecture: `npx expo eval "_IS_FABRIC"` -> `true`
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/upgrading-expo/references/new-architecture.md at line 72,
Replace the incorrect command fragment "bunx xcobra expo eval \"_IS_FABRIC\"" by
using the proper tool invocation: change "xcobra" to "expo" so it reads "bunx
expo eval \"_IS_FABRIC\"" (or if bunx is not used in your environment, use the
common alternative "npx expo eval \"_IS_FABRIC\""); update the command text in
the document accordingly.
.agents/skills/upgrading-expo/SKILL.md-84-94 (1)

84-94: ⚠️ Potential issue | 🟡 Minor

Documentation inconsistency with PR objective.

Line 90 documents the migration path as @expo/vector-iconsexpo-symbols (for SF Symbols), but the PR title indicates migration to lucide-react-native. These are different icon libraries with different approaches:

  • expo-symbols: iOS-only SF Symbols (native)
  • lucide-react-native: Cross-platform icon library

Ensure this documentation aligns with the actual icon strategy chosen for the project.

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

In @.agents/skills/upgrading-expo/SKILL.md around lines 84 - 94, The docs entry
for deprecated icons is inconsistent: update the migration table row that
currently maps `@expo/vector-icons` → `expo-symbols` to reflect the chosen
project icon library (`lucide-react-native`) or clearly document both options
and when to use them; edit the row in SKILL.md replacing `expo-symbols` with
`lucide-react-native` (or add an additional replacement column/note), and
include a brief note about platform differences (SF Symbols iOS-only vs
lucide-react-native cross-platform) so readers know which replacement applies.
.agents/skills/native-data-fetching/SKILL.md-16-19 (1)

16-19: ⚠️ Potential issue | 🟡 Minor

Add language specifier to code block.

The code block starting at line 16 is missing a language specifier, which triggers a markdownlint warning.

📝 Proposed fix
-```
+```text
 references/
   expo-router-loaders.md   Route-level data loading with Expo Router loaders (web, SDK 55+)
</details>

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

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

In @.agents/skills/native-data-fetching/SKILL.md around lines 16 - 19, The
fenced code block containing the directory listing (the lines with "references/"
and "expo-router-loaders.md Route-level data loading with Expo Router loaders
(web, SDK 55+)") is missing a language specifier; update the opening fence from
to include a language such astext (or ```txt) so the block becomes

content.
.agents/skills/native-data-fetching/SKILL.md-419-453 (1)

419-453: ⚠️ Potential issue | 🟡 Minor

Add language specifier to decision tree code block.

The decision tree code block starting at line 419 is missing a language specifier, which triggers a markdownlint warning.

📝 Proposed fix
-```
+```text
 User asks about networking
   |-- Route-level data loading (web, SDK 55+)?
   |   \-- Expo Router loaders — see references/expo-router-loaders.md
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/native-data-fetching/SKILL.md around lines 419 - 453, The
fenced decision-tree code block that begins with the line "User asks about
networking" is missing a language specifier and causes a markdownlint warning;
fix it by changing the opening fence from ``` to ```text (and keep the matching
closing fence) so the block is explicitly marked as plain text — locate the
fenced block that contains the routing/fetching/authentication tree and update
its opening fence accordingly.
.agents/skills/building-native-ui/references/webgpu-three.md-508-519 (1)

508-519: ⚠️ Potential issue | 🟡 Minor

Add language specifier to file structure code block.

The file structure code block is missing a language specifier, which triggers a markdownlint warning.

📝 Proposed fix
-```
+```text
 src/
 ├── app/
 │   └── index.tsx           # Entry point with lazy loading
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/building-native-ui/references/webgpu-three.md around lines
508 - 519, The Markdown code fence containing the file tree starting with "src/"
is missing a language specifier; update the opening triple-backtick fence to
include a language (e.g., ```text) so markdownlint stops flagging it—modify the
code block in webgpu-three.md that begins with ``` and the subsequent tree lines
(src/, app/, components/, lib/, etc.) to use ```text.
.agents/skills/native-data-fetching/references/expo-router-loaders.md-179-187 (1)

179-187: ⚠️ Potential issue | 🟡 Minor

Non-null assertion may be unsafe in static mode.

Line 181 uses a non-null assertion (request!.url), but the documentation states that request is undefined in static output mode. This could cause runtime errors.

🛡️ Proposed fix for safer request access
 export const loader: LoaderFunction<{ results: any[]; query: string }> = async (request) => {
   // Assuming request.url is `/search?q=expo&page=2`
-  const url = new URL(request!.url);
+  if (!request) {
+    throw new Error("Request object not available in static mode");
+  }
+  const url = new URL(request.url);
   const query = url.searchParams.get("q") ?? "";

Alternatively, document that this example only applies to server mode.

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

In @.agents/skills/native-data-fetching/references/expo-router-loaders.md around
lines 179 - 187, The loader uses a non-null assertion on request (request!.url)
which can be undefined in static output mode; update the loader (export const
loader) to guard request before accessing url (use request?.url or an explicit
if (!request) branch) and handle the static case by returning safe defaults
(e.g., { results: [], query: "" }) or by deriving query/page from a fallback
URL, then call fetchSearchResults only when you have a valid query/page;
reference the loader function and replace request!.url with a guarded access or
early-return to avoid runtime errors.
.agents/skills/building-native-ui/references/webgpu-three.md-523-539 (1)

523-539: ⚠️ Potential issue | 🟡 Minor

Add language specifier to decision tree code block.

The decision tree code block is missing a language specifier, which triggers a markdownlint warning.

📝 Proposed fix
-```
+```text
 Need 3D graphics?
 ├── Simple shapes → mesh + geometry + material
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/building-native-ui/references/webgpu-three.md around lines
523 - 539, The fenced decision-tree code block starting with "Need 3D graphics?"
is missing a language specifier which triggers markdownlint; update that block
by adding a language tag (e.g., ```text) after the opening triple backticks so
the block becomes fenced with a specifier and the rest of the tree (lines
containing "Need 3D graphics?", "Simple shapes → mesh + geometry + material",
"Animated objects → useFrame + refs", etc.) remains unchanged.
.agents/skills/building-native-ui/references/webgpu-three.md-250-257 (1)

250-257: ⚠️ Potential issue | 🟡 Minor

Missing React import in example.

The Scene component uses useEffect (line 253) but doesn't import it from React. This will cause a runtime error.

📦 Proposed fix
 function Scene() {
   const { camera } = useThree();
+  const { useEffect } = require("react");
 
   useEffect(() => {

Or better, add to the imports at the top of the example:

 import * as THREE from "three/webgpu";
 import { View } from "react-native";
-import { useRef } from "react";
+import { useRef, useEffect } from "react";
 import { useFrame, useThree } from "@react-three/fiber";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/building-native-ui/references/webgpu-three.md around lines
250 - 257, The example's Scene component uses useEffect (and React hooks) but
doesn't import them; add the missing React hook import by importing useEffect
(or importing React) at the top of the example so Scene, which calls useEffect
and useThree() and manipulates camera.position/camera.lookAt, will run without
runtime errors.
.agents/skills/building-native-ui/references/webgpu-three.md-565-575 (1)

565-575: ⚠️ Potential issue | 🟡 Minor

Missing useEffect import in game example.

The GameScene component uses useEffect (line 571) but the import statement at the top of the example (line 546) only imports useRef, useState, and useCallback.

📦 Proposed fix
-import { useRef, useState, useCallback } from "react";
+import { useRef, useState, useCallback, useEffect } from "react";
 import { useFrame, useThree } from "@react-three/fiber";
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/building-native-ui/references/webgpu-three.md around lines
565 - 575, The example's GameScene component uses useEffect but the top import
only includes useRef, useState, useCallback; update the React import to also
include useEffect so GameScene can call useEffect without runtime errors (locate
the import near the top of the example and add useEffect to the import list that
supplies useRef/useState/useCallback).
.agents/skills/convex-performance-audit/SKILL.md-67-67 (1)

67-67: ⚠️ Potential issue | 🟡 Minor

Fix likely broken internal skill path reference.

Line 67 points to skills/convex-migration-helper/SKILL.md, but this repo’s skill docs appear to live under .agents/skills/.... Please align this path to avoid stale navigation.

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

In @.agents/skills/convex-performance-audit/SKILL.md at line 67, The link text
in .agents/skills/convex-performance-audit/SKILL.md currently points to
skills/convex-migration-helper/SKILL.md which is a stale path; update the
reference to the repository's actual skill docs location (e.g.,
.agents/skills/convex-migration-helper/SKILL.md) so the string literal in the
file matches the correct directory, and verify any other occurrences of
"convex-migration-helper" in .agents/skills/* to ensure consistent, working
internal links.
.agents/skills/expo-cicd-workflows/scripts/validate.js-59-64 (1)

59-64: ⚠️ Potential issue | 🟡 Minor

--help should exit 0 even when no files are provided.

With current logic, validate --help returns exit code 1 because files.length === 0 is true.

✅ Proposed CLI behavior fix
-  if (files.length === 0 || args.includes('--help') || args.includes('-h')) {
+  if (args.includes('--help') || args.includes('-h')) {
     console.log(`Usage: validate <workflow.yml> [workflow2.yml ...]
 
 Validates EAS workflow YAML files against the official schema.`);
-    process.exit(files.length === 0 ? 1 : 0);
+    process.exit(0);
+  }
+
+  if (files.length === 0) {
+    console.error('No workflow files provided. Use --help for usage.');
+    process.exit(1);
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/expo-cicd-workflows/scripts/validate.js around lines 59 - 64,
The current combined condition uses (files.length === 0 ||
args.includes('--help') || args.includes('-h')) which causes validate --help to
exit with code 1 when no files exist; split the logic so that if
args.includes('--help') || args.includes('-h') you print the Usage message and
call process.exit(0), otherwise if files.length === 0 you print the Usage
message and call process.exit(1); update the conditional around the Usage/exit
block (referencing the variables args, files and the process.exit call) to
implement this branching.
.agents/skills/building-native-ui/references/zoom-transitions.md-152-152 (1)

152-152: ⚠️ Potential issue | 🟡 Minor

Use “off-screen” hyphenation for readability.

“scrolled off screen” should be “scrolled off-screen” in this sentence.

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

In @.agents/skills/building-native-ui/references/zoom-transitions.md at line
152, Update the sentence that currently reads "When source is unavailable (e.g.,
scrolled off screen), the transition zooms from the center of the screen" by
replacing "scrolled off screen" with the hyphenated form "scrolled off-screen"
for improved readability; locate this exact sentence in zoom-transitions.md and
make the single-word change.
.agents/skills/expo-deployment/SKILL.md-123-136 (1)

123-136: ⚠️ Potential issue | 🟡 Minor

Fix path references - should be ./references/ (plural).

The path references use ./reference/ (singular) but should be ./references/ (plural) to match the actual directory structure shown in the file list and the header references at lines 16-20.

🔗 Proposed fix for path references
-See ./reference/testflight.md for credential setup
-See ./reference/ios-app-store.md for App Store submission
+See ./references/testflight.md for credential setup
+See ./references/ios-app-store.md for App Store submission

 ### Android

 - Set up Google Play Console service account
 - Configure tracks: internal → closed → open → production
-- See ./reference/play-store.md for detailed setup
+- See ./references/play-store.md for detailed setup

 ### Web

 - EAS Hosting provides preview URLs for PRs
 - Production deploys to your custom domain
-- See ./reference/workflows.md for CI/CD automation
+- See ./references/workflows.md for CI/CD automation
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/expo-deployment/SKILL.md around lines 123 - 136, Update the
broken relative links in SKILL.md that use the singular path './reference/' to
the correct plural './references/' so the links to testflight.md,
ios-app-store.md, play-store.md and workflows.md resolve; search for occurrences
of the string './reference/' in the file and replace them with './references/'
(e.g., './reference/testflight.md' → './references/testflight.md').
.agents/skills/convex-setup-auth/references/convex-auth.md-20-21 (1)

20-21: ⚠️ Potential issue | 🟡 Minor

Update @auth/core version specifier in documentation.

The documentation specifies @auth/core@0.37.0 (exact pin), but @convex-dev/auth v0.0.91 requires @auth/core ^0.37.0 (caret range). Update the install command to match the actual peer dependency: npm install @convex-dev/auth @auth/core@^0.37.0 to allow compatible patch releases.

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

In @.agents/skills/convex-setup-auth/references/convex-auth.md around lines 20 -
21, The install instruction pins `@auth/core` exactly to 0.37.0 but
`@convex-dev/auth` v0.0.91 requires a caret range; update the command that
currently shows `npm install `@convex-dev/auth` `@auth/core`@0.37.0` to use the
caret range `@auth/core@^0.37.0` so the peer dependency requirement is satisfied
and compatible patch releases are allowed.
.agents/skills/expo-deployment/references/play-store.md-29-42 (1)

29-42: ⚠️ Potential issue | 🟡 Minor

Clarify that serviceAccountKeyPath is optional; document the recommended credentials approach.

The documentation shows serviceAccountKeyPath as a configuration example, but this is optional, not required. Per current Expo documentation (2025), EAS handles Android app submission credentials through its internal Credentials system: upload the Google Service Account Key to the EAS dashboard under Android > [package] > Service Credentials, then eas submit uses it automatically without needing a local path. The serviceAccountKeyPath configuration in eas.json is only needed for local workflows where the key is stored as a file; it's not recommended for CI/CD due to security concerns.

Update the documentation to clarify that the example shown is one optional approach, and recommend uploading the key to the EAS dashboard as the preferred method. If showing eas.json configuration, add a note that this is for local use only and that the dashboard approach is more secure.

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

In @.agents/skills/expo-deployment/references/play-store.md around lines 29 -
42, Clarify that serviceAccountKeyPath in the example is optional and describe
the recommended credential flow: explain that EAS manages Android submission
credentials via its internal Credentials system and that the preferred, more
secure approach is to upload the Google Service Account Key in the EAS dashboard
(Android > [package] > Service Credentials) so eas submit uses it automatically;
if keeping the eas.json example with serviceAccountKeyPath, add a clear note
that this is for local workflows only (not recommended for CI/CD) and advise
adding the key file to .gitignore when used.
.agents/skills/building-native-ui/references/media.md-70-71 (1)

70-71: ⚠️ Potential issue | 🟡 Minor

GlassButton component is used but never defined.

The example references <GlassButton /> but doesn't define or import it. Readers following this documentation won't be able to implement the camera UI without the component definition.

,

📝 Suggested GlassButton definition
function GlassButton({ onPress, icon }: { onPress: () => void; icon: string }) {
  return (
    <GlassView isInteractive style={{ padding: 12, borderRadius: 99 }}>
      <TouchableOpacity onPress={onPress}>
        <Image source={`sf:${icon}`} style={{ width: 24, height: 24, tintColor: 'white' }} />
      </TouchableOpacity>
    </GlassView>
  );
}

Do you want me to generate a complete camera example with all components defined?

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

In @.agents/skills/building-native-ui/references/media.md around lines 70 - 71,
The example uses <GlassButton> but it is not defined or imported; add a
GlassButton component definition (used by the camera example) that accepts
onPress and icon props and composes GlassView, TouchableOpacity, and Image so
selectPhoto and the setType toggle work; ensure the component name is
GlassButton, props are { onPress: () => void; icon: string }, it renders a
tappable GlassView wrapper and displays the SF icon via Image (tintable), and
export or include it in the same file so the sample JSX lines with <GlassButton
onPress={selectPhoto} ... /> and <GlassButton onPress={() => setType(t => t ===
"back" ? "front" : "back")} ... /> compile.
.agents/skills/building-native-ui/references/media.md-19-19 (1)

19-19: ⚠️ Potential issue | 🟡 Minor

SymbolView import contradicts SKILL.md library preferences.

This example imports SymbolView from expo-symbols, but SKILL.md line 85 states: "expo-image with source='sf:name' for SF Symbols, not expo-symbols or @expo/vector-icons". Consider updating to use the recommended approach for consistency.

📝 Suggested fix using expo-image
-import { SymbolView } from "expo-symbols";
+import { Image } from "expo-image";

Then in the JSX:

-<SymbolView name="photo" />
+<Image source="sf:photo" style={{ width: 24, height: 24 }} />
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/building-native-ui/references/media.md at line 19, The file
currently imports SymbolView from expo-symbols which contradicts SKILL.md's
guidance; replace the import and usage of SymbolView (from "expo-symbols") with
the recommended expo-image approach by importing from expo-image and rendering
the SF Symbol via source='sf:name' (update any JSX where SymbolView is used to
the expo-image component and pass the SF Symbol name via the source prop),
ensuring the code aligns with SKILL.md's "expo-image with source='sf:name' for
SF Symbols" recommendation.
🧹 Nitpick comments (13)
.agents/skills/building-native-ui/references/storage.md (1)

5-25: Align storage recommendations with the project’s MMKV pattern.

This section currently positions expo-sqlite/localStorage as the default key-value approach, but project convention already uses a storage utility backed by MMKV for theme preference. Please update the table/text so this guide doesn’t steer contributors away from established architecture.

Based on learnings: Theme preference is persisted in MMKV via the storage utility from @/utils/storage.

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

In @.agents/skills/building-native-ui/references/storage.md around lines 5 - 25,
Update this guide to recommend the project's MMKV-backed storage utility (the
exported storage from "@/utils/storage") instead of the expo-sqlite localStorage
polyfill for simple key-value data; change examples to show using the storage
utility's get/set methods (e.g., storage.set / storage.get or storage.setItem /
storage.getItem as implemented) and update the "When to Use What" table to list
"Project MMKV storage (storage from `@/utils/storage`)" for simple key-value use,
keep expo-sqlite for large/relational datasets and expo-secure-store for
sensitive data, and remove or de-emphasize importing
"expo-sqlite/localStorage/install" so contributors follow the established MMKV
pattern used for theme preference persistence.
.agents/skills/building-native-ui/references/form-sheet.md (1)

25-26: Consider aligning example file paths with this repo’s Expo Router layout.
These snippets reference app/..., while this project convention uses src/app/.... Updating comments/paths in examples would reduce onboarding friction.

Based on learnings: Use Expo Router with file-based organization where the entry point is src/app/_layout.tsx.

Also applies to: 56-57, 94-95, 136-137, 164-165

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

In @.agents/skills/building-native-ui/references/form-sheet.md around lines 25 -
26, Update the example Expo Router file paths in the documentation to match this
repo’s layout by changing occurrences of "app/..." to "src/app/..." in the
examples (e.g., the import example showing app/_layout.tsx and the Stack import
from "expo-router"); ensure all referenced snippets that import or reference
_layout.tsx, Stack, or other Expo Router files at lines noted (including the
other occurrences analogous to 56-57, 94-95, 136-137, 164-165) use "src/app/..."
so the examples reflect the actual project file-based routing entry point.
.agents/skills/upgrading-expo/references/native-tabs.md (1)

35-35: Minor: iOS version notation.

"iOS +26" is an unconventional notation. Consider using "iOS 26+" for consistency with typical version documentation.

Proposed fix
-New component for Apple Music-style mini players on iOS +26 that float above the tab bar:
+New component for Apple Music-style mini players on iOS 26+ that float above the tab bar:
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/upgrading-expo/references/native-tabs.md at line 35, Update
the iOS version notation in the phrase "Apple Music-style mini players on iOS
+26" to the conventional format "iOS 26+"; locate the sentence containing "iOS
+26" and replace it with "iOS 26+" so the documentation uses standard version
ordering.
.agents/skills/find-skills/SKILL.md (1)

85-94: Add language specifiers to fenced code blocks.

The example response blocks at lines 85 and 136 lack language specifiers. Adding text or plaintext would satisfy markdown linting.

Proposed fix
-```
+```text
 I found a skill that might help! The "react-best-practices" skill provides
-```
+```text
 I searched for skills related to "xyz" but didn't find any matches.

Also applies to: 136-142

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

In @.agents/skills/find-skills/SKILL.md around lines 85 - 94, Add language
specifiers to the two fenced code blocks containing the example responses "I
found a skill that might help! The "react-best-practices" skill provides..." and
"I searched for skills related to "xyz" but didn't find any matches." in
SKILL.md by changing their opening triple-backticks to include a plain text
language (e.g., ```text or ```plaintext) so the markdown linter recognizes them
as plaintext code blocks; update both example blocks accordingly.
.agents/skills/native-data-fetching/SKILL.md (1)

1-507: Consider documenting project-specific data fetching patterns.

Based on learnings, this project uses generateUseQueryHook(queryFn) and generateUseMutationHook(mutationFn) factory functions to ensure consistent loading state and error handling. This skill documentation covers generic React Query usage but doesn't mention these project-specific patterns.

Consider adding a section that documents how to use these factory functions and when to prefer them over direct useQuery/useMutation calls.

Based on learnings: Data fetching should go through generateUseQueryHook(queryFn) or generateUseMutationHook(mutationFn) factory functions to ensure consistent loading state and error handling.

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

In @.agents/skills/native-data-fetching/SKILL.md around lines 1 - 507, Add a
project-specific subsection to the SKILL.md that documents the
generateUseQueryHook(queryFn) and generateUseMutationHook(mutationFn) factory
functions: explain that data fetching should prefer these factories over direct
useQuery/useMutation to ensure consistent loading, error shape, and retry
behavior; briefly describe their expected inputs/outputs (accept a
queryFn/mutationFn and return a hook exposing data, isLoading, error,
refetch/mutate), note common configuration (staleTime, retries, error handling),
and when it’s acceptable to bypass them; reference the symbols
generateUseQueryHook and generateUseMutationHook and update the “When to Use” or
“React Query” sections to point readers to this project convention.
.agents/skills/building-native-ui/references/icons.md (1)

1-213: Consider documenting cross-platform icon strategy.

This guide exclusively covers SF Symbols, which are iOS-only. For a cross-platform React Native app, you'll need a fallback strategy for Android. The directive to "Never use FontAwesome or Ionicons" (line 3) is strong, but the PR title mentions migrating to lucide-react-native, which suggests cross-platform icon usage is needed.

Consider adding a section that addresses:

  • How to handle Android (where SF Symbols aren't available)
  • When to use lucide-react-native vs expo-symbols
  • A decision tree for choosing the right icon solution
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/building-native-ui/references/icons.md around lines 1 - 213,
Add a cross-platform icon strategy section to this SF Symbols guide: explain
that expo-symbols/SymbolView is preferred on iOS but not available on Android,
provide a fallback approach (use lucide-react-native on Android or a shared
wrapper component), clarify when to use lucide-react-native vs expo-symbols
(platform-first: expo-symbols for iOS-only multicolor/animated SF Symbols,
lucide-react-native for consistent cross-platform icons), soften or remove the
absolute "Never use FontAwesome or Ionicons" rule, and include a small decision
tree and example of a wrapper component name (e.g., Icon or PlatformIcon) that
selects SymbolView vs LucideIcon at runtime.
src/app/(authenticated)/history/_layout.tsx (1)

17-32: JSX props should be sorted alphabetically.

The options object properties headerShown and tabBarIcon should be reordered alphabetically. As per coding guidelines, all JSX props must be sorted alphabetically (enforced by Biome useSortedAttributes).

♻️ Proposed fix
       <Tabs.Screen
         name="daily-challenges"
         options={{
-          title: 'Dnevni izzivi',
-          tabBarIcon: ({ color }) => <CalendarIcon color={color} size={24} />,
           headerShown: false,
+          tabBarIcon: ({ color }) => <CalendarIcon color={color} size={24} />,
+          title: 'Dnevni izzivi',
         }}
       />
       <Tabs.Screen
         name="training-challenges"
         options={{
-          title: 'Trening izzivi',
-          tabBarIcon: ({ color }) => <GraduationCapIcon color={color} size={24} />,
           headerShown: false,
+          tabBarIcon: ({ color }) => <GraduationCapIcon color={color} size={24} />,
+          title: 'Trening izzivi',
         }}
       />
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/app/`(authenticated)/history/_layout.tsx around lines 17 - 32, Reorder
the properties inside the options objects passed to Tabs.Screen so JSX props are
alphabetically sorted: in both instances of Tabs.Screen (names
"daily-challenges" and "training-challenges") move tabBarIcon before headerShown
(so properties read "tabBarIcon" then "headerShown"), ensuring the options
object keys are alphabetized to satisfy the useSortedAttributes rule.
src/app/(authenticated)/play/daily-puzzle-solved.tsx (1)

52-57: Consider adding a color prop to ArrowUpRightIcon for visual consistency.

The Text component inside the link will inherit theme-based text color, but ArrowUpRightIcon has no explicit color prop. This might result in a color mismatch depending on how lucide icons handle default colors with react-native-unistyles theming.

🎨 Proposed fix
                   <Pressable style={styles.solutionLink}>
                     <Text size="xs" weight="medium">
                       SSKJ
                     </Text>
-                    <ArrowUpRightIcon size={14} />
+                    <ArrowUpRightIcon color={theme.colors.foreground} size={14} />
                   </Pressable>

Note: This would require accessing the theme, either via useStyles() hook or by converting the icon color into a style function similar to other patterns in the codebase.

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

In `@src/app/`(authenticated)/play/daily-puzzle-solved.tsx around lines 52 - 57,
The ArrowUpRightIcon inside the Pressable lacks an explicit color which can
mismatch the Text; update the component to pass a color prop computed from the
app theme (use the existing useStyles() hook or a style-derived color function)
so the icon color matches the Text (e.g., derive the same theme text color used
by the Text component and pass it into ArrowUpRightIcon), locating and updating
the ArrowUpRightIcon usage in the daily-puzzle-solved.tsx file.
.agents/skills/convex-quickstart/SKILL.md (1)

103-111: Add a language specifier to the fenced code block.

The directory structure code block should have a language specifier (e.g., text or plaintext) to satisfy markdown lint rules and improve rendering consistency.

📝 Proposed fix
-```
+```text
 my-app/
   convex/           # Backend functions and schema
     _generated/     # Auto-generated types (check this into git)
     schema.ts       # Database schema (if template includes one)
   src/              # Frontend code (or app/ for Next.js)
   package.json
   .env.local        # CONVEX_URL / VITE_CONVEX_URL / NEXT_PUBLIC_CONVEX_URL

</details>

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

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

In @.agents/skills/convex-quickstart/SKILL.md around lines 103 - 111, Update the
fenced directory-structure code block to include a language specifier by
changing the opening triple backticks from totext (or plaintext) so the block becomes text followed by the directory tree; leave the contents
unchanged and retain the closing ``` as-is.


</details>

</blockquote></details>
<details>
<summary>src/components/ui/Card/Card.tsx (1)</summary><blockquote>

`1-2`: **Use mixed value+type import form for `lucide-react-native`.**

Please merge these into a single mixed import to match repo convention.

<details>
<summary>♻️ Proposed refactor</summary>

```diff
-import type { LucideIcon } from 'lucide-react-native';
-import { PencilIcon } from 'lucide-react-native';
+import { PencilIcon, type LucideIcon } from 'lucide-react-native';
```
</details>

 
As per coding guidelines: "Use `import type { X }` syntax for type-only imports; for mixed imports use `import { Component, type ComponentProps }` syntax".

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

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

In `@src/components/ui/Card/Card.tsx` around lines 1 - 2, The two separate imports
for lucide-react-native should be merged into a single mixed import: replace the
separate "import type { LucideIcon }" and "import { PencilIcon }" with one
statement that imports the runtime PencilIcon and the type LucideIcon together
(e.g., import { PencilIcon, type LucideIcon } from 'lucide-react-native');
update the top of Card.tsx where LucideIcon and PencilIcon are imported so the
file follows the repo's mixed value+type import convention.
```

</details>

</blockquote></details>
<details>
<summary>.agents/skills/building-native-ui/references/route-structure.md (1)</summary><blockquote>

`18-18`: **Add language identifiers to fenced code blocks.**

These fenced blocks are missing a language tag, which will keep failing markdownlint (MD040).



Also applies to: 30-30, 69-69, 95-95, 112-112, 155-155

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

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

In @.agents/skills/building-native-ui/references/route-structure.md at line 18,
Update every fenced code block in route-structure.md that currently uses plain

(for example ```bash, ```js, ```json, ```ts, etc.) so the blocks pass
markdownlint rule MD040; scan the document for all backtick fences without a
language tag and replace them with the correct language marker while preserving
the existing code text.
.agents/skills/convex-performance-audit/references/occ-conflicts.md (1)

67-74: Clarify the sharding example with initialization code.

The sharding pattern references shardIds[shardIndex] and SHARD_COUNT but doesn't show how these are initialized. Consider adding a brief comment or preceding lines showing the setup:

📝 Suggested clarification
+// Initialize shard IDs during setup:
+// const SHARD_COUNT = 10;
+// const shardIds = await Promise.all(
+//   Array.from({ length: SHARD_COUNT }, () => 
+//     ctx.db.insert("pollCounters", { count: 0 })
+//   )
+// );
+
 // Good: shard the counter across multiple documents, aggregate on read
 const shardIndex = Math.floor(Math.random() * SHARD_COUNT);
 const shardId = shardIds[shardIndex];
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/convex-performance-audit/references/occ-conflicts.md around
lines 67 - 74, Add initialization for the sharding example by showing how
SHARD_COUNT and shardIds are defined and populated before using shardIndex and
shardId; specifically, declare SHARD_COUNT (number of shards), build shardIds
(array of document IDs for each shard) and optionally show a
creation/initialization step that ensures each shard document exists with a
count field so subsequent calls to shard = await ctx.db.get(shardId) and await
ctx.db.patch(shardId, { count: shard!.count + 1 }) won't fail due to missing
documents. Ensure references to SHARD_COUNT, shardIds, shardIndex, shardId, and
the shard documents creation/initialization are included in the preceding lines
or a brief comment.
.agents/skills/expo-cicd-workflows/scripts/fetch.js (1)

49-51: Consider documenting hash collision risk for long-term cache usage.

The 16-character hex truncation (64 bits) is sufficient for typical URL counts but could theoretically collide with very large URL sets. This is acceptable for a dev tooling cache, but a brief inline comment noting the tradeoff would aid future maintainers.

📝 Optional: Add clarifying comment
 function hashUrl(url) {
+  // 16 hex chars = 64 bits; collision probability negligible for typical URL counts
   return createHash('sha256').update(url).digest('hex').slice(0, 16);
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.agents/skills/expo-cicd-workflows/scripts/fetch.js around lines 49 - 51,
Add a brief inline comment above the hashUrl function explaining that the result
is a 16-char hex truncation (64-bit) of a SHA-256 digest, noting the small
theoretical collision risk for very large URL sets and that this truncation is a
deliberate tradeoff for shorter cache keys in dev tooling; mention that
increasing slice length (or using the full digest) is an option if collision
risk becomes a concern.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.agents/skills/building-native-ui/references/controls.md:
- Around line 180-190: The example imports and uses Stepper from "react-native"
but Stepper is not a core RN API (so the import and the usage of Stepper,
value={count}, onValueChange={setCount}, minimumValue/maximumValue will break);
replace this example with a community package (e.g., import the Stepper
component from "react-native-ui-stepper" or another suggested library) and
update the example to use that package's API (replace the import of Stepper from
"react-native" and ensure props match the chosen package's prop names for
value/change/min/max) or remove the Stepper section entirely if you prefer not
to recommend a third‑party package.

In @.agents/skills/building-native-ui/references/route-structure.md:
- Line 177: The import line uses the internal subpath; update the example to
import Stack as a named export from the main package by replacing the incorrect
"expo-router/stack" import with a named import from "expo-router" (i.e., change
the import that references Stack so it imports Stack from the main expo-router
package rather than the "expo-router/stack" subpath).

In @.agents/skills/building-native-ui/references/storage.md:
- Line 5: Remove the absolute ban on AsyncStorage and replace it with scoped
guidance: change the sentence "Never use AsyncStorage" to a recommendation that
prefers the localStorage polyfill for new key-value needs but allows
AsyncStorage for existing identity persistence; explicitly mention that Convex
user identity is stored as a Convex user ID in AsyncStorage on first account
creation and that the central hook is useUser(), so preserve that existing flow
while recommending localStorage polyfill for new features.

In @.agents/skills/expo-cicd-workflows/scripts/validate.js:
- Around line 28-35: The code calls readFile(filePath, 'utf-8') which can throw
(missing file, permission denied) and currently bypasses the per-file error
reporting; wrap the readFile call in a try/catch (or handle its promise
rejection) before attempting yaml.load so that IO errors return a per-file
result like { valid: false, error: `File read error: ${err.message}` } instead
of letting the process crash, keeping the existing yaml.parse error handling for
yaml.load as-is; target the readFile/filePath usage in validate.js to implement
this change.
- Line 55: The current entrypoint check uses import.meta.main which is not
available on older Node versions; replace the condition in the module's
top-level entry check (the line using import.meta.main) with a standard pattern
that compares new URL(import.meta.url).pathname (or new
URL(import.meta.url).toString()) to process.argv[1] (after resolving to the same
form) to detect direct invocation; update the surrounding block that runs the
script (the code guarded by the import.meta.main check) to run when that
comparison matches, ensuring you normalize both sides (URL vs file path) using
the URL constructor and path utilities as needed so the script remains
compatible across Node 18/20/22/24.

---

Minor comments:
In @.agents/skills/building-native-ui/references/media.md:
- Around line 70-71: The example uses <GlassButton> but it is not defined or
imported; add a GlassButton component definition (used by the camera example)
that accepts onPress and icon props and composes GlassView, TouchableOpacity,
and Image so selectPhoto and the setType toggle work; ensure the component name
is GlassButton, props are { onPress: () => void; icon: string }, it renders a
tappable GlassView wrapper and displays the SF icon via Image (tintable), and
export or include it in the same file so the sample JSX lines with <GlassButton
onPress={selectPhoto} ... /> and <GlassButton onPress={() => setType(t => t ===
"back" ? "front" : "back")} ... /> compile.
- Line 19: The file currently imports SymbolView from expo-symbols which
contradicts SKILL.md's guidance; replace the import and usage of SymbolView
(from "expo-symbols") with the recommended expo-image approach by importing from
expo-image and rendering the SF Symbol via source='sf:name' (update any JSX
where SymbolView is used to the expo-image component and pass the SF Symbol name
via the source prop), ensuring the code aligns with SKILL.md's "expo-image with
source='sf:name' for SF Symbols" recommendation.

In @.agents/skills/building-native-ui/references/webgpu-three.md:
- Around line 508-519: The Markdown code fence containing the file tree starting
with "src/" is missing a language specifier; update the opening triple-backtick
fence to include a language (e.g., ```text) so markdownlint stops flagging
it—modify the code block in webgpu-three.md that begins with ``` and the
subsequent tree lines (src/, app/, components/, lib/, etc.) to use ```text.
- Around line 523-539: The fenced decision-tree code block starting with "Need
3D graphics?" is missing a language specifier which triggers markdownlint;
update that block by adding a language tag (e.g., ```text) after the opening
triple backticks so the block becomes fenced with a specifier and the rest of
the tree (lines containing "Need 3D graphics?", "Simple shapes → mesh + geometry
+ material", "Animated objects → useFrame + refs", etc.) remains unchanged.
- Around line 250-257: The example's Scene component uses useEffect (and React
hooks) but doesn't import them; add the missing React hook import by importing
useEffect (or importing React) at the top of the example so Scene, which calls
useEffect and useThree() and manipulates camera.position/camera.lookAt, will run
without runtime errors.
- Around line 565-575: The example's GameScene component uses useEffect but the
top import only includes useRef, useState, useCallback; update the React import
to also include useEffect so GameScene can call useEffect without runtime errors
(locate the import near the top of the example and add useEffect to the import
list that supplies useRef/useState/useCallback).

In @.agents/skills/building-native-ui/references/zoom-transitions.md:
- Line 152: Update the sentence that currently reads "When source is unavailable
(e.g., scrolled off screen), the transition zooms from the center of the screen"
by replacing "scrolled off screen" with the hyphenated form "scrolled
off-screen" for improved readability; locate this exact sentence in
zoom-transitions.md and make the single-word change.

In @.agents/skills/convex-performance-audit/SKILL.md:
- Line 67: The link text in .agents/skills/convex-performance-audit/SKILL.md
currently points to skills/convex-migration-helper/SKILL.md which is a stale
path; update the reference to the repository's actual skill docs location (e.g.,
.agents/skills/convex-migration-helper/SKILL.md) so the string literal in the
file matches the correct directory, and verify any other occurrences of
"convex-migration-helper" in .agents/skills/* to ensure consistent, working
internal links.

In @.agents/skills/convex-setup-auth/references/convex-auth.md:
- Around line 20-21: The install instruction pins `@auth/core` exactly to 0.37.0
but `@convex-dev/auth` v0.0.91 requires a caret range; update the command that
currently shows `npm install `@convex-dev/auth` `@auth/core`@0.37.0` to use the
caret range `@auth/core@^0.37.0` so the peer dependency requirement is satisfied
and compatible patch releases are allowed.

In @.agents/skills/expo-cicd-workflows/scripts/validate.js:
- Around line 59-64: The current combined condition uses (files.length === 0 ||
args.includes('--help') || args.includes('-h')) which causes validate --help to
exit with code 1 when no files exist; split the logic so that if
args.includes('--help') || args.includes('-h') you print the Usage message and
call process.exit(0), otherwise if files.length === 0 you print the Usage
message and call process.exit(1); update the conditional around the Usage/exit
block (referencing the variables args, files and the process.exit call) to
implement this branching.

In @.agents/skills/expo-deployment/references/play-store.md:
- Around line 29-42: Clarify that serviceAccountKeyPath in the example is
optional and describe the recommended credential flow: explain that EAS manages
Android submission credentials via its internal Credentials system and that the
preferred, more secure approach is to upload the Google Service Account Key in
the EAS dashboard (Android > [package] > Service Credentials) so eas submit uses
it automatically; if keeping the eas.json example with serviceAccountKeyPath,
add a clear note that this is for local workflows only (not recommended for
CI/CD) and advise adding the key file to .gitignore when used.

In @.agents/skills/expo-deployment/SKILL.md:
- Around line 123-136: Update the broken relative links in SKILL.md that use the
singular path './reference/' to the correct plural './references/' so the links
to testflight.md, ios-app-store.md, play-store.md and workflows.md resolve;
search for occurrences of the string './reference/' in the file and replace them
with './references/' (e.g., './reference/testflight.md' →
'./references/testflight.md').

In @.agents/skills/native-data-fetching/references/expo-router-loaders.md:
- Around line 179-187: The loader uses a non-null assertion on request
(request!.url) which can be undefined in static output mode; update the loader
(export const loader) to guard request before accessing url (use request?.url or
an explicit if (!request) branch) and handle the static case by returning safe
defaults (e.g., { results: [], query: "" }) or by deriving query/page from a
fallback URL, then call fetchSearchResults only when you have a valid
query/page; reference the loader function and replace request!.url with a
guarded access or early-return to avoid runtime errors.

In @.agents/skills/native-data-fetching/SKILL.md:
- Around line 16-19: The fenced code block containing the directory listing (the
lines with "references/" and "expo-router-loaders.md   Route-level data loading
with Expo Router loaders (web, SDK 55+)") is missing a language specifier;
update the opening fence from ``` to include a language such as ```text (or
```txt) so the block becomes ```text and resolves the markdownlint warning while
preserving the existing content.
- Around line 419-453: The fenced decision-tree code block that begins with the
line "User asks about networking" is missing a language specifier and causes a
markdownlint warning; fix it by changing the opening fence from ``` to ```text
(and keep the matching closing fence) so the block is explicitly marked as plain
text — locate the fenced block that contains the routing/fetching/authentication
tree and update its opening fence accordingly.

In @.agents/skills/upgrading-expo/references/new-architecture.md:
- Line 72: Replace the incorrect command fragment "bunx xcobra expo eval
\"_IS_FABRIC\"" by using the proper tool invocation: change "xcobra" to "expo"
so it reads "bunx expo eval \"_IS_FABRIC\"" (or if bunx is not used in your
environment, use the common alternative "npx expo eval \"_IS_FABRIC\""); update
the command text in the document accordingly.

In @.agents/skills/upgrading-expo/references/react-19.md:
- Line 22: Update the awkward sentence about `use`: replace "use can be called
conditionally, this simplifies components that consume multiple contexts." with
"use can be called conditionally, which simplifies components that consume
multiple contexts."; edit the line referencing the `use` hook in react-19.md to
use the suggested wording for clarity.

In @.agents/skills/upgrading-expo/SKILL.md:
- Around line 84-94: The docs entry for deprecated icons is inconsistent: update
the migration table row that currently maps `@expo/vector-icons` →
`expo-symbols` to reflect the chosen project icon library
(`lucide-react-native`) or clearly document both options and when to use them;
edit the row in SKILL.md replacing `expo-symbols` with `lucide-react-native` (or
add an additional replacement column/note), and include a brief note about
platform differences (SF Symbols iOS-only vs lucide-react-native cross-platform)
so readers know which replacement applies.

---

Nitpick comments:
In @.agents/skills/building-native-ui/references/form-sheet.md:
- Around line 25-26: Update the example Expo Router file paths in the
documentation to match this repo’s layout by changing occurrences of "app/..."
to "src/app/..." in the examples (e.g., the import example showing
app/_layout.tsx and the Stack import from "expo-router"); ensure all referenced
snippets that import or reference _layout.tsx, Stack, or other Expo Router files
at lines noted (including the other occurrences analogous to 56-57, 94-95,
136-137, 164-165) use "src/app/..." so the examples reflect the actual project
file-based routing entry point.

In @.agents/skills/building-native-ui/references/icons.md:
- Around line 1-213: Add a cross-platform icon strategy section to this SF
Symbols guide: explain that expo-symbols/SymbolView is preferred on iOS but not
available on Android, provide a fallback approach (use lucide-react-native on
Android or a shared wrapper component), clarify when to use lucide-react-native
vs expo-symbols (platform-first: expo-symbols for iOS-only multicolor/animated
SF Symbols, lucide-react-native for consistent cross-platform icons), soften or
remove the absolute "Never use FontAwesome or Ionicons" rule, and include a
small decision tree and example of a wrapper component name (e.g., Icon or
PlatformIcon) that selects SymbolView vs LucideIcon at runtime.

In @.agents/skills/building-native-ui/references/route-structure.md:
- Line 18: Update every fenced code block in route-structure.md that currently
uses plain ``` to include the appropriate language identifier matching the block
content (for example ```bash, ```js, ```json, ```ts, etc.) so the blocks pass
markdownlint rule MD040; scan the document for all backtick fences without a
language tag and replace them with the correct language marker while preserving
the existing code text.

In @.agents/skills/building-native-ui/references/storage.md:
- Around line 5-25: Update this guide to recommend the project's MMKV-backed
storage utility (the exported storage from "@/utils/storage") instead of the
expo-sqlite localStorage polyfill for simple key-value data; change examples to
show using the storage utility's get/set methods (e.g., storage.set /
storage.get or storage.setItem / storage.getItem as implemented) and update the
"When to Use What" table to list "Project MMKV storage (storage from
`@/utils/storage`)" for simple key-value use, keep expo-sqlite for
large/relational datasets and expo-secure-store for sensitive data, and remove
or de-emphasize importing "expo-sqlite/localStorage/install" so contributors
follow the established MMKV pattern used for theme preference persistence.

In @.agents/skills/convex-performance-audit/references/occ-conflicts.md:
- Around line 67-74: Add initialization for the sharding example by showing how
SHARD_COUNT and shardIds are defined and populated before using shardIndex and
shardId; specifically, declare SHARD_COUNT (number of shards), build shardIds
(array of document IDs for each shard) and optionally show a
creation/initialization step that ensures each shard document exists with a
count field so subsequent calls to shard = await ctx.db.get(shardId) and await
ctx.db.patch(shardId, { count: shard!.count + 1 }) won't fail due to missing
documents. Ensure references to SHARD_COUNT, shardIds, shardIndex, shardId, and
the shard documents creation/initialization are included in the preceding lines
or a brief comment.

In @.agents/skills/convex-quickstart/SKILL.md:
- Around line 103-111: Update the fenced directory-structure code block to
include a language specifier by changing the opening triple backticks from ```
to ```text (or ```plaintext) so the block becomes ```text followed by the
directory tree; leave the contents unchanged and retain the closing ``` as-is.

In @.agents/skills/expo-cicd-workflows/scripts/fetch.js:
- Around line 49-51: Add a brief inline comment above the hashUrl function
explaining that the result is a 16-char hex truncation (64-bit) of a SHA-256
digest, noting the small theoretical collision risk for very large URL sets and
that this truncation is a deliberate tradeoff for shorter cache keys in dev
tooling; mention that increasing slice length (or using the full digest) is an
option if collision risk becomes a concern.

In @.agents/skills/find-skills/SKILL.md:
- Around line 85-94: Add language specifiers to the two fenced code blocks
containing the example responses "I found a skill that might help! The
"react-best-practices" skill provides..." and "I searched for skills related to
"xyz" but didn't find any matches." in SKILL.md by changing their opening
triple-backticks to include a plain text language (e.g., ```text or
```plaintext) so the markdown linter recognizes them as plaintext code blocks;
update both example blocks accordingly.

In @.agents/skills/native-data-fetching/SKILL.md:
- Around line 1-507: Add a project-specific subsection to the SKILL.md that
documents the generateUseQueryHook(queryFn) and
generateUseMutationHook(mutationFn) factory functions: explain that data
fetching should prefer these factories over direct useQuery/useMutation to
ensure consistent loading, error shape, and retry behavior; briefly describe
their expected inputs/outputs (accept a queryFn/mutationFn and return a hook
exposing data, isLoading, error, refetch/mutate), note common configuration
(staleTime, retries, error handling), and when it’s acceptable to bypass them;
reference the symbols generateUseQueryHook and generateUseMutationHook and
update the “When to Use” or “React Query” sections to point readers to this
project convention.

In @.agents/skills/upgrading-expo/references/native-tabs.md:
- Line 35: Update the iOS version notation in the phrase "Apple Music-style mini
players on iOS +26" to the conventional format "iOS 26+"; locate the sentence
containing "iOS +26" and replace it with "iOS 26+" so the documentation uses
standard version ordering.

In `@src/app/`(authenticated)/history/_layout.tsx:
- Around line 17-32: Reorder the properties inside the options objects passed to
Tabs.Screen so JSX props are alphabetically sorted: in both instances of
Tabs.Screen (names "daily-challenges" and "training-challenges") move tabBarIcon
before headerShown (so properties read "tabBarIcon" then "headerShown"),
ensuring the options object keys are alphabetized to satisfy the
useSortedAttributes rule.

In `@src/app/`(authenticated)/play/daily-puzzle-solved.tsx:
- Around line 52-57: The ArrowUpRightIcon inside the Pressable lacks an explicit
color which can mismatch the Text; update the component to pass a color prop
computed from the app theme (use the existing useStyles() hook or a
style-derived color function) so the icon color matches the Text (e.g., derive
the same theme text color used by the Text component and pass it into
ArrowUpRightIcon), locating and updating the ArrowUpRightIcon usage in the
daily-puzzle-solved.tsx file.

In `@src/components/ui/Card/Card.tsx`:
- Around line 1-2: The two separate imports for lucide-react-native should be
merged into a single mixed import: replace the separate "import type {
LucideIcon }" and "import { PencilIcon }" with one statement that imports the
runtime PencilIcon and the type LucideIcon together (e.g., import { PencilIcon,
type LucideIcon } from 'lucide-react-native'); update the top of Card.tsx where
LucideIcon and PencilIcon are imported so the file follows the repo's mixed
value+type import convention.

@zigcccc zigcccc merged commit 4151294 into main Mar 20, 2026
4 checks passed
@zigcccc zigcccc deleted the PET-42-replace-expo-vector-icons-with-lucide-react-native branch March 20, 2026 10:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant