@layers/amba-mcp 1.0.1 → 4.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,641 @@
1
+ //#region src/resources/amba-setup.ts
2
+ /**
3
+ * Canonical long-form Amba setup guide — markdown body.
4
+ *
5
+ * Companion to the short-form `instructions` field served by the MCP
6
+ * server's initialize response. The pointer "Full guide: amba://setup"
7
+ * in those instructions tells the agent to fetch this resource when it
8
+ * needs more detail than the ~1 KB summary provides.
9
+ *
10
+ * Consumed by:
11
+ *
12
+ * - The MCP resource at `amba://setup`, registered by
13
+ * `registerAllResources()` in `./index.ts` and exposed by the
14
+ * hosted MCP server at `mcp.amba.dev`. Any client (Claude Code,
15
+ * Cursor, Codex, Cowork, etc.) can fetch it via `resources/read`.
16
+ *
17
+ * Twin: this body is the server-side mirror of
18
+ * `packages/cli/skill-bundle/SKILL.md`, which the CLI installs locally
19
+ * during `npx @layers/amba init`. The two surfaces target two
20
+ * different audiences:
21
+ *
22
+ * - `SKILL.md` ships to a local `.claude/skills/amba/` and assumes
23
+ * the agent CAN shell out (the bootstrap path can `npx @layers/amba
24
+ * signup`). It also writes credentials into `.env.local` + `~/.amba/`.
25
+ * - `AMBA_SETUP_GUIDE_MD` (this constant) is served by the hosted MCP
26
+ * and assumes the agent CANNOT shell out (e.g. Claude.ai web).
27
+ * The bootstrap path must therefore use the `amba_developer_signup`
28
+ * MCP tool (the only pre-auth tool the server registers).
29
+ *
30
+ * The playbook shape (Step 0 → Step 1 classify → Step 2 confirm →
31
+ * Step 3 wire → Step 4 report) is identical between the two, so an
32
+ * agent reading either ends up at the same outcome. A drift gate test
33
+ * in `amba-setup.test.ts` asserts the structural anchors match.
34
+ *
35
+ * Taxonomy: the SDK capability map below is grouped under the canonical
36
+ * 7-category taxonomy (Identity / Engagement / Gamification / Economy /
37
+ * Social / Analytics / Infrastructure) — same shape as `categories.ts`,
38
+ * the marketing-site feature grid, and the docs IA. Drift is caught by
39
+ * `amba-setup.test.ts`.
40
+ *
41
+ * The body is plain CommonMark — no MDX, no JSX — so it renders
42
+ * identically wherever it lands.
43
+ */
44
+ const AMBA_SETUP_GUIDE_MD = `# Amba
45
+
46
+ ## What Amba is
47
+
48
+ Amba is the backend your app calls at runtime via the SDK. The MCP tools (\`amba_*\`) are for provisioning at build time — call them as the coding agent.
49
+
50
+ One Amba project = one isolated tenant database + one set of API keys + a hosted MCP at \`mcp.amba.dev\` for agent-driven provisioning. The runtime traffic goes through an SDK (\`@layers/amba-*\` on npm, \`Amba\` on SPM / Maven / pub.dev). The provisioning traffic — what you're about to do — goes through the tools listed below.
51
+
52
+ Your job is to take the user from "I have an app" to "Amba is wired in and the features are real" in one pass, without 12 follow-up questions. The journey below is the standard playbook. Don't deviate without a reason.
53
+
54
+ ## Step 0 — Bootstrap credentials
55
+
56
+ You're in an MCP client (Claude.ai web, Claude Desktop, Cursor, Windsurf, etc.) without a local CLI. The MCP server has one tool that works **without** a Bearer token: \`amba_developer_signup\`. Use it to mint a personal access token (PAT), project, and client/server keys in a single round trip — no browser, no email verification.
57
+
58
+ Call:
59
+
60
+ \`\`\`
61
+ amba_developer_signup({
62
+ email: "sandbox-<unix-seconds>-<6char-nonce>@layers.com",
63
+ password: "<32 random base64url chars>",
64
+ name: "amba-sandbox-agent"
65
+ })
66
+ \`\`\`
67
+
68
+ The response shape:
69
+
70
+ \`\`\`json
71
+ {
72
+ "data": {
73
+ "pat": "amb_dpat_…",
74
+ "developer": { "id": "…", "email": "…", "tier": "agent_sandbox" },
75
+ "project": {
76
+ "project_id": "…",
77
+ "client_key": "amb_ck_…",
78
+ "server_key": "amb_sk_…",
79
+ "provisioning_status": "provisioning",
80
+ "verify_url": "https://app.amba.dev/verify?token=…",
81
+ "verify_token": "…"
82
+ }
83
+ }
84
+ }
85
+ \`\`\`
86
+
87
+ After signup, the PAT is in your hand — keep building in THIS session immediately. Pass \`pat: "<the PAT from the response>"\` as an inline argument on every subsequent \`amba_*\` tool call; the inline arg overrides the inbound Bearer for that one call so no client config change is needed mid-session. For future sessions, write the matching snippet from \`mcp_config\` to the customer's MCP-client config file so the static Bearer takes over automatically on the next launch.
88
+
89
+ The project status is \`"provisioning"\` immediately after signup; the per-tenant DB activates within ~5 seconds. Don't block — your next call may briefly retry, that's fine. If you want to be polite, call \`amba_projects_get_provisioning_status({ project_id })\` once and proceed when it returns \`"active"\` (or after 15s, whichever first).
90
+
91
+ Tell the user where their credentials live:
92
+
93
+ - \`pat\` — the Bearer they should configure in this MCP client's settings (and treat like a password).
94
+ - \`project_id\`, \`client_key\` — the values they paste into their app's \`.env.local\` / \`.env\`.
95
+ - \`server_key\` — never ship to user devices; only into a server \`.env\` or a secret manager. The \`amb_dev_sk_\` / \`amb_live_sk_\` prefix is the marker.
96
+
97
+ **Already have a PAT?** Skip the signup. Call \`amba_developer_me({})\` to verify the Bearer; if it succeeds, either reuse the most recent project (\`amba_projects_list\`) or call \`amba_projects_create({ name: "<app-name>", platform: "all" })\` and then \`amba_api_keys_create\` twice to mint client + server keys for \`environment: "development"\`.
98
+
99
+ ## Step 1 — Classify the app
100
+
101
+ Look at what the user told you and at any files they shared. You're trying to pick one of ten presets in 30 seconds, not write a treatise. Inputs:
102
+
103
+ - The user's prompt — "I'm building a fitness tracker" / "a marketplace for…" / "a Duolingo for X".
104
+ - README content if shared.
105
+ - \`package.json\` / \`pubspec.yaml\` / \`build.gradle.kts\` / \`Package.swift\` — framework + dependencies.
106
+ - Screen / view names — \`WorkoutScreen\`, \`MatchView\`, \`LessonPage\`, \`CartView\`, \`ProductDetail\`, \`ChatThread\`.
107
+
108
+ Pick the closest match:
109
+
110
+ | Preset | When | Default Amba surfaces |
111
+ | --- | --- | --- |
112
+ | **fitness** | health / fitness tracker (workouts, steps, meditation) | identity (Apple+Google), push, XP, achievements, streaks, leaderboards, content (daily tips) |
113
+ | **social** | social network / community (friends, feeds, groups) | identity, push, friends, groups, feeds, messaging, moderation, content |
114
+ | **marketplace** | commerce / marketplace (catalog, stores, payments) | identity, push, catalog, stores, currencies (loyalty), reviews, segments |
115
+ | **productivity** | productivity / SaaS tool (collaboration, milestones) | identity (Apple+Google+OTP), push, collections, achievements, content (changelog), segments |
116
+ | **education** | education / learning app (courses, progress, rewards) | identity, push, XP, achievements, streaks, leaderboards, content (lessons), onboarding |
117
+ | **game** | game / casual gaming | identity (anon-first), push, XP, achievements, currencies, inventory, leaderboards, challenges, stores |
118
+ | **dating** | dating / matching app | identity (phone-OTP), push, friends (matches), messaging, moderation (heavy), reviews |
119
+ | **content_creator** | content platform (feeds, subscriptions, tips) | identity, push, feeds, content, currencies (tips), referrals, stores (subscriptions) |
120
+ | **ai_chatbot** | AI / chatbot / assistant app | identity, push, AI prompts, currencies (credits), content (system prompts), onboarding |
121
+ | **custom** | none of the above | pick features individually |
122
+
123
+ Detection heuristics, in priority order:
124
+
125
+ 1. The user's own description — most direct signal.
126
+ 2. Filename match in \`screens/\` or \`views/\` (high signal).
127
+ 3. Dependency in \`package.json\` — \`react-native-health\` → fitness, \`@stream-io/*\` → social or dating, \`@stripe/*\` → marketplace, \`revenuecat\` → marketplace or content_creator.
128
+ 4. README copy — "fitness", "habit", "match", "chat", "store", "subscription".
129
+
130
+ If two presets tie, pick the one the user's filenames match more closely. If still tied or no signal, fall back to **custom** and let them pick.
131
+
132
+ ## Step 2 — Confirm with the user
133
+
134
+ Use a single multi-choice. Quote the surfaces from the table above so they know what they're getting.
135
+
136
+ **Question 1: classification + scope**
137
+
138
+ > I'm reading this as a **\\{kind\\}** app. I'd wire up: **\\{surfaces\\}**. Sound right?
139
+ >
140
+ > 1. Yes, wire it up as proposed (Recommended)
141
+ > 2. Same kind but I want to pick features individually
142
+ > 3. Wrong kind — let me pick from the list
143
+ > 4. Custom — I'll pick features manually
144
+
145
+ If the user picks 1, go to Step 3. If 2 or 4, follow up with a multi-select of surfaces. If 3, present the table again and pick a different preset.
146
+
147
+ **Question 2 (preset-specific):** see the per-surface sub-resources (\`amba://setup/<surface>\`) for the full "Common follow-ups" list. Examples:
148
+
149
+ - **fitness / game / education** — leaderboard scope? (all-time, weekly, daily, none)
150
+ - **game / content_creator** — virtual currency name? (\`gold\`, \`gems\`, \`coins\`, \`credits\` — defaults to \`coins\`)
151
+ - **content_creator** — monetization? (tips, subscriptions, both)
152
+ - **dating** — phone OTP or email-only? (phone strongly recommended)
153
+ - **ai_chatbot** — daily free credit cap?
154
+
155
+ Batch the follow-ups into one or two multi-choice rounds. Don't drip-feed six separate questions.
156
+
157
+ ## Step 3 — Wire it up
158
+
159
+ For each surface in the confirmed set, read the relevant sub-resource and execute its procedure. Each sub-resource is the full per-surface playbook (MCP tools + SDK init per stack + common follow-ups + re-run behavior):
160
+
161
+ - **identity** (auth, anonymous/Apple/Google/OTP/magic-link, link/unlink) → \`amba://setup/identity\`
162
+ - **engagement** (push, segments, content libraries, onboarding flows, deeplinks, referrals, tracked links) → \`amba://setup/engagement\`
163
+ - **gamification** (XP rules, achievements, streaks, leaderboards, challenges) → \`amba://setup/gamification\`
164
+ - **economy** (currencies, catalog, stores, inventory) → \`amba://setup/economy\`
165
+ - **social** (friends, groups, feeds, messaging, moderation, reviews) → \`amba://setup/social\`
166
+ - **infrastructure** (collections / DB tables, functions, analytics, AI prompts, media, secrets, configs, integrations, sites) → \`amba://setup/infrastructure\`
167
+
168
+ The general flow for every surface:
169
+
170
+ 1. **Detect stack.** Look at \`package.json\`, \`pubspec.yaml\`, \`build.gradle.kts\`, \`ios/*.xcodeproj\`. The detection rules:
171
+ - \`pubspec.yaml\` present → Flutter.
172
+ - \`package.json\` with \`expo\` → Expo.
173
+ - \`package.json\` with \`react-native\` (no \`expo\`) → bare React Native.
174
+ - \`package.json\` with \`react\` (no \`react-native\`) → web (or Next.js — same SDK).
175
+ - \`Package.swift\` or \`*.xcodeproj\` only → iOS Swift.
176
+ - \`build.gradle.kts\` or \`build.gradle\` with \`com.android.application\` → Android Kotlin.
177
+ - Multiple (e.g. \`ios/\` + \`android/\` inside an Expo repo) → Expo wins.
178
+
179
+ 2. **Create resources via MCP.** Call the \`amba_<surface>_create\` tools to mint the definitions. Always include \`project_id\` from the project you created in Step 0. Always show the user the tool call before making destructive changes (creating a resource isn't destructive — but creating 30 of them is noisy).
180
+
181
+ 3. **Write SDK init code.** Drop the per-stack snippet (from the sub-resource) into the user's entry file. Detection:
182
+ - Expo / React Native: \`app/_layout.tsx\`, \`App.tsx\`, \`index.js\` (in that order)
183
+ - web / Next.js: \`app/layout.tsx\`, \`pages/_app.tsx\`, \`src/main.tsx\`, \`src/App.tsx\`
184
+ - iOS Swift: \`Sources/<App>/<App>App.swift\`, \`App/AppDelegate.swift\`
185
+ - Android Kotlin: \`app/src/main/java/.../<App>.kt\` (the \`Application\` subclass — create one if missing)
186
+ - Flutter: \`lib/main.dart\`
187
+
188
+ Always make additive edits — \`await Amba.configure(...)\` next to existing init, not replacing it. Never refactor existing auth or storage code; if the user has Firebase Auth or Supabase, leave it. Amba's auth is opt-in per call.
189
+
190
+ 4. **Run the project's existing test command** to confirm nothing broke. Detection:
191
+ - \`package.json\` \`scripts.test\` → \`npm test\` (or \`pnpm test\` if \`pnpm-lock.yaml\` present)
192
+ - \`pubspec.yaml\` → \`flutter test\`
193
+ - \`build.gradle.kts\` → \`./gradlew test\` (skip on first wire-up — slow)
194
+ - iOS — skip (need a simulator).
195
+
196
+ If tests fail because of your edits, undo the offending edit and surface a clear error. If they fail for unrelated reasons (pre-existing red), note it and proceed.
197
+
198
+ 5. **Verify with the SDK.** Tell the user to call \`Amba.diagnostics.ping()\` (\`Amba.Diagnostics.Ping()\` on Unity) in their entry file. It returns \`{ ok, server_project_id, environment, key_fingerprint, latency_ms }\`. \`ok: true\` with the expected \`server_project_id\` confirms the wiring.
199
+
200
+ ## Step 4 — Report
201
+
202
+ Tell the user a structured summary. Use this exact shape so they can skim it fast:
203
+
204
+ \`\`\`
205
+ Amba is wired in. Here's what changed:
206
+
207
+ DONE
208
+ - identity: Apple + Google sign-in available; signInAnonymously() called at app start
209
+ - gamification: 3 achievements, 1 streak, 1 leaderboard created
210
+ resources: first_workout, week_warrior, century_club / daily_workout / weekly_xp
211
+ - engagement: push registration wired; default segment "active_users" created
212
+
213
+ SKIPPED (low signal — re-run with /amba <feature> if you want them)
214
+ - economy: no in-app currency UI found in your screens
215
+ - social: no friends/feed surfaces found
216
+
217
+ NEEDS YOUR INPUT
218
+ - Apple Sign In: add the "Sign in with Apple" capability in Xcode > Signing & Capabilities.
219
+ - Google Sign In: paste your Google OAuth client ID into amba_projects_update({ google_oauth_client_id: "..." }).
220
+ - APNs / FCM: upload credentials in app.amba.dev before push delivers.
221
+
222
+ NEXT STEPS
223
+ - Paste AMBA_CLIENT_KEY into your build env (already shown above)
224
+ - Trigger a workout in your existing flow — watch the achievement unlock + XP land
225
+ - Open https://app.amba.dev to see users pour in
226
+ \`\`\`
227
+
228
+ Be specific. List resources by key, not "some achievements". If something needs the user's input (third-party credentials, OAuth client IDs, push certs), say it clearly with the exact next action.
229
+
230
+ ## Stance (read this once)
231
+
232
+ - **Don't ask which surfaces to use.** Classify, then confirm in one multi-choice. The taxonomy is the whole point.
233
+ - **Default to additive, non-breaking changes.** Don't refactor existing auth, storage, or networking code. Drop in \`await Amba.configure(...)\` next to whatever the user already has.
234
+ - **Never create resources without the user's confirmation in Step 2.** A 3rd-party "convenience" achievement called \`first_login\` is debt.
235
+ - **If something is genuinely ambiguous** (leaderboard scope, currency real-money vs virtual, dating phone vs email), ask via a follow-up multi-choice. Don't guess and don't paragraph-it.
236
+ - **clientKey vs serverKey.** \`AMBA_CLIENT_KEY\` (\`amb_dev_ck_…\` in dev, \`amb_live_ck_…\` in prod) ships to user devices. \`AMBA_SERVER_KEY\` (\`amb_dev_sk_…\` / \`amb_live_sk_…\`) never does — only into server \`.env\` or a secret manager. Mixing them is the #1 security mistake; if you're writing into a file that ships with the app binary, it's the client key, period.
237
+ - **Don't echo the PAT in chat output on every call.** Showing it once after signup is fine; do not repeat it.
238
+
239
+ ## Get credentials (cheat sheet)
240
+
241
+ - No terminal, in an MCP client: call \`amba_developer_signup\` (no Bearer required) — this guide's Step 0.
242
+ - With a terminal: \`npx -y @layers/amba init\` signs up, mints a project + client/server keys, writes \`.env.local\` + \`AMBA.md\`, installs the \`/amba\` skill, and wires \`mcpServers.amba\` into every detected MCP-client config in one command. Auto-detects non-TTY invocations (the coding-agent bash-tool case) and runs headlessly.
243
+ - Bind the sandbox account to a real email later: \`npx @layers/amba claim me@example.com\`. The backend emails a one-click magic link; clicking it lifts the sandbox cap to the Free tier.
244
+ - Hosted MCP endpoint: \`https://mcp.amba.dev/mcp\` (Streamable HTTP, Bearer auth).
245
+
246
+ ## SDKs
247
+
248
+ | Stack | Registry | Package |
249
+ |---|---|---|
250
+ | Browser / Node / React / React Native / Expo | npm | \`@layers/amba-{web,node,react,react-native,expo}\` |
251
+ | Swift | SPM | \`https://github.com/layers/amba-sdk-ios\` |
252
+ | Kotlin | Maven Central | \`com.layers.amba:amba-sdk-android\` |
253
+ | Flutter | pub.dev | \`amba\` |
254
+ | Unity | UPM (git) | \`https://github.com/layers/amba-sdk-unity.git\` |
255
+
256
+ All SDKs expose the same surface: \`Amba.configure({ projectId, apiKey })\`, then \`Amba.events.track(...)\`, \`Amba.users.*\`, \`Amba.collections.*\`, etc. Per-stack quickstart pages with the exact initialization snippet: \`https://docs.amba.dev/sdk/<framework>\`.
257
+
258
+ ## What Amba does
259
+
260
+ ### Identity
261
+ - **users** — app-user registry. Auto-created on first SDK call; admin via \`amba_users_*\`.
262
+ - **roles + permissions** — RBAC. Define with \`amba_roles_create\`; assign via \`amba_roles_assign\`.
263
+ - **api_keys** — client + server keys per project. Mint via \`amba_api_keys_create\`.
264
+
265
+ ### Engagement
266
+ - **onboarding** — multi-step first-run flows. Define with \`amba_onboarding_create\`; SDK \`Amba.onboarding.next()\`.
267
+ - **segments** — user cohorts. Define with \`amba_segments_create\`; used as push/feed targets.
268
+ - **push** — scheduled or triggered notifications. Chain: configure integrations (apns/fcm) → \`amba_push_campaigns_create\` → \`amba_push_campaigns_send\` (or schedule).
269
+ - **referrals** — referral codes. Define with \`amba_referrals_create\`.
270
+ - **deeplinks** — universal links. Set domain with \`amba_deeplinks_set_config\`.
271
+ - **tracked_links** — UTM-tagged outbound links. Define with \`amba_tracked_links_create\`.
272
+ - **content** — episodic delivery (lessons, quotes, daily prompts). Chain: \`amba_content_libraries_create\` → \`amba_content_items_add\` → \`amba_content_schedules_create\`.
273
+
274
+ ### Gamification
275
+ - **xp** — experience points + level. Define rules with \`amba_xp_rules_create\`; SDK \`Amba.xp.getBalance\`.
276
+ - **achievements** — earnable badges. Define with \`amba_achievements_create\`; unlock via xp rules or \`amba_inventory_grant_item\`.
277
+ - **streaks** — recurring engagement counters. Define with \`amba_streaks_create\`; client calls \`Amba.streaks.qualify(key)\`.
278
+ - **leaderboards** — ranked user lists. Define with \`amba_leaderboards_create\`; populated from events.
279
+ - **challenges** — time-bounded goals. Define with \`amba_challenges_create\`; progress via SDK.
280
+
281
+ ### Economy
282
+ - **currencies** — virtual currencies (coins, gems). Define with \`amba_currencies_create\`; grant via \`amba_currencies_grant\` or event rules via \`amba_currency_grant_rules_create\`.
283
+ - **catalog + stores** — purchasable items + storefronts. Chain: \`amba_catalog_items_create\` → \`amba_catalog_items_set_price\` → \`amba_stores_create\` → \`amba_stores_add_listing\`. (Define currency first.)
284
+ - **inventory** — items users own. Read via SDK \`Amba.inventory.*\`; grant with \`amba_inventory_grant_item\`.
285
+
286
+ ### Social
287
+ - **friendships** — friend graph. SDK \`Amba.friends.*\`; admin via \`amba_friendships_*\`.
288
+ - **groups** — guilds/parties/chats. Define with \`amba_groups_create\`; members managed via SDK + admin tools.
289
+ - **messaging** — DMs + group chat. Enabled by default; moderate via \`amba_messaging_*\`.
290
+ - **feeds** — algorithmic activity feeds. Define ranking with \`amba_feeds_rules_create\`.
291
+ - **reviews** — user-submitted reviews. Enabled by default; moderate via \`amba_reviews_*\`.
292
+ - **moderation** — content review queue + trust scores. Configure with \`amba_moderation_configure\`; review via \`amba_moderation_queue_list\`.
293
+
294
+ ### Analytics
295
+ - **events** — track user actions. SDK \`Amba.events.track()\`; query via \`amba_events_count\`.
296
+ - **sessions** — session telemetry. Tracked automatically; query via \`amba_sessions_list\`.
297
+ - **analytics** — funnels + retention. Query via \`amba_analytics_get\`.
298
+
299
+ ### Infrastructure
300
+ - **collections** — your own typed key-value tables. Define with \`amba_collections_create\`; read/write from SDK \`Amba.client.*\`.
301
+ - **functions** — serverless TypeScript handlers. Deploy with \`amba_functions_deploy\`; schedule with \`amba_functions_schedule\`.
302
+ - **sites** — static site hosting at \`*.app.amba.host\`. Deploy with \`amba_sites_deploy\`.
303
+ - **media** — file storage + CDN. Upload via \`amba_media_upload\`.
304
+ - **secrets** — env vars for functions. Set via \`amba_secrets_set\`.
305
+ - **configs** — remote config flags. Define with \`amba_configs_create\`.
306
+ - **integrations** — third-party webhooks (RevenueCat, Superwall, AppsFlyer, etc.). Configure with \`amba_integrations_configure\`.
307
+ - **ai_prompts** — versioned LLM prompts callable from SDK. Define with \`amba_ai_prompts_create\`; call via \`amba_ai_prompts_invoke\`.
308
+ `;
309
+ /** Canonical URI for the MCP resource. */
310
+ const AMBA_SETUP_GUIDE_URI = "amba://setup";
311
+ /** Canonical MIME type for the guide body. */
312
+ const AMBA_SETUP_GUIDE_MIME = "text/markdown";
313
+ /**
314
+ * Body-version marker. Bumped when the canonical body changes shape
315
+ * in a way that downstream agents should re-read. The CLI embeds it
316
+ * into every fan-out file (\`CLAUDE.md\`, \`AGENTS.md\`, etc.) so a
317
+ * re-init can detect stale content. Bumped to \`v2\` when this PR
318
+ * replaced the capability-only guide with the full classify → confirm
319
+ * → wire-up playbook.
320
+ */
321
+ const AMBA_SETUP_GUIDE_BODY_VERSION = "v2";
322
+ //#endregion
323
+ //#region src/resources/expo-build-prompt.ts
324
+ /**
325
+ * Canonical Amba Expo build prompt — markdown body (no MDX frontmatter).
326
+ *
327
+ * Source of truth for three customer-facing surfaces:
328
+ *
329
+ * 1. The published docs page at
330
+ * `https://docs.amba.dev/prompts/expo-build` — the MDX file at
331
+ * `apps/docs/content/docs/prompts/expo-build.mdx` ships the same
332
+ * body wrapped in fumadocs frontmatter.
333
+ * 2. The MCP resource `amba://prompts/expo-build` registered by
334
+ * `registerAllResources()` in `./index.ts` and exposed by the
335
+ * hosted MCP server at `mcp.amba.dev`.
336
+ * 3. The inlined snapshot baked into the `/amba-build` Claude Code
337
+ * skill by `amba init --sandbox` (see `packages/cli/src/skills.ts`).
338
+ *
339
+ * Drift between this constant and the MDX file is caught by
340
+ * `expo-build-prompt.test.ts` — that test reads the MDX from disk,
341
+ * strips the YAML frontmatter, and asserts it equals `EXPO_BUILD_PROMPT_MD`.
342
+ *
343
+ * **Update protocol:** edit the MDX (it's the human-facing surface;
344
+ * it renders on docs.amba.dev). Re-run the drift test. The test will
345
+ * fail with a diff. Apply the same diff here. The two are kept in
346
+ * sync by hand because the MDX must be statically parseable for
347
+ * fumadocs + we can't import `.md` files as raw strings without a
348
+ * build-step that pulls in extra config.
349
+ *
350
+ * The body itself is plain CommonMark — no MDX components, no JSX —
351
+ * so it renders identically as `.md` (the MCP / skill consumers) and
352
+ * as `.mdx` (the docs site).
353
+ */
354
+ const EXPO_BUILD_PROMPT_MD = `> **Last reviewed:** 2026-05-17. The canonical version of this page lives
355
+ > at [docs.amba.dev/prompts/expo-build](https://docs.amba.dev/prompts/expo-build).
356
+ > If you're reading an inlined snapshot from your
357
+ > \`.claude/skills/amba-build/SKILL.md\`, check the URL above for updates.
358
+
359
+ This is the prompt an AI coding agent runs to build a full Expo app
360
+ where Amba is the only backend. It's structured as a single \`/goal\`
361
+ directive — paste it, replace \`<DESIGN_HASH>\` with whatever describes
362
+ your design (a URL, a description, a Figma link), and let the agent
363
+ execute.
364
+
365
+ ## Quick setup
366
+
367
+ The CLI handles signup, project provisioning, env-file writes, and MCP
368
+ client config wiring in one command:
369
+
370
+ \`\`\`bash
371
+ npx -y @layers/amba init
372
+ \`\`\`
373
+
374
+ That's the entire setup. The CLI:
375
+
376
+ 1. Signs up an agent-mode developer account (no browser, no email
377
+ verification needed for sandbox).
378
+ 2. Creates an Amba project and mints a client key + admin PAT.
379
+ 3. Writes \`.env.local\` (\`AMBA_PROJECT_ID\`, \`AMBA_CLIENT_KEY\`,
380
+ \`AMBA_API_URL\`).
381
+ 4. Writes \`AMBA.md\` (project-scoped context for the agent).
382
+ 5. Auto-wires \`mcpServers.amba\` into every MCP client config it
383
+ detects on disk — Claude Code, Cursor, Windsurf.
384
+ 6. Verifies the PAT against the API and confirms it's good.
385
+
386
+ The Amba MCP toolset (\`amba_*\` tools — ~130 of them) is available to
387
+ the agent immediately: pass the freshly-minted \`pat\` as an inline
388
+ argument on every \`amba_*\` call in the current session. The next time
389
+ your MCP client starts it picks the PAT up from the config as the
390
+ inbound Bearer automatically — at that point the \`pat\` arg becomes
391
+ optional. No restart needed; nothing for you to do.
392
+
393
+ If you have the \`/amba-build\` skill installed (via
394
+ \`npx -y @layers/amba init\`), invoke it directly:
395
+
396
+ \`\`\`
397
+ /amba-build <DESIGN_HASH>
398
+ \`\`\`
399
+
400
+ Otherwise paste the prompt below.
401
+
402
+ ## Current known gotchas
403
+
404
+ Three remaining wrinkles you may hit. Everything else from the 2026-05
405
+ DX cascade is fixed.
406
+
407
+ - **Web CORS** — the public API does not currently send
408
+ \`Access-Control-Allow-Origin\` for browser-origin requests. Use the
409
+ agent's circuit-break-on-second-failure rule for web targets; for
410
+ Expo (iOS + Android) you'll never see this.
411
+ - **React Native bundle size** — the React Native SDK adds ~4 MB to
412
+ the JS bundle today. Functional, just heavier than the long-term
413
+ goal. Tracked separately.
414
+ - **Sandbox MAU cap (100)** — the agent-mode sandbox tier caps at 100
415
+ monthly active users. If you blow through it during testing, call
416
+ \`amba_users_reset_sandbox\` to clear the counter — that tool exists
417
+ specifically for this. Upgrade to the Free tier (1,000 MAU, 500 MB
418
+ DB) by running \`amba claim me@example.com\` from the terminal — the
419
+ backend emails a one-click magic link to the address you pass in;
420
+ clicking it binds the account to that email and lifts the cap.
421
+
422
+ ## How to read the design
423
+
424
+ If \`<DESIGN_HASH>\` is a URL to a packaged design (e.g. a download
425
+ link from your design tool of choice), unpack it before you start:
426
+
427
+ \`\`\`bash
428
+ mkdir -p design && cd design
429
+ curl -L "<DESIGN_HASH>" -o design.tar.gz
430
+ gunzip -c design.tar.gz | tar -x
431
+ ls
432
+ # Expected: README, chats/, project/ (or equivalent)
433
+ \`\`\`
434
+
435
+ Read the README first — it should tell you what each subdirectory
436
+ holds. The \`chats/\` directory typically contains conversation logs
437
+ that capture the design intent in dialog form; treat them as the
438
+ authoritative source for tone and feature priorities. The \`project/\`
439
+ directory holds the structured asset graph (screens, components,
440
+ styles).
441
+
442
+ If \`<DESIGN_HASH>\` is a freeform description (not a URL), skip the
443
+ unpacking and treat the description text as the design brief.
444
+
445
+ ## Use Amba for everything
446
+
447
+ The rule: any feature that touches data, identity, scheduling,
448
+ notifications, content, or social — use Amba. Don't reach for
449
+ AsyncStorage-as-database, don't bring in Firebase / Supabase / your
450
+ own server, don't roll a custom auth layer. The point of this build
451
+ is that Amba covers it all.
452
+
453
+ Specifically: every feature in the design that needs a backend maps
454
+ to an Amba primitive. If you can't find a fit, the rule is **escalate
455
+ in the gaps log** (see the verification gate), not "ship without
456
+ Amba." Skipping a primitive needs a written justification — the
457
+ verification gate enforces this.
458
+
459
+ ## Feature → Amba primitive map
460
+
461
+ | App feature | Amba primitive | MCP tools |
462
+ | -------------------------------------------------- | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
463
+ | User accounts (anonymous + Apple + Google + email) | Auth | \`amba_developer_signup\` (one-time bootstrap), \`Amba.signIn()\` SDK calls |
464
+ | Profile data (name, avatar, prefs) | App users | \`amba_users_list\`, \`amba_users_get\`, \`amba_users_bulk_update\` |
465
+ | Daily content (tips, lessons, quotes) | Content libraries + schedules | \`amba_content_libraries_create\`, \`amba_content_items_add\`, \`amba_content_schedules_create\`, \`amba_content_list_libraries\`, \`amba_content_list_items\`, \`amba_content_list_schedules\` |
466
+ | Push notifications | Push campaigns | \`amba_push_campaigns_create\`, \`amba_push_campaigns_send\`, \`amba_push_send_test\`, \`amba_push_list_campaigns\` |
467
+ | User segments (e.g. inactive 7d, premium) | Segments | \`amba_segments_create\`, \`amba_segments_list\`, \`amba_segments_evaluate\` |
468
+ | Daily streaks | Streaks | \`amba_streaks_create\`, \`amba_streaks_list\` (call \`streaks.qualify()\` from the SDK to record activity) |
469
+ | XP and levels | XP rules | \`amba_xp_rules_create\`, \`amba_xp_rules_list\`, \`amba_users_get_xp\` |
470
+ | Achievements / badges | Achievements | \`amba_achievements_create\`, \`amba_achievements_list\`, \`amba_achievements_get\` |
471
+ | Challenges (time-limited goals) | Challenges | \`amba_challenges_create\`, \`amba_challenges_list\`, \`amba_challenges_list_participants\` |
472
+ | Leaderboards | Leaderboards | \`amba_leaderboards_create\`, \`amba_leaderboards_list\`, \`amba_leaderboards_get\` |
473
+ | In-app currency / virtual goods | Economy (currencies + catalog + stores) | \`amba_currencies_create\`, \`amba_catalog_items_create\`, \`amba_stores_create\`, \`amba_currencies_grant\`, \`amba_users_get_inventory\` |
474
+ | Social (friends, groups, feed, DMs) | Social primitives | \`amba_create_group\`, \`amba_groups_list\`, \`amba_groups_update_member\`, \`amba_friendships_list\` (feeds + messaging via SDK: \`Amba.feeds.*\`, \`Amba.messaging.*\`) |
475
+ | Remote feature flags / config | Configs | \`amba_configs_create\`, \`amba_configs_list\`, \`amba_configs_update\` |
476
+ | Entitlements (premium / paywall) | RevenueCat / Superwall integration | \`amba_integrations_configure\`, \`amba_integrations_test\` |
477
+ | Custom data (anything not above) | Collections | \`amba_collections_create\`, \`amba_collections_alter\`, \`amba_collections_list\`, \`amba_admin_insert_row\`, \`amba_admin_list_rows\`, plus client-side \`Amba.collections.*\` |
478
+ | Analytics / event tracking | Events | \`Amba.events.track(...)\` from the SDK; query with \`amba_analytics_get\`, \`amba_users_list_events\` |
479
+
480
+ Every primitive above has list / read MCP tools you can use to verify
481
+ seed data after creation — the verification gate uses these to catch
482
+ "fake implementation" failure modes (where the app code thinks a thing
483
+ was created but nothing actually landed in the backend).
484
+
485
+ ## Seed data
486
+
487
+ Before writing app code, seed the backend with enough data that every
488
+ screen in the design has something realistic to render. Order:
489
+
490
+ 1. **Configs** — feature flags + tunable constants the app reads at
491
+ boot (\`amba_configs_create\`).
492
+ 2. **Segments** — at least one (e.g. "new_user", first 7 days) so
493
+ targeting works downstream.
494
+ 3. **Content libraries + schedules** — daily content for any
495
+ tips/quotes/lessons screen. Seed ≥30 items so the carousel /
496
+ day-stepper doesn't loop visibly.
497
+ 4. **Streaks** — define the streak shape (daily / weekly, grace
498
+ window, freeze policy).
499
+ 5. **XP rules** — events → XP-award rules so XP accrues from real
500
+ gameplay.
501
+ 6. **Achievements** — unlock criteria for badges.
502
+ 7. **Challenges** — at least one active challenge with rewards.
503
+ 8. **Leaderboards** — XP, streaks, or any custom metric.
504
+ 9. **Currencies + catalog + stores** — virtual currency, catalog
505
+ items, store listings (only if the design has an economy screen).
506
+ 10. **Collections** — schemas + sample rows for any custom data the
507
+ app needs (e.g. user-generated content, journal entries, custom
508
+ list items).
509
+ 11. **Push campaigns** — at least one welcome push + one re-engagement
510
+ push targeting your "new_user" segment.
511
+
512
+ After seeding, the verification gate (below) confirms each primitive
513
+ exists by calling the matching \`amba_*_list\` MCP tool. Empty list →
514
+ failure.
515
+
516
+ ## Engineering rules
517
+
518
+ These are non-negotiable. Violating any one of them fails the build
519
+ gate.
520
+
521
+ - **Expo Router with typed routes.** Use \`expo-router\` and enable
522
+ \`experiments.typedRoutes\` in \`app.json\`. Every screen is a
523
+ filesystem route; no manual navigation stacks.
524
+ - **TypeScript strict mode.** \`strict: true\` in \`tsconfig.json\`. Zero
525
+ \`any\`. Zero \`@ts-ignore\`. \`tsc --noEmit\` must pass.
526
+ - **React Native primitives only.** \`View\`, \`Text\`, \`Pressable\`,
527
+ \`ScrollView\`, \`FlatList\`, \`Image\`. No \`div\`, no \`span\`, no DOM-only
528
+ libs. The build target is iOS + Android + Web — every screen has to
529
+ render on all three.
530
+ - **Fonts via expo-font.** Don't ship system-font-only screens; load
531
+ the design's typography via \`useFonts\` and gate the splash screen
532
+ on load.
533
+ - **Persistence via AsyncStorage.** Anything you cache client-side
534
+ (theme choice, last-viewed-item, dismissed banners) goes in
535
+ AsyncStorage. Never sprinkle direct file I/O.
536
+ - **Theme system.** A single \`theme.ts\` exports light + dark token
537
+ maps; consume via a \`useTheme()\` hook. The verification gate
538
+ toggles light ↔ dark and screenshots; if any screen has hardcoded
539
+ colors that don't flip, the gate fails.
540
+ - **Circuit-break on second failure.** If two consecutive Amba API
541
+ calls fail with the same error, stop retrying and surface a clean
542
+ empty-state to the user. Don't loop forever; don't crash. The web
543
+ CORS issue (above) is the most likely trigger.
544
+ - **Deterministic offline fallback.** When \`fetch\` fails (airplane
545
+ mode, network drop), the app renders **deterministic** placeholder
546
+ content — same content per \`userId + day\` — never random. Real data
547
+ swaps in when the network returns.
548
+ - **Three-platform bundle gate.** \`expo export --platform web\`,
549
+ \`expo export --platform ios\`, and \`expo export --platform android\`
550
+ must all succeed. If any one fails, the build fails. No
551
+ "shipped iOS-only, web is broken" — the rule is parity.
552
+ - **Don't name a tab \`settings.tsx\`.** Use \`account.tsx\` or
553
+ \`preferences.tsx\` instead. Expo Router's static web export generates
554
+ \`settings.html\` correctly but does not resolve direct URL navigation
555
+ to \`/settings\` — the client-side router shows an unmatched-route
556
+ error while other tab names work fine. (Observed in dogfood; upstream
557
+ behavior, not an Amba issue.)
558
+
559
+ ## Verification gate
560
+
561
+ Before declaring the build done, run every check in this list. Any
562
+ failure means the build is not done — fix and re-run.
563
+
564
+ \`\`\`bash
565
+ # Type-check
566
+ pnpm tsc --noEmit
567
+
568
+ # Three-platform export
569
+ pnpm expo export --platform web
570
+ pnpm expo export --platform ios
571
+ pnpm expo export --platform android
572
+ \`\`\`
573
+
574
+ Then, from inside the agent (use the Amba MCP tools):
575
+
576
+ - \`amba_analytics_get\` → at least one event tracked end-to-end
577
+ through \`Amba.events.track()\` from the app.
578
+ - \`amba_users_list\` → at least one user exists (the agent's own
579
+ anonymous signin counts).
580
+ - For every primitive the seed step created, call the matching
581
+ \`amba_*_list\` and assert non-empty:
582
+ - \`amba_configs_list\`
583
+ - \`amba_segments_list\`
584
+ - \`amba_content_list_libraries\`, \`amba_content_list_items\`,
585
+ \`amba_content_list_schedules\`
586
+ - \`amba_streaks_list\`
587
+ - \`amba_xp_rules_list\`
588
+ - \`amba_achievements_list\`
589
+ - \`amba_challenges_list\`
590
+ - \`amba_leaderboards_list\`
591
+ - \`amba_currencies_list\` (if economy seeded)
592
+ - \`amba_catalog_list\` (if catalog seeded)
593
+ - \`amba_collections_list\` + \`amba_admin_list_rows\` per collection
594
+ - \`amba_push_list_campaigns\`
595
+ - Empty list for any seeded primitive → the implementation is fake
596
+ (UI exists but never wrote to the backend). Failure.
597
+ - Manually walk every route in the browser (\`expo start --web\`),
598
+ screenshot each, and confirm:
599
+ - Light theme renders cleanly.
600
+ - Dark theme renders cleanly (toggle and re-screenshot every
601
+ route).
602
+ - Empty states render when collections are empty (fresh-install
603
+ simulation: wipe AsyncStorage, reload).
604
+ - \`amba_users_reset_sandbox\` to confirm you can recover from the MAU
605
+ cap if you blew past 50 during testing.
606
+
607
+ Skipping any primitive's seed step requires a one-line written
608
+ justification in the gaps log (next section). "We don't need
609
+ streaks" is fine; silence is not.
610
+
611
+ ## Final output
612
+
613
+ When done, write a final report to \`BUILD_REPORT.md\` in the project
614
+ root. Required sections:
615
+
616
+ - **Start timestamp** (when the agent started).
617
+ - **End timestamp** (when the verification gate last passed).
618
+ - **MCP call inventory** — every \`amba_*\` tool you invoked, with a
619
+ count. Lets a human reviewer audit "did this agent actually use
620
+ Amba for X" at a glance.
621
+ - **Primitive coverage table** — one row per primitive from the
622
+ Feature → Amba primitive map. Mark each ✅ (used), ⚠️ (used with
623
+ caveats — explain), or ⏭ (skipped — justify in one line).
624
+ - **Gaps log** — every primitive you skipped, every feature you
625
+ couldn't fit cleanly to an Amba primitive, every workaround. One
626
+ line per gap, no marketing language.
627
+ - **\`seed-report.json\`** — machine-readable seed summary:
628
+ \`{ "primitive": "<name>", "created": <count>, "listed": <count> }\`
629
+ for every primitive. The \`listed\` count comes from the
630
+ \`amba_*_list\` call in the verification gate. \`created ===
631
+ listed\` for every row is the success condition.
632
+
633
+ If \`BUILD_REPORT.md\` is missing any required section, or
634
+ \`seed-report.json\` is missing, the build is not done.
635
+ `;
636
+ /** Canonical URI for the MCP resource. */
637
+ const EXPO_BUILD_PROMPT_URI = "amba://prompts/expo-build";
638
+ /** Canonical MIME type for the prompt body. */
639
+ const EXPO_BUILD_PROMPT_MIME = "text/markdown";
640
+ //#endregion
641
+ export { AMBA_SETUP_GUIDE_MD as a, AMBA_SETUP_GUIDE_BODY_VERSION as i, EXPO_BUILD_PROMPT_MIME as n, AMBA_SETUP_GUIDE_MIME as o, EXPO_BUILD_PROMPT_URI as r, AMBA_SETUP_GUIDE_URI as s, EXPO_BUILD_PROMPT_MD as t };
package/dist/index.d.ts CHANGED
@@ -16,6 +16,10 @@
16
16
  */
