# AI Agent Instructions for NEO Monorepo > **Purpose:** This document provides structured guidance for LLM coding agents working on the NEO monorepo. Follow these instructions to maintain code quality, consistency, and project integrity. --- ## Table of Contents - [NEO project summary](#neo-project-summary) - [Installed agent skills](#installed-agent-skills) - [Skill precedence (NEO vs generic guidance)](#skill-precedence-neo-vs-generic-guidance) - [Customization and fork branches](#customization-and-fork-branches) - [Project Structure Rules](#project-structure-rules) - [Framework Awareness](#framework-awareness) - [Server vs Client Components](#server-vs-client-components) - [Component Architecture](#component-architecture) - [Styling Guidelines](#styling-guidelines) - [Animated icons (NEO)](#animated-icons-neo) - [UNA CMS API Integration](#una-cms-api-integration) - [Code Quality Checklist](#code-quality-checklist) --- ## NEO project summary NEO is a **Yarn workspaces monorepo** with **Turborepo** ([`turbo.json`](turbo.json)): shared application code lives in [`packages/app`](packages/app), the web app in [`apps/next`](apps/next) (Next.js 16, App Router), and the native app in [`apps/expo`](apps/expo) (Expo 54, React Native). Styling uses **Uniwind** (Tailwind CSS v4 syntax for React Native) on native and **Tailwind CSS 4** (via `@tailwindcss/postcss`) on web, with semantic design tokens from settings—see [README.md](README.md) for versions, scripts (`yarn web`, `yarn native`), and setup, and [uniwind.md](uniwind.md) for the NativeWind→Uniwind migration notes. **Product integration** (see also [.cursorrules](.cursorrules)): the frontend targets **UNA CMS** APIs (not a generic REST backend). Use [`app/lib/fetcher`](packages/app/lib/fetcher.js) for requests, follow `/api.php?r=module/action/Template` patterns, respect proxy/env configuration for web vs native, and use **Pusher** where real-time updates are required. Authentication and menus follow existing `currentUser` and [`app/lib/util`](packages/app/lib/util.js) patterns. **Routing**: Expo Router under `apps/expo/app/`, Next.js App Router under `apps/next/app/`. **Backend contract for UNA developers** ([`una-api` skill](.agents/skills/una-api/SKILL.md)): blocks and services must tolerate **guest (non-logged-in) users**—guard user/profile access, avoid PHP fatals, and return **JSON** for NEO. A fatal or HTML error page on a block breaks page JSON parsing and can blank the whole screen. **How installed skills help**: Vercel-oriented skills add React/Next performance guidance, cache/PPR notes, Turborepo usage, UI/accessibility audits, deploy automation, browser automation, and Expo/native UI patterns. They **do not** replace NEO-specific rules above when the two conflict—see [Skill precedence](#skill-precedence-neo-vs-generic-guidance). --- ## Installed agent skills Skills are installed with the [Vercel Agent Skills](https://vercel.com/docs/agent-resources/skills) workflow (`npx skills add `, optionally `--skill `). **Canonical copy:** [`.agents/skills/`](.agents/skills/) at the repo root (one directory per skill, typically with `SKILL.md`). The CLI also writes **`skills-lock.json`** at the repo root (version pins/hashes for reproducibility) and may create **`.claude/skills/`** symlinks into `.agents/skills/`. **Trae** and **Windsurf** are not used—`.trae/` and `.windsurf/` are gitignored if recreated. This repo also ships **local** skills (not from `npx skills`): [`una-api`](.agents/skills/una-api/SKILL.md) and [`react-doctor`](.agents/skills/react-doctor/SKILL.md). Commit **`.agents/`**, **`skills-lock.json`**, and **`.claude/skills/`** so the team shares the same capabilities; they are not ignored by default. **CLI note:** the `skills` package uses **different `--skill` ids** than some GitHub folder names—for `vercel-labs/agent-skills`, use ids such as `vercel-react-best-practices`, `vercel-composition-patterns`, and `vercel-react-native-skills` (not always the short folder names). Run `npx skills add ` interactively or check the CLI’s “Available skills” list if a flag fails. | Skill (install id / folder) | Source repo | Use when | |----------------------------|-------------|----------| | `vercel-react-best-practices` | [vercel-labs/agent-skills](https://github.com/vercel-labs/agent-skills) | React/Next performance, bundles, rerenders, server/client data patterns | | `vercel-composition-patterns` | same | Compound components, reducing boolean prop sprawl, scalable component APIs | | `vercel-react-native-skills` | same | React Native / Expo performance, lists, navigation, images, gestures | | `web-design-guidelines` | same | Auditing web UI for a11y, UX, forms, motion—map suggestions to **design tokens** where applicable | | `deploy-to-vercel` | same | Deploy flows and Vercel-oriented deployment tasks | | `next-best-practices` | [vercel-labs/next-skills](https://github.com/vercel-labs/next-skills) | Next.js app patterns, bundling, fonts, hydration, async | | `next-cache-components` | same | Cache Components / `use cache` / PPR-oriented guidance | | `next-upgrade` | same | Next.js upgrade assistance (CLI may flag **higher codegen risk**—review changes) | | `turborepo` | [vercel/turborepo](https://github.com/vercel/turborepo) | Task graph, caching, CI, monorepo boundaries | | `agent-browser` | [vercel-labs/agent-browser](https://github.com/vercel-labs/agent-browser) | Browser automation / debugging workflows tied to that toolchain | | `building-native-ui` | [expo/skills](https://github.com/expo/skills) | Expo Router native UI patterns (tabs, media, controls)—complements shared `packages/app` code | | `uniwind` | [uni-stack/uniwind](https://github.com/uni-stack/uniwind) | Uniwind / Tailwind CSS v4 styling in React Native: `className` on RN components, theming, variants, Metro config | | `una-api` | NEO (local, [`.agents/skills/una-api`](.agents/skills/una-api)) | UNA CMS guest-safe blocks, JSON API responses, `fetcher`/`/api.php?r=...` alignment with `packages/app` | | `react-doctor` | NEO (local, [`.agents/skills/react-doctor`](.agents/skills/react-doctor)) | Code-quality sweep when finishing a feature or before committing: lint, dead code, a11y, bundle size, architecture diagnostics | --- ## Skill precedence (NEO vs generic guidance) 1. **UNA integration** — Always use [`fetcher`](packages/app/lib/fetcher.js), correct `/api.php?r=...` endpoints, env/proxy rules, and expectations in the [`una-api` skill](.agents/skills/una-api/SKILL.md). Generic Next/React skills may assume arbitrary APIs. 2. **Cross-platform** — Shared UI and logic belong in `packages/app`; keep [`icon.js`](packages/app/ui/atoms/icon.js) / [`iconset.js`](packages/app/ui/atoms/iconset.js) / [`iconset.web.js`](packages/app/ui/atoms/iconset.web.js) and other platform splits consistent with [.cursorrules](.cursorrules). For **animated** Lucide icons (registry, scenes, SVG constraints), follow [animated-icons.md](animated-icons.md). 3. **Design system** — Prefer semantic tokens and existing components over hardcoded colors or ad hoc Tailwind from generic “design audit” outputs. 4. **React Compiler** — This repo targets Next.js 16 with React Compiler; follow [Framework Awareness](#framework-awareness) here. Skills that push blanket `memo`/`useCallback` should be applied only when justified (profiling or clear benefit). 5. **Server vs client** — RSC applies in [`apps/next/app`](apps/next/app) only. Shared code in [`packages/app`](packages/app) is predominantly client (`'use client'`) because it must also run under Expo. Do not strip `'use client'` from `packages/app` for “RSC purity.” --- ## Customization and fork branches **Extension point for derivative work:** [`packages/app/customization/resources/agents.md`](packages/app/customization/resources/agents.md) and [`packages/app/customization/resources/claude.md`](packages/app/customization/resources/claude.md) **reference** this file and [`CLAUDE.md`](CLAUDE.md) at the repo root and hold **per-project** notes (client UNA setup, deployment, team conventions). See [`packages/app/customization/resources/README.md`](packages/app/customization/resources/README.md) for the full workflow. **Merge hygiene:** On the **upstream** monorepo, keep those customization files **small** so they seldom conflict. In **branch or fork projects** that track upstream, **prefer changing only files under `packages/app/customization/`** (including `resources/`) instead of editing root `AGENTS.md` / `CLAUDE.md` or default files under `packages/app/` when a customization hook exists—so upstream merges stay straightforward. --- ## Project Structure Rules The active monorepo surface is: ``` apps/next apps/expo packages/app ``` ### Rules for Main Apps When working on `next` or `expo`: 1. **Share code through `packages/app`** 2. **Follow the established component hierarchy** (see Component Architecture) 3. **Keep web and native implementations aligned** 4. **Use Uniwind (native) + Tailwind CSS 4 conventions already established in the repo** ### Import Verification Before adding imports, verify the source: ```javascript // ✅ CORRECT for main apps import { Button } from 'app/ui/atoms/button'; import { settings } from 'app/customization/settings'; // ❌ WRONG - bypassing shared app code from feature files import { SomeExternalComponent } from 'external-lib'; ``` --- ## Framework Awareness ### Always Check Installed Versions Before implementing features, **verify the installed framework versions**: ```bash # Check package.json in the relevant app directory cat apps/next/package.json | grep -E '"next"|"react"' cat apps/expo/package.json | grep -E '"expo"|"react-native"' ``` ### Current Framework Versions (Keep Updated) | Framework | Version | Key Changes | |-----------|---------|-------------| | **Next.js** | 16.3.x | React Compiler support (stable), new caching patterns, `use cache` directive | | **React** | 19.1.x | Actions, `use()` hook, improved Suspense | | **Expo** | 54.x | New Architecture enabled by default, expo-router 6 | | **React Native** | 0.81.x | Bridgeless mode, concurrent features | | **Tailwind CSS** | 4.2.x | Web via `@tailwindcss/postcss` | | **Uniwind** | 1.6.x | Native Tailwind v4 (`apps/expo/global.combined.css`) | ### Lookup Documentation When Uncertain If you're unsure about best practices for the installed version: 1. **Next.js 16:** Check https://nextjs.org/docs for latest patterns 2. **Expo 54:** Check https://docs.expo.dev for latest APIs 3. **React 19:** Check https://react.dev for new patterns ### React Compiler Next.js 16 has **stable React Compiler support**. This means: - Manual `useMemo`, `useCallback`, and `React.memo` are often unnecessary - The compiler auto-memoizes components and values - Remove redundant memoization when it doesn't serve a specific purpose --- ## Server vs Client Components ### Where each model applies (NEO) | Layer | Default | Notes | |-------|---------|--------| | [`apps/next/app`](apps/next/app) | **Server Components** | Thin shells: fetch page JSON, pass into shared client tree | | [`packages/app`](packages/app) | **Client** (`'use client'`) | Shared with Expo/React Native — not RSC | | [`apps/expo`](apps/expo) | Client / native | Expo Router; no RSC | Prefer Server Components **inside `apps/next/app`** when they do not need hooks or browser APIs. Do **not** refactor shared `packages/app` UI into RSC. ```javascript // ✅ PREFERRED in apps/next/app — Server Component page shell export default async function Page() { const data = await fetchData(); return ; // packages/app Root is client } // ✅ EXPECTED in packages/app — Client Component 'use client'; export default function InteractiveWidget() { const [state, setState] = useState(); // ... } ``` ### When Client Components Are Required (Next app routes) Use `'use client'` in `apps/next` **only** for: 1. **React hooks that require client state:** `useState`, `useEffect`, `useRef` 2. **Browser APIs:** `window`, `document`, `localStorage`, `navigator` 3. **Event handlers that need state:** Click handlers with state updates 4. **Third-party client-only libraries** 5. **Anything imported from `packages/app` that already needs the client boundary** (usually already marked) ### Island Architecture Pattern When you must use client components under Next, **wrap them as islands** so parent server components can still stream: ```javascript // ✅ CORRECT - Island pattern // components/interactive-widget.client.js 'use client'; export function InteractiveWidget({ initialData }) { const [state, setState] = useState(initialData); return ; } // app/page.js (Server Component) import { Suspense } from 'react'; import { InteractiveWidget } from './components/interactive-widget.client'; export default async function Page() { const data = await fetchData(); // Server-side fetch return (

