Imported from mrmeg/expo-template (
AGENTS.md). Install upstream withnpx skills add mrmeg/expo-template. Copyright stays with the author.
Project Guidance
Bun-managed Expo template with reusable UI and media packages. Code directly unless the user asks for a plan.
How To Work
- Read this file first, then load only what the task needs.
- Validate with fresh command output; never claim tests, builds, UI checks, or CI passed from memory.
- Keep durable template guidance in
docs/or the relevant package README. - Reusable UI goes in
packages/ui; reusable media contracts and processing inpackages/media. - App integrations stay under
client/,server/,app/api/, orshared/.
Docs
| Doc | Path | Purpose |
|---|---|---|
| LLM Entry Point | llms.txt |
Index of fetchable LLM docs for external consumers |
| LLM Bundle | llms-full.txt |
Generated concat of the LLM docs; rebuild with bun run docs:llms |
| LLM Examples Index | llms-examples.txt |
Generated raw-URL index of demo routes, screens, components, server files |
| Template Guide | docs/template-modernization-guide.md |
LLM-facing component, screen-template, and modernization reference |
| Migration Guide | docs/migration-guide.md |
Portable, self-contained guide for migrating an external Expo app to this baseline |
| Server Guide | docs/server-guide.md |
Server output, rendering, API routes, data loaders, middleware, replication checklist |
| Bundle Analysis | docs/bundle-analysis.md |
Bundle-size guard usage and baseline update steps |
| Error Tracking | docs/error-tracking.md |
Sentry runtime (native + web) and native upload setup |
| E2E Tests | docs/e2e.md |
Maestro blank-env smoke suite: flows, setup, selector conventions, CI status |
| Media Worker Migration | docs/media-worker-migration.md |
Shared media Worker contract, consumer migration checklists, legacy-worker teardown |
| UI Package | packages/ui/README.md |
@mrmeg/expo-ui install, setup, components, theming, publishing |
| Media Package | packages/media/README.md |
@mrmeg/expo-media install, setup, processing, server handlers |
| Lint Package | packages/lint/README.md |
@mrmeg/eslint-plugin-expo-ui rules, CLI (bun lint:ui), settings, style contracts, adoption in other projects, troubleshooting, release |
Tech Stack
| Layer | Tech | Notes |
|---|---|---|
| Package manager | Bun | bun.lock; CI installs with bun install --frozen-lockfile |
| App runtime | Expo SDK 58 (beta), React 19.2, React Native 0.88 (RC) | Expo Router entry, native and web targets |
| Router | Expo Router 58 | Typed routes, API routes, server output, server rendering, middleware (stable) and data loaders |
| Language | TypeScript 6 strict | Path alias @/* points at repo root |
| UI | @mrmeg/expo-ui workspace package |
RN primitives, design tokens, theme state, reusable components |
| Media | @mrmeg/expo-media workspace package |
Client hooks, processing helpers, S3/R2 server handlers |
| Lint | @mrmeg/eslint-plugin-expo-ui workspace package |
Design-system ESLint rules; bun lint:ui for app, client, shared; published alongside @mrmeg/expo-ui; reads packages/ui/src here and dist/design-system.json in consumers |
| State/data | Zustand 5, TanStack React Query 5 | Persisted client stores; query defaults in app providers |
| Auth | Clerk or AWS Amplify/Cognito | Optional; env-selected (Clerk publishable key, or both Cognito vars; Cognito wins if both) behind a shared AuthClient/TokenVerifier |
| Billing | Stripe hosted-external baseline | Optional; disabled unless Stripe/server env is configured |
| Server | Bun server (server.bun.ts) |
Expo Server adapter, compression, CORS, rate limits, security headers |
| Observability | @sentry/react-native (native), @sentry/react (web, lazy) |
Runtime DSN and native upload config are separately env-gated |
| Testing | Jest 29, jest-expo, RNTL 14 | bun run verify runs CI's validate gates in order: packages:peer-check, typecheck, lint, check:features, gen:templates:check, gen:blocks:check, docs:llms:check, docs:versions:check, tests |
Project Notes
- Use the exact package scripts in
package.json; do not substitute generic Expo or npm commands when a local Bun script exists. - Quote route paths with parentheses or brackets in shell commands, for example
'app/(main)/(tabs)/index.tsx'. - Design-system rules — raw colors, off-scale spacing, appearance overrides on
@mrmeg/expo-uicomponents, raw primitives the design system already wraps — are enforced by@mrmeg/eslint-plugin-expo-ui(packages/lint/README.md) throughbun run lint, which coversapp/only.bun lint:uilintsapp,client, andsharedfor design-system violations alone,--changednarrows it to the files you touched, and--doctor [file]checks the plugin, the config, and the design system are wired. Read the message and use the token, variant, or component it names; never disable one of these rules without a-- reasonon the disable comment. - Auth, billing, media, and Sentry must fail closed when env is missing; a blank
.envkeeps the template explorable. - Web is server-rendered per request:
web.output: "server"plusunstable_useServerRenderingruns routes, loaders, middleware, and API routes on the server, so the first response carries real route markup. The server has no DOM: anything the first render needs comes off the request (server/lib/ssrViewport.ts,server/lib/ssrOnboarding.ts), and styles must be registered at module scope forclient/features/app/SsrStyleFlush.tsxto serialize them — seedocs/server-guide.md. Verify web changes in a browser againstbun run build && bun run start, not only Jest ortsc. - Five gallery routes under
app/(main)/(demos)—showcase/index.tsx,themed-showcase.tsx,components/index.tsx,components/[id].tsx,blocks/index.tsx— are one-line lazy shells; edit the bodies inclient/showcase/*Screen.tsx. Live previews stay out of the eager web bundle because they are reachable only throughclient/showcase/gallery.tsx, via the singleimport()inclient/showcase/lazyGallery.tsx;client/showcase/__tests__/gallerySplitPoint.test.tsfails on a static import from outsideclient/showcase/. - Generated artifacts, all gated by
bun run verifyand CI — regenerate and commit, never hand-edit:client/templates/registry.generated.tsandclient/blocks/registry.generated.ts(bun run gen:templates/gen:blocks);llms-full.txtandllms-examples.txt(bun run docs:llms, built byscripts/build-llms-full.mjsfrom its source-doc list and directory walks — rerun after editing those docs or adding/removing demo routes, screens, components, or form wrappers).bun run docs:versions:checkholdsREADME.md's version claims topackage.json.
Agent Workflow
Use this workflow only for planned work. Normal coding requests proceed directly.
write-speccreates a self-contained spec in the trackedAgent/folder;review-specmarks it ready or blocked.shiftimplements ready specs.dayshiftpins interactive mode;nightshiftruns ready AFK specs without questions.- Each spec becomes one
agent/*branch and draft PR against its declaredbase-branch. After the PR opens, set the spec'sstatus: in-reviewand itsprlink, and commit that on the base branch. Never includeAgent/files inagent/*PR diffs. review-shiftreviews and merges those PRs.- Keep target branches clean and synchronized. Verify with fresh command output.