Updated Jun 25, 2026 · Affirmology_AppBuild_Briefs_v1.md
Purpose: everything Claude Code needs to build, through the night, (A) the lean scale-ready backend, (B) the Atlas wrap with magic-link, and (C) the Affirmology consumer app in React Native. Jeff pastes the KICKOFF block below into a Claude Code window on the Mac to start the night; the briefs that follow hold the detail. Apple steps that need a human wait for Jeff in the morning and are listed at the end.
Decisions already locked (from the architecture decision doc): consumer app = React Native (Expo); Atlas = wrap the existing web app, magic-link login; ratings PLUS notes everywhere; oracle chat stays fun, support handled separately; Android dropped for now; bundle ids ai.affirmology.atlas and ai.affirmology.app; v1 is a data-driven TESTING SUITE (audios are records, swappable any time); build the lean backend first; beta target around July 2-3.
You are building Affirmology's iOS apps overnight. Work autonomously until you hit something
that genuinely needs Jeff, then keep going on everything else and log the blocker.
FIRST: read these in /Users/jeffreyparker/CLAUDE/AFFIRMOLOGY/
- CLAUDE.md and Affirmology_PROJECT_STATE.md (current truth; obey the hard rules)
- CLAUDE OUTPUTS/Affirmology/Affirmology_AppBuild_Briefs_v1.md (this file: Briefs A, B, C)
- CLAUDE OUTPUTS/Affirmology/Affirmology_AppArchitecture_Decision_v1.md (the why)
- CLAUDE OUTPUTS/Affirmology/Affirmology_DeliveryApp_Spec_v1.md (the product)
THEN execute in this order, committing in small steps as you go:
1. Brief A: the lean backend (consumer system of record + magic-link auth), extending the
existing affirmology-studio API. This is the long pole; do it first.
2. Brief C: the Affirmology React Native (Expo) app, lean v1. The big build. Get it running
in a simulator and talking to the backend.
3. Brief B: the Atlas Capacitor wrap with magic-link. Smaller; do it after C is moving, or
interleave when C is blocked.
HARD RULES (never break):
- DO NOT TOUCH THE LOCKED DEMO (affirmology-demo-site/server/api.py and its path). It is
byte-for-byte frozen.
- No em dashes anywhere, in code comments or copy. Brand: emerald #0a2014 / gold #c89b3c /
cream #faf6ee, Cormorant Garamond + Inter + JetBrains Mono. Sol = Soledad Gabriela Ballard.
- Every audio is chart-driven and personal; the app NEVER ships a generic audio. Audios are
data records. Style/structure shared, content never shared. Tier-walls A/B only.
- Reuse the existing engine and endpoints (/api/hermes for the oracle chat, /api/library for
the catalog, /api/feedback). Do NOT rebuild the council, the render pipeline, or charts.
- Verify before claiming done: run pytest for any engine touch; typecheck/build the RN app;
do not mark a step complete on a failing build.
DO NOT BLOCK on: Apple App Store Connect UI, Apple signing/2FA, TestFlight uploads that need
Jeff's Apple login, physical-device installs, or any secret you do not have (APNs key, Apple
API key, a DATABASE_URL you cannot provision). When you hit one, write it to
/Users/jeffreyparker/CLAUDE/AFFIRMOLOGY/CLAUDE OUTPUTS/Affirmology/MORNING-FOR-JEFF.md with the
exact thing you need, and keep building everything else.
ORACLE PHOTOS: Jeff provided the locked council head busts as hosted URLs. Download each into
affirmology-app/assets/oracles/ with the filename shown in the "Oracle photo assets" table at
the bottom of this doc, and wire each to the matching oracle in the chat UI. Use the CURRENT
locked names (note: Vedic is "Sri Agastya", NOT the older "Parashara"). For any oracle without a
photo, use a neutral placeholder circle with the oracle's initial. If a download fails, keep the
placeholder and note it in MORNING-FOR-JEFF.md.
END OF NIGHT: write a clear morning report to
CLAUDE OUTPUTS/Affirmology/OVERNIGHT-REPORT.md: what is built, what runs, how to run it,
what is in MORNING-FOR-JEFF.md, and the exact next steps. Update Affirmology_PROJECT_STATE.md.
Goal: a real, Postgres-backed system of record for consumer data and a magic-link auth, added to the EXISTING affirmology-studio API (one backend serves Studio, Atlas, and the consumer app; auth + entitlements decide who sees what). Keep the engine, render, and the studio's existing routes as-is.
Extend the affirmology-studio API (api/, FastAPI on Render) with a consumer data layer and
magic-link auth. Do not rip out the existing SQLite job/library store; ADD the new layer
alongside it.
DATA LAYER (scale-ready):
- Use SQLAlchemy with a DATABASE_URL env var. Target Postgres in production; fall back to a
local SQLite file when DATABASE_URL is unset so dev and tests run with no live DB. Keep
models Postgres-compatible (no SQLite-only types). Add Alembic (or a simple create_all for
v1) for the schema.
- Try to provision a Render Postgres instance via the Render API using RENDER_API_KEY from
affirmology-studio/.env, set DATABASE_URL as a Render env var on affirmology-studio-api, and
record what you did. If the API call needs a plan choice or anything ambiguous, DO NOT guess:
log it to MORNING-FOR-JEFF.md and proceed on the SQLite fallback so the night is not blocked.
SCHEMA (per the spec section 10; lean but real):
- person(id, email unique, name, birth_data json, chart_ref, tier, status, created_at, source)
- membership(person_id, tier, status, started_at, expires_at, custom_audio_credits,
chatbot_allowance) -- entitlements/metering present now even though beta is all free tier
- invite(email, status, invited_by, redeemed_at) -- the gate; seed jeff@jeffparker.love,
solballard@gmail.com, cjacobsandassoc@gmail.com
- auth_code(email, code_hash, token_hash, expires_at, used) -- magic-link / one-time code
- session(token, person_id, created_at, expires_at)
- structure(id, name, category, description) -- the shared audio TYPES
- audio(id, owner_person_id, structure_id, category, title, length, mp3_url, report_url,
description, source, tier_visibility, published_at) -- every audio belongs to a person;
no generic rows. This is data-driven: rows are added/swapped any time, no app release.
- category(id, name, sort, description, tier_visibility)
- event(id, person_id, type, target_id, payload json, created_at) -- append-only spine:
play_started/play_progress/play_completed/rating_given/note_left/chat_turn/vote_cast/
suggestion_made/report_viewed/report_emailed/wall_hit_custom_audio
- feedback(id, person_id, audio_id, stars, comfort_vote, note text, structured json, voice_url,
created_at) -- NOTE field is first-class (Jeff: ratings PLUS notes on everything)
- roadmap_item(id, title, description, status, created_by, created_at)
- suggestion(id, person_id, text, voice_url, linked_audio_id, status, created_at)
- vote(person_id, target_type, target_id, value, created_at) -- unique per person+target
- chat_session(id, person_id, started_at) and chat_message(id, session_id, role, oracle,
text, created_at, tags json)
- report_access(person_id, report_id, viewed_at, emailed_at)
AUTH (magic-link, used by BOTH the consumer app and Atlas):
- POST /api/auth/request {email}: if email is on the invite allowlist (or an existing person),
generate a 6-digit code + a one-time token, store hashes with a short expiry, and email both
a tappable magic link and the code via the existing api/emailer.py (Resend, from
reports@affirmology.ai). If not invited, return a neutral 200 (do not reveal allowlist).
- POST /api/auth/verify {email, code} OR GET /api/auth/magic?token=...: validate, create a
session token, return it. Sessions are bearer tokens; add a get_current_person dependency.
- Rate-limit requests per email; single-use codes; expiries. Standard care.
CONSUMER ENDPOINTS (the app calls these; reuse existing where present):
- GET /api/app/home -> greeting + continue-listening + new-since-last
- GET /api/app/library -> this person's categories + audios (data-driven; wraps /api/library)
- GET /api/app/audio/{id} -> detail + mp3_url + report availability
- POST /api/app/events -> accept a batch of events (supports offline queue sync)
- POST /api/app/feedback -> stars + comfort + NOTE + structured (writes feedback + event)
- GET/POST /api/app/roadmap and /api/app/suggestions and /api/app/vote (Shape Affirmology;
fast-follow ok if time-pressed, but stub the endpoints)
- POST /api/app/chat -> WRAP the existing /api/hermes council path with a CONSUMER GUARDRAIL
system prompt: stays in oracle character (Sophia + specialists), grounded in THIS person's
chart and A/B corpus, MUST NOT create or promise audios, limited scope, may mention features
and tiers, never exposes app internals. Log to chat_session/chat_message with derived tags.
Route obvious SUPPORT questions to a separate "Support Oracle" handling (a distinct system
prompt) so the main oracle stays fun. Return which oracle is speaking so the app can show the
right avatar.
- GET /api/app/report/{id} -> the written report as STRUCTURED DATA (JSON or clean HTML) so the
RN app renders a native reading view; reuse the report engine's content. Plus
POST /api/app/report/{id}/email -> email the PDF via the existing path.
- Entitlement checks on every endpoint via membership.tier (all beta = free tier for now).
Seed: create person rows for Jeff, Sol, Colin from known_charts.py (reuse api/people.py).
Verify: add pytest covering auth (request/verify/expiry/allowlist), an event write+read, a
feedback write with a note, and the chat guardrail (assert it refuses an audio-creation
request). Run the full suite green. Commit in small steps.
Goal: ship the existing Atlas/Studio web app as a real iOS app via Capacitor, gated by the new magic-link auth, to TestFlight internal testers (Jeff, Sol, Colin).
Wrap the existing Studio/Atlas web app (affirmology-studio/web) as an iOS app with Capacitor,
using the new magic-link auth instead of Cloudflare Access. Do not rebuild native; do not alter
the demo.
1. Confirm Node 22+, Xcode, CocoaPods on the Mac.
2. In the web project, add @capacitor/core, @capacitor/cli, @capacitor/ios. Initialize with
app name "Atlas", bundle id "ai.affirmology.atlas".
3. Load mode: for an always-online internal tool, point Capacitor server.url at the live
https://studio.affirmology.ai (remote URL) for v1 speed. (Note in code how to switch to a
bundled build later.)
4. AUTH SWITCH: make Atlas use the magic-link auth from Brief A (email -> code/link -> session)
as its gate, replacing the Cloudflare Access requirement. The Studio web app should detect it
is unauthenticated and show the magic-link sign-in. Keep Cloudflare Access available as an
optional outer layer but it is no longer the primary gate. Document the exact Cloudflare
change Jeff must make (remove/relax the Access policy on studio.affirmology.ai) in
MORNING-FOR-JEFF.md; do not change Cloudflare settings without him unless you have a verified
token and it is clearly safe.
5. Add the app icon + splash (brand emerald/gold). Add iOS platform.
6. Build in Xcode. Signing, the App Store Connect app record, the TestFlight upload, and adding
Sol + Colin as internal testers all need Jeff's Apple login/2FA: prepare everything up to the
point of the human step, then write the precise click-list to MORNING-FOR-JEFF.md.
7. Verify the wrapped app loads the Studio and the magic-link sign-in works in the iOS simulator
before declaring the build ready.
Goal: a native iOS app (Expo + React Native) that is a beautiful, offline-capable listening experience plus the scoped oracle chat, feedback, and reports. Lean cut first; the rest lands later over the air.
Build the Affirmology consumer app as a new Expo (React Native) project at
/Users/jeffreyparker/CLAUDE/AFFIRMOLOGY/affirmology-app (new folder, its own git repo). iOS
first; do not add Android. Bundle id ai.affirmology.app, name "Affirmology".
STACK:
- Expo (managed), TypeScript, expo-router (or react-navigation).
- react-native-track-player for audio: background playback (enable the iOS Audio background
mode), lock-screen controls, and OFFLINE caching/downloads. This is the core feature: audio
must keep playing while the user is in other apps and must work with no connection.
- expo-secure-store for the session token; expo-notifications for push; expo-font for the brand
fonts (Cormorant Garamond, Inter, JetBrains Mono); expo-file-system for downloaded audio +
cached catalog; expo-av only if needed alongside track-player.
- A small API client pointing at the affirmology-studio API base URL (configurable); bearer
session token from Brief A.
BRAND: emerald #0a2014 background, card #112e26, gold #c89b3c, cream #faf6ee, lines #1f4536.
Cormorant Garamond italic/600 headlines, Inter body, JetBrains Mono eyebrow tags. Calm,
cinematic, "let it land" pacing. No em dashes.
SCREENS (lean v1):
1. LOGIN: enter email -> POST /api/auth/request -> enter the 6-digit code (or tap the emailed
magic link) -> POST /api/auth/verify -> store session. Invite-gated by the backend.
2. HOME: greeting by first name, continue-listening, what is new since last visit.
3. LIBRARY: categories from /api/app/library; each audio card shows title, category, length,
one-line description, the person's state (new/in progress/listened) and their star once given.
All data-driven; whatever the backend returns is what shows.
4. PLAYER: big calm player via react-native-track-player. Ritual tap-to-begin, transport,
background + lock-screen, speed. Auto-download this person's audios + the starter set over
wifi; a downloaded-only view; offline playback; queue play/progress/complete events locally
and sync to /api/app/events on reconnect. Below the player: the description, the feedback
panel, and a link to the report. Beta users are NEVER emailed mp3s; they listen here only.
5. FEEDBACK: 1-5 stars + comfort vote + a NOTE field (notes on everything) + the structured
prompts (felt like you? listen again? share?). Reachable from every screen. Also the
listened-but-unrated nudge: surface audios with a completed play and no rating as a gentle
"how did this land?" prompt on next open and a "needs your take" row on Home.
6. CHAT (oracle): a Sophia/Hermes oracle experience via POST /api/app/chat. Show the speaking
oracle's face photo in the bubble (placeholder circle with the oracle initial until Jeff
provides the photos folder; wire a name->image map so dropping the photos in finishes it).
Stays fun and about the blueprint; cannot create audios; support questions get the separate
Support Oracle handling. This is a primary engagement + data surface.
7. REPORT VIEWER: a native in-app reading view rendering GET /api/app/report/{id} (structured
content: prose, oracle voices, mantras, chart panels) so people stay in the app and it works
offline; plus an "email me the PDF" button.
8. PROFILE: name, tier, sign out.
PUSH: register for expo-notifications; support "new audio ready" and occasional "rate this"
nudges (server-triggered). Wire the token to the backend.
DEFER to over-the-air fast-follows (stub or hide, do not block v1): the Shape Affirmology
voting/suggestions board, a polished usage dashboard, Fish-audio spoken oracle replies. Leave
clean seams so they drop in later via EAS Update.
BUILD + RUN: get it running in the iOS simulator end to end against the backend (log in, see
library, play with background + offline, chat, leave feedback with a note, read a report).
Set up EAS (eas.json) for cloud build + submit to TestFlight as EXTERNAL testers, but the
actual eas submit needs Jeff's Apple credentials / an App Store Connect API key: prepare it and
put the exact step in MORNING-FOR-JEFF.md. Typecheck and build clean before declaring done.
Commit in small steps with clear messages.
These cannot be done overnight without your Apple login and 2FA. Claude Code will prepare everything up to these and list specifics in MORNING-FOR-JEFF.md:
ai.affirmology.atlas) and Affirmology (ai.affirmology.app).DATABASE_URL where noted (one line).Realistic sequence after the night: Atlas can reach TestFlight (internal, no review) fastest; the Affirmology app follows once the backend and app are verified and the one external beta review clears. Target the founders first, then your week-out cohort.
Locked council head busts (marble-and-gold, emerald/gold/cream), generated 2026-06-18. Use the CURRENT names; "Sri Agastya" is the Vedic oracle (the older docs said "Parashara", that name is retired). Download each to the given filename. These are emerald-background hero busts; for small round UI avatars, request background-removed transparent PNGs from Jeff later if wanted (he flagged he may prefer a front-facing crop for one female oracle; easy swap later).
Consumer-chat oracles (show these first):
- sophia.png (lead synthesist + Western) -> https://d8j0ntlcm91z4.cloudfront.net/user_3F3pFGHoR8fJGcZbldgyQ5ENom4/hf_20260618_173827_f279c8ef-8d24-4b2c-99cd-ea2df6ad5c5e.png
- hermes.png (messenger / in-app router; also good for the Support Oracle) -> https://d8j0ntlcm91z4.cloudfront.net/user_3F3pFGHoR8fJGcZbldgyQ5ENom4/hf_20260618_195327_0b609b93-1a5c-46eb-a5d1-ee5d893dae77.png
- agastya.png (Vedic / Nadi sage; display name "Sri Agastya") -> https://d8j0ntlcm91z4.cloudfront.net/user_3F3pFGHoR8fJGcZbldgyQ5ENom4/hf_20260618_194137_9776591c-ebe4-4fc6-9557-8477b0f1a9e5.png
- prometheus.png (Human Design) -> https://d8j0ntlcm91z4.cloudfront.net/user_3F3pFGHoR8fJGcZbldgyQ5ENom4/hf_20260618_201920_b92285c7-dd14-4c07-a813-06c3784f0f1a.png
- athena.png (Gene Keys) -> https://d8j0ntlcm91z4.cloudfront.net/user_3F3pFGHoR8fJGcZbldgyQ5ENom4/hf_20260618_194222_5000d786-369a-4cf0-a0ac-f1ceae77b4c4.png
- pythagoras.png (Numerology) -> https://d8j0ntlcm91z4.cloudfront.net/user_3F3pFGHoR8fJGcZbldgyQ5ENom4/hf_20260618_194146_ba29dd08-1fa4-4e8b-884e-2ba61e2d1dd7.png
- chiron.png (Technique healer) -> https://d8j0ntlcm91z4.cloudfront.net/user_3F3pFGHoR8fJGcZbldgyQ5ENom4/hf_20260618_213701_9a0faaa2-1309-4ab6-940b-185020e0a9d1.png
Relationship lenses (when a member asks about a relationship):
- eros.png (attraction) -> https://d8j0ntlcm91z4.cloudfront.net/user_3F3pFGHoR8fJGcZbldgyQ5ENom4/hf_20260618_194304_91a48dd9-3d4c-4be9-9e43-c3d38c415910.png
- concordia.png (harmony) -> https://d8j0ntlcm91z4.cloudfront.net/user_3F3pFGHoR8fJGcZbldgyQ5ENom4/hf_20260618_211449_5a7b9ef2-d16d-4f3c-9ae7-2399bc775681.png
- hestia.png (hearth & belonging) -> https://d8j0ntlcm91z4.cloudfront.net/user_3F3pFGHoR8fJGcZbldgyQ5ENom4/hf_20260618_194517_b47a153c-520c-4c08-a75d-60407857d1e3.png
- gaia.png (earth & foundation) -> https://d8j0ntlcm91z4.cloudfront.net/user_3F3pFGHoR8fJGcZbldgyQ5ENom4/hf_20260618_215641_176f2987-ab2d-4ef7-86d3-47a7c334fd6d.png
Makers / listeners (optional in the consumer chat; include the files):
- orpheus.png -> https://d8j0ntlcm91z4.cloudfront.net/user_3F3pFGHoR8fJGcZbldgyQ5ENom4/hf_20260618_194148_14aeecc7-fe51-4dab-ac1f-3e5f56c69178.png
- apollo.png -> https://d8j0ntlcm91z4.cloudfront.net/user_3F3pFGHoR8fJGcZbldgyQ5ENom4/hf_20260618_194551_10234a69-4b85-4aad-abb9-e5d250eb652c.png
- hypnos.png -> https://d8j0ntlcm91z4.cloudfront.net/user_3F3pFGHoR8fJGcZbldgyQ5ENom4/hf_20260618_202239_39062581-89ea-4699-b99f-86cc1510a374.png
- echo.png -> https://d8j0ntlcm91z4.cloudfront.net/user_3F3pFGHoR8fJGcZbldgyQ5ENom4/hf_20260618_194259_97c5ef06-b0b9-4dab-886b-d1711c2760aa.png
- persephone.png -> https://d8j0ntlcm91z4.cloudfront.net/user_3F3pFGHoR8fJGcZbldgyQ5ENom4/hf_20260618_173716_f562b3d9-716f-4ccf-8b44-6d6a6be1f808.png
For ATLAS (the team app): the system itself is personified as "Atlas" with its own bust; use it as the Atlas app icon/identity if useful:
- atlas.png -> https://d8j0ntlcm91z4.cloudfront.net/user_3F3pFGHoR8fJGcZbldgyQ5ENom4/hf_20260618_215301_949ba972-8ace-4d2c-be25-1b7d13b9574d.png
Source of truth for the full set + alternates (Hermes Trismegistus/Thoth/Quetzalcoatl forms): Affirmology_OracleHeadPhotos_AppHandoff_v1.md and Affirmology_OracleTeamSheet_v2.html.