{data.title}

{/* Server rendered */} Loading...
}> ); } ``` ### Next.js 16 Caching Patterns Use the new `use cache` directive for data caching: ```javascript // ✅ Modern caching pattern (Next.js 16+) import { cacheLife } from 'next/cache'; async function getCachedData() { 'use cache'; cacheLife('hours'); // or 'minutes', 'days', 'weeks', 'max' return await fetchExpensiveData(); } // ❌ AVOID - Old pattern // unstable_cache is deprecated in favor of 'use cache' ``` ### Data Fetching Hierarchy 1. **Server Components** - Fetch directly with async/await 2. **`use cache` directive** - For expensive operations needing caching 3. **Route Handlers** - For API endpoints 4. **Client-side fetching** - Only when server-side is impossible (real-time updates, user-specific client data) --- ## Component Architecture ### Component Hierarchy Follow the established pattern for organizing components: ``` packages/app/ ├── ui/ │ ├── primitives/ # Basic building blocks (View, Text wrappers) │ ├── atoms/ # Simple, single-purpose components │ │ ├── button.js │ │ ├── input.js │ │ └── badge.js │ └── molecules/ # Composite components │ ├── card.js │ ├── dropdown-menu.js │ └── profile-hover-card.js ├── components/ │ ├── elements/ # Page section components │ ├── units/ # List item renderers │ ├── forms/ # Form components │ └── nav/ # Navigation components ``` ### Component Creation Rules 1. **Never add external components directly to pages/features** ```javascript // ❌ WRONG - Installing component in page // app/dashboard/page.js import { SomeExternalComponent } from 'external-lib'; // ✅ CORRECT - Wrap in ui/atoms or ui/molecules first // packages/app/ui/atoms/some-component.js import { SomeExternalComponent } from 'external-lib'; export function SomeComponent(props) { return ; } // Then use in pages import { SomeComponent } from 'app/ui/atoms/some-component'; ``` 2. **Check for existing components before creating new ones** ```bash # Search for existing components grep -r "ComponentName" packages/app/ui/ grep -r "similar-functionality" packages/app/ ``` 3. **Follow the component map pattern for overridable components** ```javascript // packages/app/customization/molecules/_map.js import { componentsMapDefault } from 'app/ui/molecules/_map'; import CustomComponent from 'app/customization/molecules/my-component'; componentsMapDefault['my-component'] = CustomComponent; export const componentsMap = componentsMapDefault; ``` ### Cross-Platform Components When creating components for both web and native: ```javascript // component.tsx (shared logic or web default) export function Component({ ...props }) { return Web/Shared; } // component.native.tsx (native-specific) export function Component({ ...props }) { return Native; } // component.web.tsx (web-specific, if needed) export function Component({ ...props }) { return
Web Only
; } ``` --- ## Styling Guidelines ### Use Existing Design Tokens **Always use design tokens from settings** - never hardcode colors or spacing: ```javascript // ✅ CORRECT - Using design tokens // ❌ WRONG - Hardcoded values ``` ### Theme Token Categories Reference tokens from `packages/app/default/settings.js` (and the `packages/app/settings/` modules it composes): | Category | Examples | |----------|----------| | **Colors** | `bg-card`, `text-foreground`, `border-border`, `bg-primary` | | **Spacing** | Use Tailwind scale: `p-2`, `p-3`, `p-4`, `gap-2`, `gap-4` | | **Typography** | `text-sm`, `text-base`, `text-lg`, `font-medium`, `font-semibold` | | **Borders** | `rounded-lg`, `rounded-xl`, `rounded-2xl`, `border`, `border-border/60` | | **Shadows** | `shadow-sm`, `shadow-md`, `shadow-lg` | ### Button Styling Use button variants from settings: ```javascript // Available variants (from settings.theme.button_styles)