ReadyNative
For agents

Conventions

The rules a ReadyNative app expects you to follow: the @/lib shim contract, where code lives, the files setup owns, how to extend the graph

These are the rules the repo won't tell you itself. Follow them and your change looks like the rest of the app; break one and the next bun run gen:graph, bun run lint or bun run doctor tells on you.

The shim contract

Every capability is reached through @/lib/<category>: @/lib/auth, @/lib/payments, @/lib/analytics, @/lib/push, @/lib/crash, @/lib/storage. The shim exists whether or not a module was selected - when the category is none, the shim is a no-op with exactly the same signature, so a screen written against it compiles and runs either way.

That single rule is what keeps screens portable:

  • Import @/lib/auth from a screen, never @supabase/supabase-js or another vendor SDK.
  • To swap a provider, rewrite the shim, not its call sites. That's the whole point.
  • UI comes from @/components/ui (Screen, Box, Text, Button, Row, List, …), not from raw react-native views: the primitives carry the theme tokens and dark mode. Styling has the pattern.

Where things live

In the finalized tree bun run setup leaves:

PathWhat belongs there
src/approutes only - every file is a route, _layout.tsx files are navigators
src/screensscreen bodies; a route imports one and renders it
src/components/uithe primitive kit, reached as @/components/ui; types in types.ts
src/componentsyour own shared components, next to the kit
src/storeszustand stores (or whatever the state category selected)
src/libthe shims, env.ts, the API client - the app's plumbing
src/hookshooks shared across screens
src/themetokens.ts, the design tokens every stack's theme is generated from
docsARCHITECTURE.md and graph.json, both generated

Before setup, or after setup --keep-modules, the kit is in src/ui/<stack> behind @/ui, typed by the UI contract, and modules/ holds every option.

Keep non-route code out of src/app: expo-router turns every file there into a route, and a helper next to a screen becomes a URL nobody asked for.

Generated - do not hand-edit

Each of these files has an owner that rewrites it:

FileOwner
src/providers.tsxsetup (from every selected module's providers[], sorted by order)
src/lib/env.ts, .env.examplesetup (from every module's env[])
.readynative.jsonsetup - the record of what was applied
src/global.css, tailwind.config.js, tamagui.config.tsbun run gen:theme, from src/theme/tokens.ts (whichever your stack uses)
public/.well-known/*bun run gen:links
docs/graph.json, docs/ARCHITECTURE.mdbun run gen:graph

Editing one of these isn't fatal, only temporary: the next generator run overwrites you. To add an env key, add it to src/lib/env.ts and .env.example, then re-run bun run gen:graph; bun run doctor is what tells a human the key is missing from .env.

setup runs once

In a finalized tree, bun run setup is a stub that prints "Already applied" - there's no "re-run setup with a different option". Switching an option starts from a fresh clone; see Can I change a module after setup?.

Extending the graph

gen:graph only knows about files. When you add something it can't see - a background job, a webhook, an external service - say so where you wrote it, with a one-line annotation in any src/** file:

// @graph node=job:digest kind=feature label="Nightly digest" edges=lib:api/client,env:EXPO_PUBLIC_API_URL

One node per line. node is the id, kind is one of module, service, provider, route, screen, feature, hook, store, lib, env, script, custom (anything else becomes custom), label is quoted and edges is a comma-separated list of node ids the new node points at.

For anything with no natural home under src/, add it to docs/graph.extra.json, which is merged verbatim and has the last word over both the generator and the annotations:

{
  "nodes": [{ "id": "service:stripe", "kind": "service", "label": "Stripe" }],
  "edges": [{ "from": "service:stripe", "to": "env:EXPO_PUBLIC_API_URL", "kind": "reads" }]
}

An edge pointing at a node that doesn't exist is reported as a warning, not an error - it may point at work you haven't done yet.

Commands

bun run doctor       # env keys, config placeholders, EAS login, SDK versions
bun run gen:graph    # docs/graph.json + docs/ARCHITECTURE.md (--check fails when stale)
bun run gen:theme    # src/theme/tokens.ts to src/global.css / tailwind.config.js / tamagui.config.ts
bun run gen:links    # links config to public/.well-known/*
bun run gen:assets   # assets/brand/icon.png to icons and splash
bun run typecheck && bun run lint && bun run test

Install packages with expo install, never a bare add - it resolves the version that matches this SDK:

bunx expo install expo-haptics

Use whichever package manager's lockfile is in the repo (bun.lock → bun, package-lock.json → npm, and so on); the scripts themselves run under plain node, so all four work. A library with native code needs a dev build (bunx expo run:ios), not Expo Go - see Expo Go or a dev build.

Run lint and typecheck before you call a task done.

On this page

Get ReadyNative