Skip to main content
Mobile Launcher
First App Launch in 30 minutes

Initialize Your Project

Run yarn init:project to turn the boilerplate into your own app, then let yarn verify:identity prove that none of the template's identity survived.

Turn the boilerplate into your app

A fork of this boilerplate once reached a working feature loop, three merged pull requests and a live backend while still wearing the parent's bundle id, the parent's URL scheme, and a third app's Firebase project. Every test passed. Every build succeeded. Nothing errored, because nothing in the repo was capable of erroring on it. The symptom surfaced weeks later, in a runtime log, when someone worked out that every analytics event that app had ever recorded had been landing in another project the whole time.

So the bootstrap does not stop at "it builds". It ends in a check that reads your tree and fails the run while any of the template's identity is still in it.

yarn init:project rewrites your identity files and runs expo prebuild --clean. Run it once, on a fresh clone, before you have written code you would hate to lose. To see what it does without touching native folders, copy the repo somewhere throwaway and run node init.js --no-native.

These two commands arrive with the init identity bootstrap change, dated 2026-08-22 and written up in ai_rules/migrations/2026-08-22-init-identity-bootstrap.md inside the boilerplate. If yarn verify:identity is not listed in your package.json, pull the latest boilerplate and follow that migration file, which carries the exact steps.

Before you start

Four things. init asks for each one, and three of the four decide whether the final check passes.

What you needWhy it mattersWhere to get it
A bundle id you ownIt goes into app.json as ios.bundleIdentifier and android.package, and Firebase has to be registered against the same stringReverse DNS on a domain you control, for example com.yourcompany.yourapp
Your own Firebase project, with both config files downloadedinit copies google-services.json and GoogleService-Info.plist into the repo root. Skip this and the tree still names the template's project, which is exactly the failure aboveFirebase Setup
A square source image, 1024x1024 or largerinit resizes it to 1024x1024 for every icon and splash image app.json declares. A directory of prepared assets works tooIcons and Splash
An iOS Google OAuth client id, only if you want Google sign inLeave it blank and the template's GIDClientID key is removed outright. Google sign in stays off until you add your own, which beats silently pointing at somebody else's OAuth clientFirebase console, iOS app, OAuth client

Register both the iOS bundle id and the Android package in Firebase before you run init. The check compares the package name inside each config file against app.json, and a config exported before you registered the right identifier will fail it.

Run it

yarn init:project

Seven steps, in this order.

StepIt asks forIt writes
1. Recordnothing.init-parent-identity.json, the identity you forked from, captured before anything is rewritten
2. App ideaname, one line pitch, categoryai_rules/app_approach/product_description.md, and only while that file is still byte identical to the committed template. Author it yourself first and this step skips instead of overwriting you
3. Identitybundle id, Android package, URL scheme, iOS Google client idapp.json name, slug, scheme, ios.bundleIdentifier, android.package, ios.infoPlist.CFBundleURLTypes, ios.infoPlist.GIDClientID, plus AUTH_SCHEME in src/features/auth/constants/index.ts
4. Firebasepaths to your two config filescopies both into the repo root
5. Brand colorsa preset, or your own hexthe ten accent* literals in src/ui/tokens/colors.ts, plus expo.android.adaptiveIcon.backgroundColor
6. Icon and splasha square image, or a directory of prepared assetsevery image path app.json declares
7. Verifynothingnothing. It reads, and a non zero exit stops the run

Then, unless you passed --no-native, it runs yarn install, expo prebuild --clean, and verifies a second time. That second pass matters: prebuild writes ios/ and android/, and those trees carry their own copies of the Firebase configs and the bundle id.

The color presets

midnight-lime, warm-sand, deep-violet, mono-ink, forest (the boilerplate default), or custom to supply your own light and dark hex.

Each preset is a starting point for the accent ramp, nothing more. init writes accent tokens and stops there, because the semantic map in src/ui/style/colors-theme.ts already dereferences them. For the full design system, typography, spacing, radii and motion, run the design system generator afterwards. See Claude Design.

