Fundraising OS Feature Specification. August 2026.
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.
The thesis page has three vertical zones, rendered top to bottom in a single scrollable view.
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.
fos-thesis-oneliner). This is the elevator pitch.fos-thesis-body-p paragraph blocks at 0.95rem, ink-soft color, 1.7 line-height. This is the verbal version of the thesis, not a summary, not bullet points. It should sound natural when spoken aloud.The pitch is always visible. It never hides behind a tab or disclosure. Scrolling past it is the only way to move beyond it.
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.
The Ask · Why Now · Use of Funds · Why Us · Anchor Plan · Full Memo · Sources
Behavior:
is-active class).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.
thesis_docs| Column | Type | Purpose |
|---|---|---|
id | TEXT PK | Random hex id |
founder_id | TEXT FK | References founders(id) |
title | TEXT | Display title (default: "Fundraising thesis") |
source | TEXT | Provenance line (e.g. "Prepared by Boo") |
summary | TEXT | The pitch narrative (Zone 1 body) |
sections | JSONB | Full research memo: [{heading, body}] |
distilled | JSONB | Structured fields for pills |
sources | JSONB | Source documents: [{label, url?}] |
raw_markdown | TEXT | Complete thesis as markdown (export format) |
created_at | TIMESTAMPTZ | Insertion time |
{
"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.
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.
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 }.
distilled.ask), rendered as paragraphs.distilled.why_now), rendered as paragraphs.distilled.use_of_funds), rendered as a list. Uses fos-thesis-list-rich for extra padding per item.distilled.why_us), rendered as paragraphs.distilled.anchors), rendered as a list. Only shown when anchors are non-empty.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.sources[]), rendered as a linked list. Only shown when sources exist.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.
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.
| Class | Element | Purpose |
|---|---|---|
fos-thesis | Container | Max-width 780px wrapper |
fos-thesis-pitch | Zone 1 | Pitch narrative wrapper, margin-bottom 28px |
fos-thesis-oneliner | Callout | Accent-bordered card for the elevator pitch |
fos-thesis-narrative | Body | Container for pitch paragraphs |
fos-thesis-body-p | Paragraph | 0.95rem, ink-soft, 1.7 line-height, 12px margin |
fos-thesis-pills | Nav bar | Flex row, horizontal scroll, sticky, z-index 10 |
fos-thesis-pill | Button | Pill button, rounded 20px, 0.78rem |
fos-thesis-pill.is-active | Active pill | Accent background, white text |
fos-thesis-section-panel | Section | Content panel, hidden/shown by JS |
fos-thesis-list | List | No bullets, border-separated items |
fos-thesis-list-rich | List variant | Extra padding for multi-line items |
fos-thesis-memo-section | Full memo section | Heading + body, 28px margin-bottom |
fos-thesis-memo-heading | Section heading | 1rem, bold, ink color |
File: src/client/thesis.ts, imported in app.ts.
.fos-thesis-pills. If absent, exit (empty state or no pills).[data-thesis-pill] buttons and [data-thesis-section] panels.is-active on the clicked pill, set hidden on all non-matching panels, remove hidden from the matching panel.| Attribute | Element | Value |
|---|---|---|
data-thesis-pill | Button | Section key (e.g. "ask", "why-now", "full-memo") |
data-thesis-section | Panel div | Matching section key |
When a founder says "write my thesis" or Boo detects an empty thesis tab, Boo generates the thesis through a multi-phase process.
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).
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.
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.
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.
#why-now, #full-memo) so the founder can share a link that opens directly to a specific section.