17
17
  import type { McpServer } from '@modelcontextprotocol/sdk/server/mcp.js';
18
18
  import { ApiClient } from './api-client.js';
19
+ export { registerAllResources } from './resources/index.js';
20
+ export { EXPO_BUILD_PROMPT_MD, EXPO_BUILD_PROMPT_MIME, EXPO_BUILD_PROMPT_URI, AMBA_SETUP_GUIDE_MD, AMBA_SETUP_GUIDE_MIME, AMBA_SETUP_GUIDE_URI, AMBA_SETUP_GUIDE_BODY_VERSION, AMBA_SETUP_IDENTITY_MD, AMBA_SETUP_IDENTITY_MIME, AMBA_SETUP_IDENTITY_URI, AMBA_SETUP_ENGAGEMENT_MD, AMBA_SETUP_ENGAGEMENT_MIME, AMBA_SETUP_ENGAGEMENT_URI, AMBA_SETUP_GAMIFICATION_MD, AMBA_SETUP_GAMIFICATION_MIME, AMBA_SETUP_GAMIFICATION_URI, AMBA_SETUP_ECONOMY_MD, AMBA_SETUP_ECONOMY_MIME, AMBA_SETUP_ECONOMY_URI, AMBA_SETUP_SOCIAL_MD, AMBA_SETUP_SOCIAL_MIME, AMBA_SETUP_SOCIAL_URI, AMBA_SETUP_INFRASTRUCTURE_MD, AMBA_SETUP_INFRASTRUCTURE_MIME, AMBA_SETUP_INFRASTRUCTURE_URI, AMBA_SETUP_SUB_RESOURCES, } from './resources/index.js';
21
+ export { CATEGORY_META, CATEGORY_ORDER, TOOL_CATEGORY, getToolCategory } from './categories.js';
22
+ export type { AmbaCategory } from './categories.js';
19
23
  /**
20
24
  * Register every Amba MCP tool group against the given server, using the
21
25
  * given API client. A single `McpServer` instance should only have this