PRD: Thesis Tab

Table of Contents
PRD: Thesis Tab

PRD: Thesis Tab

Fundraising OS Feature Specification. August 2026.

1. Purpose

The Thesis tab is the founder's fundraising pitch, distilled into a single page that serves two audiences. The founder reads it to prepare for meetings, rehearse the verbal pitch, and keep the narrative sharp. An investor who receives a deep link reads it as a self-contained memo that answers "what is this company, how much are they raising, and why."

The page must feel like a document, not a dashboard. One page, one thesis, with structured depth available on demand.

2. Page Layout

The thesis page has three vertical zones, rendered top to bottom in a single scrollable view.

Zone 1: The Pitch (always visible)

The verbal thesis narrative. This is the part the founder reads out loud. It answers the question "what is your company and why should I care?" in the founder's own voice.

The pitch is always visible. It never hides behind a tab or disclosure. Scrolling past it is the only way to move beyond it.

Zone 2: Section Pills (sticky navigation)

A horizontal row of pill buttons that segment the structured detail of the thesis. The pills stick to the top of the section area as the user scrolls, so navigation is always available.

Default pills (when all distilled fields are present)

The Ask · Why Now · Use of Funds · Why Us · Anchor Plan · Full Memo · Sources

Behavior:

Zone 3: Section Content

The content panel below the pills. Only one section is visible at a time, switched by the pills. No animation, instant swap via hidden attribute.

3. Data Model

Table: thesis_docs

ColumnTypePurpose
idTEXT PKRandom hex id
founder_idTEXT FKReferences founders(id)
titleTEXTDisplay title (default: "Fundraising thesis")
sourceTEXTProvenance line (e.g. "Prepared by Boo")
summaryTEXTThe pitch narrative (Zone 1 body)
sectionsJSONBFull research memo: [{heading, body}]
distilledJSONBStructured fields for pills
sourcesJSONBSource documents: [{label, url?}]
raw_markdownTEXTComplete thesis as markdown (export format)
created_atTIMESTAMPTZInsertion time

Distilled JSONB schema

{
  "one_liner": "string",        // The elevator pitch (Zone 1 callout)
  "ask": "string",              // The Ask pill content
  "why_now": "string",          // Why Now pill content
  "use_of_funds": ["string"],   // Use of Funds pill content (list items)
  "why_us": "string",           // Why Us pill content
  "anchors": ["string"]         // Anchor Plan pill content (list items)
}

All fields are optional. Pills render only for present, non-empty fields. The summary column holds the pitch narrative (Zone 1) separately from the distilled card fields.

Query

SELECT * FROM thesis_docs
WHERE founder_id = $1
ORDER BY created_at DESC
LIMIT 1

The most recent thesis doc wins. No versioning in the current model. Each POST /api/thesis inserts a new row. Historical versions are queryable but the UI always shows the latest.

4. API

POST /api/thesis

Bearer-authenticated (Boo API token). Inserts a new thesis_docs row.

{
  "founder_slug": "boolab",             // required
  "title": "Fundraising Thesis",        // default: "Fundraising thesis"
  "source": "Prepared by Boo",          // nullable
  "summary": "...",                     // The pitch narrative (Zone 1)
  "sections": [                         // Full memo sections
    { "heading": "...", "body": "..." }
  ],
  "distilled": {                        // Structured pill fields
    "one_liner": "...",
    "ask": "...",
    "why_now": "...",
    "use_of_funds": ["..."],
    "why_us": "...",
    "anchors": ["..."]
  },
  "sources": [                          // Source documents
    { "label": "Deck", "url": "https://..." }
  ],
  "raw_markdown": "..."                 // Complete thesis as markdown
}

Returns { "ok": true }.

5. Rendering Rules

