Updated May 21, 2026 · Affirmology_DemoLaunchPlan_v2.md
Goal: Stand up affirmology.ai/demo so an investor or partner can enter their birth data, watch their report appear, listen to their personalized audio, and get the same package emailed to them. All driven by the existing Python agent in affirmology-agent/.
Scope (locked): Investor / partner demo, not public launch. No payments, no accounts, no abuse protection beyond a basic rate cap. Polish over throughput. Vibe: simple, mysterious, "you are looking at something sacred."
.env.Heavenly Circuit.mp3 for v1, every demo. Variations come later.hello@affirmology.ai, sent from GHL once the domain is verified.Pulled from the deck cover, page 2, page 3, page 4.
--bg-deep #0a2014 /* the deep emerald, near-black with green undertone */
--bg-card #112e26 /* one shade lifted, for cards and form rows */
--bg-quote #163a30 /* a touch lighter still, for callouts */
--gold #c89b3c /* primary gold for buttons and ornaments */
--gold-soft #d9b15a /* hover state and small flourishes */
--gold-glow rgba(200, 155, 60, 0.25) /* button shadows, focus rings */
--cream #faf6ee /* primary text on dark bg */
--cream-muted #cdbfa3 /* secondary text, labels, captions */
--line #1f4536 /* dividers, form borders */
Typefaces. - Cormorant Garamond (italic and semibold) for the headlines, the pull quotes, and the user's name on the results page. Google Fonts, free, weights 400, 500, 600, 700, plus italic 400 and 500. - Inter (300, 400, 500) for everything you read in paragraphs, labels, buttons. - JetBrains Mono (400) at 11px for the eyebrow tags ("✦ THE INTAKE ✦", "✦ YOUR CHART ✦"). Tracking 0.4em uppercase. Sparingly.
Ornament. The gold four-pointed star ✦ used as a section divider and a list bullet. The deck uses constellation dust in the background. We'll use a faint SVG of scattered gold points fixed behind the content at maybe 8% opacity. Sparingly, never noisy.
Tone of voice. Half-whispered. "Your chart. Your healing. Your voice." style. Never marketing speak. The intake page has at most one sentence of explanation under the title. The results page just says "Sol, your soul's song" above the player. The report speaks for itself.
affirmology.ai as a sending domain in GHL using DNS records added to Cloudflare. No mail server of our own.hello@affirmology.ai and forwards it to your real inbox.affirmology.ai/demo. Static page on Cloudflare Pages. Deep emerald background. Cormorant title "Your chart. Your healing. Your voice." in cream and gold./api/runs. Agent returns { run_id, status: "queued" } immediately and starts work in the background. The page navigates to affirmology.ai/demo/r/[run_id].Heavenly Circuit.mp3 using FFmpeg, then uploads audio plus report to R2./api/runs/[id] every 3 seconds. Progress states display in turn: "Calculating your chart" → "Hearing your themes" → "Composing your voice" → "Mixing your soul's song" → "Ready". A breathing gold star animates while waiting.delivered, the results page shows: the user's first name in italic Cormorant at top, the play button below that, the report rendered as styled HTML below the player (faded and softly blurred until play is pressed). A single quiet link sits at the very bottom: "Download the report (PDF)".hello@affirmology.ai.Path: affirmology.ai/demo (Cloudflare Pages, index.html at /demo/)
Layout: Single centered column, max width 560px, vertically centered on first load, soft scroll thereafter. Star-dust SVG fixed behind everything at 8% opacity.
Above the fold: Eyebrow "✦ AFFIRMOLOGY ✦". Title "Your chart. Your healing. Your voice." in Cormorant italic, cream. One subline in Inter at --cream-muted: "Enter the moment you arrived. Receive your soul's song."
Form fields: First name. Middle name (optional). Last name. Birth date. Birth time (24h, with "I don't know" toggle that disables the field and surfaces a small note: "Your rising sign and houses will be soft."). Time zone (browser-detected, dropdown). Birth location (text input with a geocoder autocomplete). Email.
Submit button: Full-width, gold background, deep emerald text, "Begin" in Inter 500. Hover lifts to --gold-soft.
Submit behavior: Fetch POST to /api/runs. On 200, navigate to results page. On error, inline error in cream, no popups.
Path: affirmology.ai/demo/r/[run_id]
Waiting state: Same emerald background. Breathing gold star ✦ centered, 64px. Below it, the current progress phrase in Cormorant italic, fading in and out as the phase changes. Optional: a faint percentage in JetBrains Mono at the very bottom.
Delivered state, top to bottom:
1. Eyebrow "✦ YOUR SOUL'S SONG ✦" in gold mono caps.
2. The user's name: "Sol" in Cormorant italic, large. Subtitle: "Recorded for the moment you arrived." in cream-muted.
3. The audio player. Custom-styled HTML5 audio. Gold play/pause button. Cream waveform or thin progress bar. Time codes in JetBrains Mono.
4. A thin gold divider with a centered ✦.
5. The report rendered as styled HTML. Headlines in Cormorant. Body in Inter. Same emerald background. Width matches the audio player.
6. At the bottom, "Download the report (PDF)" as a quiet link in --cream-muted, underlined.
The soft gate: Section 5 starts at opacity: 0.25 with filter: blur(6px). A JavaScript listener on the audio's play event transitions it to opacity: 1; filter: blur(0) over 1.5 seconds. Nothing is hidden, just hushed until you press play.
Polling: Client polls /api/runs/[id] every 3 seconds while status is in queued, computing_chart, generating_script, recording_audio, mixing. Stops on delivered or failed.
Wraps: the existing affirmology-agent Python package.
Stack: FastAPI + uvicorn, dockerized. Background work via FastAPI's built-in BackgroundTasks for demo volume (no Redis or Celery needed).
Endpoints:
- POST /api/runs - accepts the form payload, validates, starts the background task, returns { run_id, status }. Enforces the 5-per-email-per-day cap by checking R2 manifest or a tiny SQLite file.
- GET /api/runs/{run_id} - returns current status. On delivered, also returns the rendered report markdown, the signed audio URL, the signed PDF URL, and any verification flags.
- POST /api/webhook/test/ghl - fires a test payload to the GHL webhook for setup verification.
Background pipeline: compute_chart (existing) → generate_reports (existing) → verify_report (existing) → generate_script (Phase 2 work, partially stubbed today; v1 uses the existing Affirmology_Script_v5.md template filled with the chart values) → synthesize_audio (ElevenLabs Charlotte, new) → mix_audio (FFmpeg, voice on top, Heavenly Circuit.mp3 ducked to -18 dB, new) → render_pdf (PDF skill, new) → upload_to_r2 (new) → notify_ghl (new) → mark delivered.
Deploy: Add Dockerfile, railway.toml, FastAPI module under src/affirmology/api.py. Push to a new GitHub repo, connect Railway, railway up. Environment variables: ANTHROPIC_API_KEY, ELEVENLABS_API_KEY, ELEVENLABS_VOICE_ID (Charlotte), R2_ACCESS_KEY, R2_SECRET_KEY, R2_BUCKET, R2_ENDPOINT, GHL_WEBHOOK_URL, DEMO_RATE_LIMIT=5.
This is the most manual piece. Two separate setups inside GHL.
4a. Verify affirmology.ai as a sending domain (one-time).
1. In GHL: Settings → Email Services → Dedicated Domain → "Add Domain" → enter affirmology.ai.
2. GHL gives you about 4 DNS records (a TXT for SPF, two CNAMEs for DKIM, one TXT for DMARC).
3. In Cloudflare DNS for affirmology.ai, add each record exactly as shown. Set proxy status to "DNS only" (gray cloud), not "Proxied".
4. Back in GHL, click "Verify". Usually green within 5 minutes, sometimes up to an hour.
5. Add hello@affirmology.ai as a "From" identity inside Settings → My Staff or Settings → Sender Domains.
4b. Inbound webhook + email automation.
1. Workflows → Create Workflow → Trigger: "Inbound Webhook".
2. GHL generates a webhook URL. Copy it into the agent's GHL_WEBHOOK_URL env var.
3. Sample payload (paste this into the GHL test sender so it can map fields):
json
{
"first_name": "Sol",
"last_name": "Parker",
"email": "sol@example.com",
"birth_date": "1990-03-21",
"birth_time": "14:32",
"birth_location": "Buenos Aires, Argentina",
"audio_url": "https://r2.../audio.mp3?signed",
"report_url": "https://r2.../report.pdf?signed",
"run_id": "run_abc123"
}
4. Add action: Create/Update Contact. Map email to email, first_name and last_name accordingly. Map audio_url, report_url, birth_date, birth_time, birth_location, run_id to custom fields (create them if they don't exist).
5. Add action: Send Email. From: hello@affirmology.ai. Subject: "Your Affirmology, ready". Body template (cream + gold, dark emerald): a Cormorant headline, a paragraph in Inter, two gold buttons (Listen and Download), one quiet line of closing copy. I will deliver the HTML email template alongside the code.
4c. Inbound forwarding.
1. In Cloudflare: Email → Email Routing → enable for affirmology.ai.
2. Add a route: hello@affirmology.ai → forwards to jeff@jeffparker.love.
3. Verify your destination address in Cloudflare's confirmation email.
Bucket: affirmology-demo-renders
Objects per run: runs/{run_id}/audio.mp3, runs/{run_id}/report.pdf, runs/{run_id}/report.md, runs/{run_id}/chart.json.
Access: Signed URLs valid for 30 days, generated server-side in the agent. No public bucket.
Setup: Create the bucket in the Cloudflare R2 dashboard. Generate an R2 API token with Object Read & Write scope. Hand me the access key, secret, endpoint, and bucket name.
compute_chart and generate_reports exposed through /api/runs. Audio still placeholder. Proves the deploy story. About one focused session.affirmology.ai/demo. About 30 minutes once everything else is green.Total time to a live demo: 4 to 6 focused sessions.
You (manual setup, one-time):
- Railway account. Connect to a GitHub repo for the agent.
- Cloudflare Pages project. Point at affirmology.ai/demo.
- Cloudflare R2 bucket and API token.
- ElevenLabs Creator-tier account. Charlotte voice ID is already in .env.
- GHL: verify affirmology.ai as a sending domain (Component 4a), build the inbound webhook workflow (Component 4b).
- Cloudflare Email Routing: forward hello@affirmology.ai to your real inbox (Component 4c).
- Hand me the resulting URLs and tokens so I can fill the agent's .env.
I build:
- Intake page HTML, CSS, JS. Self-contained, no framework. Matches the deck.
- Results page HTML, CSS, JS. Polling, soft gate, custom audio player, inline report.
- FastAPI wrapper around the existing Python agent.
- Dockerfile, railway.toml, deploy config.
- ElevenLabs synthesis function (Charlotte).
- FFmpeg mix function (Heavenly Circuit at -18 dB under voice).
- PDF render function (using the PDF skill).
- R2 upload helper and signed-URL generator.
- GHL webhook POST in the agent.
- GHL HTML email template, deck-styled.
- A README that ties all the deploy steps together.
Before I can finish components 3 to 5, I need:
- Railway public URL (after you deploy the first stub).
- R2 access key, secret, endpoint, bucket name.
- GHL inbound webhook URL.
- Confirmation that affirmology.ai is verified as a sending domain in GHL.
I can build components 1 and 2 (the HTML pages) without any of the above. They're mocked against a stub. So the next session can start there.
Build the intake page and the results page in the deck's visual language, mocked against a fake agent. Drop both files in AFFIRMOLOGY/CLAUDE OUTPUTS/Affirmology/ for review. You open them in your browser, submit the form, watch the simulated 30-second render, see the report fade in under the play button when you press play. That is the experience locked.
Greenlight that and I'll build it next.