Now I have the complete picture. Here are the 3 highest-impact items:

---

#1 — Wire Brief Email Delivery (The Broken Last Mile)

What: `generateDailyBriefs()` generates content and stores it to DB — then stops. No email is ever sent. Members configured `email_notify=1` and chose a delivery time, but those preferences are dead. After generation, loop through members with `email_notify=1` for each generated brief, group by member, render a digest email, and send via Resend.

Platform: iCharles Daily Todd (`brief-generator.ts` + `email.ts`)

Why now: This is the core promise of the product. Members explicitly opted in to receive personalized AI briefs. They're getting nothing. Every day this is broken is a day the platform's marquee feature produces zero user-visible value. Fix this before acquiring more members — you're already churning silently.

Complexity: Medium

First step today: In `brief-generator.ts`, after the generation loop, add a second pass: query `member_brief_items` where `email_notify=1`, group today's generated briefs by `member_id`, call `sendEmail()` once per member with a compiled digest. Reuse the existing email infrastructure from `email.ts`.

---

#2 — Render Brief Content as Markdown HTML

What: Line 394 of `daily-todd.ts` does `escapeHtml(b.content)` with `white-space:pre-wrap`. Claude always outputs markdown (headers, bullets, bold). Add a `markdownToHtml()` function — either a tiny inline parser or `marked` via bun — and render it as real HTML in the Past Briefs viewer. Apply the same in the email template.

Platform: iCharles Daily Todd (past-briefs page + future email digest)

Why now: Right now a brief looks like:

```

Top Stories


Item 1: Something important happened...
```

That's raw text in a `pre-wrap` div. It looks broken. The AI quality is probably good — but perception is everything for retention. This is a 30-minute fix with outsized perceived quality improvement. Every member who opens Past Briefs right now sees an unpolished product.

Complexity: Small

First step today: Add a 40-line `markdownToHtml(text: string): string` utility that handles `##/###` headers, `bold`, `italic`, `- ` bullets, and blank-line paragraphs. Swap it in for `escapeHtml` on line 394.

---

#3 — Inject Member Profile Into Brief Prompts (Real Personalization)

What: The `brief_catalog` has one static `ai_prompt` per item, shared identically across all members. The onboarding flow collects interests (Technology, Faith, Entrepreneurship, etc.) and a bio — but `brief-generator.ts` only fetches `member_id, site_id, item_key, email`. Query the member's profile and interests at generation time and prepend them to every prompt as: `"Member context: Name is X, interests include Y and Z, bio: [bio]. Generate the brief with these interests in mind."` This makes the same brief category generate completely different content for a triathlete vs a pastor.

Platform: Daily Todd + Onboarding (closes the loop between the two systems)

Why now: This is the differentiation moat. Generic AI newsletters are free everywhere. A brief that's actually tuned to your interests is something members will pay for and tell others about. The infrastructure is all there — onboarding stores interests, briefs store content — they just don't talk to each other. This is the feature that justifies the subscription price.

Complexity: Medium

First step today: In `brief-generator.ts`, modify the `memberItems` query to also join `member_profiles` (or wherever onboarding saves interests/bio) and pull `interests` and `bio` per member. Then prepend a 2-3 line personalization block to `prompt` before calling `runAI()`. No schema changes needed if onboarding already writes to an existing table.

---

Priority order: #2 this afternoon (30 min, removes a broken-looking experience), #1 this week (missing core value delivery), #3 next sprint (retention differentiator once delivery is working).