Icon resizing uses what is already on your machine

From a single square image, init tries macOS sips first, then Python's Pillow. No new dependency is added for this. If it finds neither, it says so and asks you for a directory of prepared assets instead, named to match what app.json declares.

The check that ends the run

scripts/verify-identity.js is the reason this page exists. It is executable, it runs at the end of init, and you can run it on its own any time:

yarn verify:identity

Seven things get checked.

  1. app.json declares a scheme, an iOS bundle id and an Android package.
  2. AUTH_SCHEME equals app.json's expo.scheme. A stale one breaks OAuth redirects quietly.
  3. expo.scheme is registered in CFBundleURLTypes, so a deep link opens your app and not the template's.
  4. Every Firebase config in the tree names one single project id.
  5. Each Firebase config's bundle id and package name match app.json. This is the check that catches an app running as one identity and reporting as another.
  6. The icons and splash images app.json declares are not byte identical to the template's.
  7. None of the recorded parent identity strings survive anywhere in app.json, either Firebase config, src/features/auth/constants/index.ts, or the generated ios/ and android/ trees.

Findings are reported by record key and file:line, never by value, because a couple of those strings are credential adjacent.

Exit codes:

CodeMeaning
0clean
1at least one check failed
2a check could not run, which is treated as a failure and never as a pass

Why the check does not go stale

The template's identity strings are not hardcoded anywhere in the verifier. Step 1 of init reads your tree before it rewrites anything and records what it found to .init-parent-identity.json. The verifier then asserts the absence of exactly those strings, so it stays correct for any future variant of the boilerplate without anyone maintaining a list.

Do not delete .init-parent-identity.json. Without it the absence sweep and the icon check cannot run, and the verifier exits 2 rather than reporting a clean pass on a check it never performed. The file is gitignored on purpose, since it is per fork and some of its values are credential adjacent.

If you are working in the template repo itself, and it is meant to wear the template identity, skip the absence sweep explicitly:

node scripts/verify-identity.js --template

That still runs the positive checks: scheme parity, Firebase project consistency, and the bundle id match.

You are done when the check passes

Not when it builds. Building was never the thing that broke.

  • yarn verify:identity exits 0 on the source tree
  • It still exits 0 after expo prebuild --clean, with ios/ and android/ on disk
  • .init-parent-identity.json exists and is not committed
  • Your Firebase console shows events arriving in your project, not somebody else's

Prove the check can actually fail before you trust a green one. On a throwaway copy, change AUTH_SCHEME in src/features/auth/constants/index.ts to something else, run yarn verify:identity, and watch it exit 1 and name the check. Then put it back.

Non interactive runs

Useful in CI, or when you want the same bootstrap twice.

node init.js --answers answers.json node init.js --answers answers.json --no-native

answers.json accepts these keys: projectName, pitch, category, iosBundleIdentifier, androidPackage, scheme, googleClientId, googleServicesJson, googleServiceInfoPlist, theme, brandColorLight, brandColorDark, vibe, radius, iconSource, platform.

--no-native skips yarn install, expo prebuild --clean and the app launch, so only the source tree is touched and only the first verify pass runs.

Common issues

What you seeWhat it means
no .init-parent-identity.json and exit 2The record is missing, so the absence sweep cannot run. Re run yarn init:project, or pass --template if this really is the template repo
AUTH_SCHEME does not equal app.json expo.schemeYour scheme changed in app.json but not in src/features/auth/constants/index.ts. OAuth redirects will break
BUNDLE_ID does not match app.jsonYour Firebase config was exported for a different identifier. Register the right bundle id and package in Firebase and download both files again
is byte-identical to the template'sThat icon or splash image is still the template's. Re run the icon step with your own artwork
no image tool availableNeither sips nor Python's Pillow is on this machine. Pass a directory of prepared assets instead of a single image
WARNING: no icon source givenYou skipped the icon step. It is a warning at that moment and a failure at step 7

Next

With the app wearing its own identity, carry on to Tool Integration for Supabase and RevenueCat, then First App Launch for environment variables and your first run.