Imported from x21ai/PurpleLifeAi (
AGENTS.md). Install upstream withnpx skills add x21ai/PurpleLifeAi. Copyright stays with the author.
Learned User Preferences
- Local previews: Cursor browser only. Always open websites/pages in Cursor Simple Browser (or
cursor-ide-browserMCP when available). Never open Chrome/Safari/openCLI unless the user explicitly asks for an external browser. - When implementing an attached plan, do not edit the plan file; mark pre-created to-dos in_progress and complete all without recreating them.
- On session start read
docs/HANDOFF.md,docs/DECISIONS.md,docs/OPEN-ISSUES.md, anddocs/LEARNINGS.mdbefore changing anything (.cursor/rules/compounding-memory.mdc). After every completed task, append a log entry todocs/HANDOFF.mdand refresh its Current snapshot before claiming done; also syncCURSOR_HANDOFF.md(extended ops), relevantdocs/runbooks,.cursor/rules/when conventions change,AGENTS.md/mem/for durable decisions, and paste-ready Lovable prompts for UI-only follow-ups. Mandatory percompounding-memory.mdc,00-handoff.mdc, andpost-task-documentation.mdc; never leave important context only in chat. When switching machines, commit and push all in-progress work and refresh handoff before stopping so the next machine cangit pulland resume. - When migration artifacts are missing from the repo, provide copy-paste Lovable prompts the user can run there.
- Always fully clean git working tree before handoff or close: run
./scripts/clean-workspace-junk.sh(PID locks,test-results/, macOS* 2.*duplicates); never say "clean aside from local junk" or leave untracked artifacts. Rule:.cursor/rules/clean-working-tree.mdc. - At cutover, keep existing Oura/Whoop OAuth apps and only add workers.dev redirect URIs. Migration cutover priority: preserve user UUIDs, public data, and storage; password reset is OK; password hashes are not required.
- No hardcoded or fake health metrics presented as real; for HIPAA-ready go-live use empty states and connect prompts when real data is absent, not sample numbers or a demo badge.
- Agent-owned operations: run all Doppler, Supabase Management API, wrangler deploy, git, bun gates, local web preview (
bun run devat http://localhost:8080), iOS CLI (scripts/native-ios-build.sh,bun run ios:device-build,bun run ios:local-signing,bun run ios:check-asc,bun run ios:testflightperdocs/testflight-setup.md; build scripts usexcode-select -pthen fallback to/Applications/Xcode.app,/Applications/Xcode-beta.app, or~/Downloads/Xcode-beta.app; Xcode Command Line Tools alone cannot build iOS, run simulators, or replace full Xcode), plist edits, andcap syncyourself viaxcodebuildCLI, never ask the operator to open Xcode GUI. Rule:.cursor/rules/no-manual-operator-work.mdc. Check Doppler before asking for keys: native iOS secrets (PURPLE_LIFE_*inx21/prd, seemem/doppler-purple-life.md; oldpurple-lifeproject deleted 2026-07-14), Worker deploy and www Cloudflare smoke inx21/prd_cloudflare; before destructive Doppler changes, verify all iOS script paths againstx21/prdonly (ios:check-asc,ios:check-luciq, JWT, local-signing); operator only when blocked by App Store Xcode install (Xcode.appdownload), Xcode license acceptance, or missing Doppler secrets (APNs/FCM keys). - Ship work on feature branches and open PRs;
ghCLI is not installed locally and no GitHub token is available, so PRs are opened via the GitHub branch URL and commits go to the active feature branch (e.g.feat/real-vitals-and-integrations). - Verify both functionality and visuals before claiming done: real end-to-end checks (webhook POST, query the live DB) plus screenshots across viewports (
tests/e2e/visual-layout.spec.ts, output undertest-results/visual/), not assertions from code alone. Never ask the operator to test a local URL until the agent has curl + Cursor browser MCP verification on that exact URL (.cursor/rules/proof-of-work.mdc). For multi-issue debug, native, design, or ship sessions, use multitask mode with parallel subagents (often 8-10) rather than serial one-offs. Expect work 100% complete and verified before demo handoff; partial "agents still running" is insufficient. 2026-07-04 max-agent fleet: ~15+ subagents on disjointflutter/scopes (fail-open data screens, burger drawer, TestFlight prep, browser QA); parent merges and runs gates before claiming done. - Hold UI to an Apple-grade bar: the user repeatedly asks "how would Apple do it" and rejects over-wide, empty, or edge-drifting/full-bleed layouts; keep content in a centered, width-capped column with aligned controls, never
inset-x-0full width. Liquid-glass design passes (iOS 26/27 tokens insrc/styles.css,mem/design/liquid-glass-tokens.md, Figma Apple kit when available) are look-and-feel only: frosted nav/sheets,.glass-pressfeedback, 44pt touch targets, no data removal or functionality changes. Flutter shell burger menu: top-right hamburger must open a right-edgeScaffold.endDrawer(RTL slide, flush under top bar, glass panel ~280–336px), not a SnackBar, left drawer, or floating popover; routes Account, Settings, Tools, Care, Sign out. - Only operate on Purple's own project and accounts; never write to any other Supabase project or account, even when credentials grant access.
- Live-user safety gate: before shipping
lovable/redesignchanges, require a read-only audit confirming no destructive SQL/migrations/seeds, manual deploy only, backup note, and explicit approval for any new auth/onboarding write path or sync behavior changes. - Whole-app redesign: Lovable works on GitHub branch
lovable/redesign; Cursor gatekeepsmain(baseline7086ffa, sync runbookdocs/SYNC-AND-RELEASE.md, gatekeeperdocs/LOVABLE-REDESIGN-WORKFLOW.md,docs/LOVABLE-DESIGNER-RULES.md). The user coordinates and tells Cursor when Lovable has updates; never blame the user for Lovable platform or bot sync commits. Cursor reviews, runs all quality gates (includingcheck:supabase-types), merges tomainwhen clean, and asks before live deploy. After merge, keepmainandlovable/redesignat the same commit; user expects git committed, pushed, and prod/Lovable/local in sync. Only Cursor regeneratestypes.ts, migrations, and RLS/security fixes; paste-ready Lovable prompts for UI-only. Lovable must not edittypes.tsor use Try to fix on build/security errors. Manual deploy only during redesign. - Capacitor interim retired (operator 2026-07-04): TestFlight builds 1–9 were Capacitor WebView; all future iOS uploads are Flutter native only (
bun run ios:flutter-testflight). Capacitor scripts (ios:testflight:capacitor) remain for rollback reference, not the default path. Seedocs/FLUTTER-TESTFLIGHT-CUTOVER.md,mem/flutter-lovable-workflow.md. - Flutter + Lovable split: Lovable owns web design on
lovable/redesign(TanStack); Cursor ownsflutter/,design/tokens.json, migrations, and ports signed-in app screens after each merge. Lovable must not editflutter/ordesign/tokens.json.design/tokens.jsonbridges web CSS (src/styles.css) to Dart (flutter/lib/design/). Runbooks:docs/LOVABLE-FLUTTER-SYNC.md,mem/flutter-lovable-workflow.md. - TestFlight observability (permanent): Before and after every
bun run ios:testflight, triage all ASC beta feedback (ios:check-tf-feedback) and all Luciq crashes/bugs (MCP Flutter - Purple - Beta). Fix P0 or log indocs/OPEN-ISSUES.md; do not claim build ready with open crash regressions. Rule:.cursor/rules/flutter-testflight-observability.mdc; screenshot feedback gaps:mem/observability/testflight-beta-feedback.md.
Learned Workspace Facts
- Supabase projects: OLD ref
lzuodgpqseijhhyzgfky(Lovable Cloud; DB password andSUPABASE_SERVICE_ROLE_KEYnot accessible to the owner, see repo.env/PROJECT_KNOWLEDGE.md); NEW refxxnzmfzsjplrutrgbzxy(Purple Life, us-east-2, user-owned), schema and data import complete (5,751 rows, 13 auth users), production DNS cutover complete (www.purplelife.organd apex route to Cloudflare Workerpurplelife), edge functions: oura-sync, journal-processor, journal-extract, ai-orchestrator, risk-forecaster, med-dose-action; deploy withbunx supabase@latest functions deploy <name> --project-ref xxnzmfzsjplrutrgbzxy(globalsupabaseCLI may SIGKILL; Management API zip deploy is unreliable); setsupabase/config.tomlproject_idto the new ref (in-repo, not downloaded from the dashboard). Use Session pooler (port 5432) for psql DDL and\copy; Transaction pooler (6543) breaks large DDL; CLIdb query --linkedmay 403, use dashboard SQL editor or Management APIPOST /v1/projects/{ref}/database/query. Lovable preview must use NEW viadocs/LOVABLE-ENV-PARITY.md(VITE_SUPABASE_URL=https://auth.purplelife.org, matching publishable key and project id); OLD schema mismatch breaks Lovable preview (Path B: point Lovable at NEW, do not patch OLD). Only Cursor regeneratessrc/integrations/supabase/types.tsfrom NEW;check:supabase-types(prebuild + CI) rejects truncated types. Lovable design syncs on branchlovable/redesign; Cursor gatekeepsmain. - Migration and Lovable redesign pitfalls (complete):
purple-migration/on GitHub; auth via Admin API +auth-users.json(import-auth.mjs, UUID preservation); runresign-journal-media.mjsif journal media still on old host; marketing heroes use localsrc/assets/*.jpgvia vite imagetools, not Lovable.asset.jsonor/__l5e/CDN (404 outside preview;check-unique-route-images.mjsguards); Apple/Google OAuth uses@lovable.dev/cloud-auth-jsonly on Lovable preview hosts (isLovablePreviewHost()insrc/lib/lovable-preview.ts), prod/local usesupabase.auth.signInWithOAuth. - CI quality gates:
check:live-datarunscheck-no-test-data.mjs(code plus optional--dbscan; resolves service role from DopplerSERVICE_ROLE_KEY/SUPABASE_SECRET_KEY) andcheck-no-fake-vitals.mjs(blocks invented health metrics on app screens);check:lovable-authguardslovable.authbehindisLovablePreviewHost; CI runs on pushes tomainandlovable/redesignplus all PRs; full sync/release runbook indocs/SYNC-AND-RELEASE.md. - Apple Health on web is push-only via Health Auto Export webhook
/api/public/hooks/apple-health?token=<secret>(apple_health_tokens, not Sign in with Apple OAuth); browsers cannot use HealthKit. Native iOS/Android:ios/andandroid/committed; Capacitor 8 iOS uses Swift Package Manager (ios/App/CapApp-SPM/Package.swift, no Podfile/CocoaPods);webDiriscapacitor-shell/(minimalindex.html; TanStack Start dist has no root HTML; fixes TestFlight launch crash when shell was missing); buildApp.xcodeprojviascripts/native-ios-build.sh(simulator) orbun run ios:device-build(device, auto-installs and launches when USB connected); local signing viabun run ios:local-signing(scripts/ios-write-local-signing.sh, Dopplerx21/prdPURPLE_LIFE_DEVELOPMENT_TEAM, checked beforecursor-cloudflare); App Store Connect app Purple for Life (6787298041, bundleorg.purplelife.app) must be created in the ASC browser first (API returns 403 on create); TestFlight upload viabun run ios:testflightafterbun run ios:check-ascconfirmsPURPLE_LIFE_APP_STORE_CONNECT_*in Dopplerx21/prd(docs/testflight-setup.md); ASC live build 1.0 (28) VALID 2026-07-13 (Founding Team, internal + external beta);scripts/native-ios-testflight.shpasses ASC API key toxcodebuild(no Xcode Apple ID login). Luciq crash reporting (formerly Instabug): SPMluciqai/luciq-ios-sdk, init inAppDelegate.swift, SDK tokenPURPLE_LIFE_LUCIQ_APP_TOKENin Dopplerx21/prd. Capacitor shell (capacitor.config.ts, bridge insrc/lib/native/*) loads production (https://www.purplelife.org) so web deploy updates UI instantly;isNativeApp()/useNativeIos()defer until the Capacitor bridge injects on remote WebViews before choosing native HealthKit vs webhook UI. Store release only for native project/plugin/permission changes (docs/native-app-setup.md,mem/native-app-healthkit.md). Native HealthKit/Health Connect read via@capgo/capacitor-healthintobiometrics(source='apple_health'/health_connect) through authenticated/api/health/native-sync; iOS auth must omitvo2MaxfromAUTH_READ_TYPES(Capgo enum rejects it and breaks all Health calls); connect usesisCoreAuthorized(partial grants OK); UI "Last synced" usesapple_health_tokens.last_sync_at, not vitals timestamps; native connect gates on device authorization, not prior accountbiometricsrows from webhook/HAE/import;native_push_tokensmigration applied on live DB. Local med reminders work natively; remote push needs APNs/FCM secrets in Doppler/Worker. - Doppler: native iOS/TestFlight/Luciq in
x21/prd(PURPLE_LIFE_*,scripts/doppler-run-purple-life.sh,mem/doppler-purple-life.md; oldpurple-lifeproject deleted 2026-07-14); PurpleLife Worker deploy (build:prod,deploy:staging:ploy,deploy:www-ploy:dry-run) and Mac www smokebun run test:www-cloudflare-datausex21/prd_cloudflare(notprd, and notcursor-cloudflare/prd_cloudlfare); Flutter dart-define scripts and prod Playwright e2e still namecursor-cloudflare/prd_cloudlfare;VITE_*forbuild:prodcome fromx21/prd_cloudflare(noNEW_*prefix; migration import complete); separate Cloudflare tokensCLOUDFLARE_API_TOKEN(Workers deploy) andCLOUDFLARE_DNS(zone DNS edit);CLOUDFLARE_ACCOUNT_IDis eigital (08e766e92db74bc7ef14c6b5c86bddf0), not POS (c7f99ecba0ace852de43684ec8a44612); override account ID on deploy if Doppler still has POS; map DopplerRESEND_KEYto WorkerRESEND_API_KEY. - Production auth emails: Supabase Send Email hook to Worker
/api/email/auth/webhook; DopplerSUPABASE_SEND_EMAILmaps to WorkerSEND_EMAIL_HOOK_SECRET; PGMQ plus pg_cron jobprocess-email-queue(purple-migration/05-cutover/setup-email-pump.sql) pumps/api/email/queue/process; Cloudflare Worker cron/api/public/cron/email-queue-pumpruns the same pump every minute as backup; Resend sends fromnoreply@notify.purplelife.org(API key must authorize that domain). wrangler.deploy.jsoncproduction deploy needsworkers_dev: trueplus zone routes forwww.purplelife.org/*andpurplelife.org/*; Sunday cron day must be7not0(Cloudflare); usebun run build:prodbefore deploy so VITE_* is not baked from stale local.env. During redesign,.github/workflows/deploy.ymlisworkflow_dispatchonly (no push-to-main auto-deploy). Prod smoke tests run withbunx playwright test --project=desktop-1024(viewport projects: mobile-375, tablet-768, tablet-1023, desktop-1024, desktop-1440) againstE2E_BASE_URL=https://www.purplelife.orgwith E2E creds from Doppler.- Supabase custom domain
auth.purplelife.orgis live (Custom Domains add-on, ~$10/mo, must be enabled in the Supabase dashboard since the Management API cannot enable add-ons); branded Google OAuth consent requires the browser Supabase client URL (VITE_SUPABASE_URL) to behttps://auth.purplelife.orgin Dopplerx21/prd_cloudflareand GitHub deploy secrets, thenbun run build:prod, otherwise consent still shows*.supabase.co. Supabase Management API uses DopplerSUPABASE_PERSONAL_TOKEN(sbp_); data keys (sb_secret_/service role) return 401 onapi.supabase.com; custom hostname endpoint is/custom-hostname/initialize(not/initiate), add-ons at/billing/addons(PATCH),/database/queryruns DDL. Cloudflare zonepurplelife.orgid is2d21ef1d41f1d5ee52a57060fbcd4740; custom-domain DNS records must be DNS-only (not proxied), added viaCLOUDFLARE_DNS. - Wearables and AI: Oura sync is a Supabase Edge Function (
OURA_CLIENT_ID/OURA_CLIENT_SECRETas edge secrets via Management API/secrets); Whoop config/sync and AI run on the Cloudflare Worker (WHOOP_CLIENT_ID/WHOOP_CLIENT_SECRET,ANTHROPIC_API_KEYviawrangler secret bulk). AI goes throughcallAIForUser->process.env.ANTHROPIC_API_KEY, default modelclaude-sonnet-4-5(DopplerCLAUDE_AI); provider OAuth redirect URIs are registered manually in the Oura/Whoop consoles, prod callbackshttps://www.purplelife.org/oauth/{oura,whoop}/callback; daily AI narrative cached inhealth_narratives(RLS, one row/user/day), read byvitals.tsx/my-health.tsxviagetScoreSnapshot/getHealthNarrative. Shared sync model: each*_tokenstable hassync_mode(manual | interval | visit (default) | pull) plussync_interval_hours(0 for non-interval so crons skip; Oura cron is an edge function, Whoop runs viasyncAllConnectedUsers); sharedSyncModeSelect,WEARABLE_PROVIDERSregistry insrc/lib/wearable-sync.ts,useWearableAutoSync(3h throttle, visit mode), Today pull-to-refresh syncs all. Whoop can succeed while Oura fails whenoura_tokens.expires_atis past; reconnect Oura in Tools. Add a pull device: create its*_tokenstable (defaults visit/0,last_sync_at, RLS), a cron skipping interval 0, a registry entry plus trigger case, and<SyncModeSelect table=...>. - Layout and theming: app route pages center content in
mx-auto max-w-3xl px-5 sm:px-10 lg:px-16(a few pages are legitimately wider, e.g. biometricsmax-w-5xl); bottom sheets must wrap header and body in the sharedSheetColumn(mx-auto w-full max-w-xl) exported fromsrc/components/ui/sheet.tsx, since thebottomvariant is full-bleedinset-x-0by default;tests/e2e/visual-layout.spec.tsasserts the capped sheet width on desktop. Theme is class-based (.darkon<html>viasrc/lib/theme-provider.tsx, bootstrap script in__root.tsx; default appearance is dark when nopurple-themepreference is stored;useRouteThemeis a deprecated no-op); the.sheet-canvas(Account/Tools/Apple Health) and.report-canvas(Reports) surfaces are theme-aware with light defaults and.darktoken overrides insrc/styles.css(the metric drilldown.metric-canvasstays light by design), so new sheet/report surfaces must use tokens, never hardcodedtext-white/bg-white/text-[#FAFAFC]. Liquid glass utilities (.glass-surface,.glass-nav,.glass-card,.glass-press) and--glass-*tokens live insrc/styles.csspermem/design/liquid-glass-tokens.md; apply on nav and floating controls only, not full content backgrounds; respectprefers-reduced-transparencyfallbacks. - Flutter client (
flutter/, iOS/Android/web/macOS/Windows, bundleorg.purplelife.app): Phase 0-1 covers signed-in app routes only; marketing pages (/,/pricing, etc.) remain TanStack/React onwww.purplelife.org. Offline-first via Drift cache and sync queue (flutter/lib/core/offline/). Local web preview:./scripts/flutter-web-serve.shserves release build at http://localhost:8765 with--bind ::(macOS resolves localhost to IPv6 first); use Cursor browser only, not file paths or external browsers. Flutter web fixes do not ship via Capacitor TestFlight (that shell loads prod web); TestFlight and Flutter are separate tracks until Phase 5 cutover permem/flutter-lovable-workflow.md. ASC live 1.0 (28) VALID Founding Team (TF28, 2026-07-13); analyze clean, 254/254 tests after TF27 P0 fixes (Taken, refill, keyboard, score wrap, narrative). - Meds routing and drug autofill: flat-routed parent routes with child routes (e.g.
src/routes/_app/meds.tsxowningmeds.$medId,meds.history) MUST render an<Outlet/>or children silently render the parent. Dose history is editable and backfillable viagetDosesForDate/getDoseHistoryByDayinsrc/lib/meds-today.ts. Drug autofill viasrc/lib/drug-db.server.ts(openFDA NDC + RxNorm RxNav, edge-cached) withsrc/lib/med-dictionary.tsoffline fallback andsrc/components/meds/med-name-search.tsxautocomplete.