Pill construction order

  1. The Ask (from distilled.ask), rendered as paragraphs.
  2. Why Now (from distilled.why_now), rendered as paragraphs.
  3. Use of Funds (from distilled.use_of_funds), rendered as a list. Uses fos-thesis-list-rich for extra padding per item.
  4. Why Us (from distilled.why_us), rendered as paragraphs.
  5. Anchor Plan (from distilled.anchors), rendered as a list. Only shown when anchors are non-empty.
  6. Full Memo (from sections[]), rendered as a sequence of heading + body blocks. Each section body supports markdown-style bold (**text**) and bullet lists. Only shown when sections exist.
  7. Sources (from sources[]), rendered as a linked list. Only shown when sources exist.

Empty state

When getLatestThesis() returns null, the page renders a centered empty state with the prompt "No thesis yet" and a copy-paste command: @Boo write my fundraising thesis memo.

Fallback rendering

When distilled is empty but summary or sections exist (legacy data), the pitch section shows the summary and the sections render in a single scrollable view without pills. This preserves backward compatibility with thesis docs created before the pills redesign.

6. CSS Architecture

ClassElementPurpose
fos-thesisContainerMax-width 780px wrapper
fos-thesis-pitchZone 1Pitch narrative wrapper, margin-bottom 28px
fos-thesis-onelinerCalloutAccent-bordered card for the elevator pitch
fos-thesis-narrativeBodyContainer for pitch paragraphs
fos-thesis-body-pParagraph0.95rem, ink-soft, 1.7 line-height, 12px margin
fos-thesis-pillsNav barFlex row, horizontal scroll, sticky, z-index 10
fos-thesis-pillButtonPill button, rounded 20px, 0.78rem
fos-thesis-pill.is-activeActive pillAccent background, white text
fos-thesis-section-panelSectionContent panel, hidden/shown by JS
fos-thesis-listListNo bullets, border-separated items
fos-thesis-list-richList variantExtra padding for multi-line items
fos-thesis-memo-sectionFull memo sectionHeading + body, 28px margin-bottom
fos-thesis-memo-headingSection heading1rem, bold, ink color

Mobile (max-width 768px)

7. Client-Side Behavior

File: src/client/thesis.ts, imported in app.ts.

Initialization

  1. Find .fos-thesis-pills. If absent, exit (empty state or no pills).
  2. Collect all [data-thesis-pill] buttons and [data-thesis-section] panels.
  3. On pill click, set is-active on the clicked pill, set hidden on all non-matching panels, remove hidden from the matching panel.
  4. Auto-scroll the active pill into view on mobile (smooth, center-aligned).
  5. Activate the first pill on page load.

Data attributes

AttributeElementValue
data-thesis-pillButtonSection key (e.g. "ask", "why-now", "full-memo")
data-thesis-sectionPanel divMatching section key

8. Content Generation (Boo's Role)

When a founder says "write my thesis" or Boo detects an empty thesis tab, Boo generates the thesis through a multi-phase process.

Phase 1: Research

Parallel web research across five streams: VC landscape (what top firms are writing about the category), competitor deep dive (who competes and their funding), comparable rounds (real deal data at similar stage/size), founder story (verifiable track record), and market timing evidence (spending data, adoption rates, macro signals).

Phase 2: Compose

Write the full investor-grade thesis using the founder's narrated input as the soul and the research as the foundation. The thesis must read as a pitch the founder can say verbatim, not a research report. Follow the content-writing skill rules: no em dashes, no contractions, no generic AI vocabulary, every claim backed by a specific fact.

Phase 3: Review

Adversarial review from a skeptical VC partner perspective. The reviewer checks whether the memo would earn a meeting, flags gaps (missing revenue numbers, unaddressed risks, weak competitive positioning), and suggests specific rewrites. The thesis is revised based on this feedback before posting.

Phase 4: Post

Structure the thesis into the API payload: summary for the pitch narrative, distilled for the structured fields, sections for the full memo, and raw_markdown for export. Post via POST /api/thesis.

Content rules

9. Future Considerations

Chart, full screen