They're flowcharts β visual maps of how our advisory machine actually runs, step by step. Drawn with a tool called Mermaid, but the tool doesn't matter β what matters is the picture: boxes are steps, arrows are what moves things forward, diamonds are yes/no decisions, and notes off to the side flag who owns a step or what's not built yet.
What they show: the real path things take β a founder going from first call β free pack β signing β ongoing cadence; an investor intro moving from draft β copy-edit β approval β sent; how data flows from the CRM into the site.
Why they exist: so the whole team shares one picture of how the process works β where the handoffs are, who owns each step, where the gaps are.
How to read one: start at the top (or the ● start dot) and follow the arrows. Labels on arrows are the condition; notes on the side flag ownership / "not built yet."
Reviewing: does this match how it actually works in your head? Flag anything wrong, missing, or out of order.
The full founder journey from inbound triage through the free-pack trigger, kickoff, the six-week delivery cycle, and the three-week context refresh that keeps profiles current.
flowchart TD
IB["Inbound Lead Founder reaches out"]
TRIAGE["Inbound Triage sop-inbound-triage 4-tier classification"]
IB --> TRIAGE
TRIAGE -->|"Tier A: pre-rev SaaS"| GOOD["Good Fit Schedule intro call"]
TRIAGE -->|"Tier B: pre-rev high-capex"| MAYBE["Conditional Fit Assess further"]
TRIAGE -->|"Tier C/D: post-rev / advice-only"| PASS["Pass / Redirect Scripted response"]
GOOD --> INTRO_CALL["Intro Call 1st transcript Trigger: founder-profiler + initial meeting-ingestor run"]
MAYBE --> INTRO_CALL
INTRO_CALL -->|"profile created"| FP4["founder-profiler run founders.json updated assets/profiles.json"]
FP4 --> FREE["Free Pack Delivery 2 LinkedIn posts 1 IR newsletter draft no investor intros yet"]
FREE --> DECISION{"Founder Signs?"}
DECISION -->|"No"| NURTURE["Nurture / Archive profile retained"]
DECISION -->|"Yes"| KICKOFF_CALL["Kickoff Call 2nd transcript Trigger: full system kickoff"]
KICKOFF_CALL --> ONBOARD["Onboard Set ICPs + investor prefs Matching run Context established"]
ONBOARD --> WK1["Week 1-2 2 LI posts published Matching underway Context refresh if needed"]
WK1 --> WK3["Week 3 Context Refresh Check-in call or async Profile updates if needed"]
WK3 --> WK4["Week 4-5 2 LI posts/wk continues 1 investor intro ~wk 4 IR newsletter drafted"]
WK4 --> WK5["Week 5-6 IR newsletter finalized + Canva PDF Distributed to investor network"]
WK5 --> WK6_END["End of Cycle 1 Weekly check-in Cycle review"]
WK6_END --> REFRESH["Every 3 Weeks Context-Refresh Interview TFG-driven 15-30 min recorded"]
REFRESH --> NEXT_CYCLE["Next 6-Week Cycle 6 intros Β· 12 LI posts Β· 1 newsletter"]
NEXT_CYCLE --> REFRESH
style TRIAGE fill:#1A1F2A,stroke:#46546F,color:#E8E6E0
style FREE fill:#1F1A0A,stroke:#B5651D,color:#E8E6E0
style KICKOFF_CALL fill:#15252A,stroke:#2E6E5E,color:#E8E6E0
style NEXT_CYCLE fill:#15252A,stroke:#2E6E5E,color:#E8E6E0
style REFRESH fill:#1A1F2A,stroke:#46546F,color:#E8E6E0
style PASS fill:#201015,stroke:#8B92A0,color:#E8E6E0
Free pack spec (2 LI + 1 IR newsletter) from the task brief β not explicitly in sops.json but consistent with sop-six-week-cycle. Kickoff as 2nd transcript and 1st transcript as intro call from task brief and sop-meeting-ingestor. 3-week refresh cadence from task brief; the six-week cycle contains two such refreshes internally.
Shows where data originates, how it flows through profiling and matching, how content is generated, and how the D1 app store and human "faucet" gate every outbound action.
flowchart TD
subgraph SOURCES["Source Layer"]
TR["Client Transcripts Client meeting Transcripts/"]
FJ["founders.json source-of-truth profiles"]
IJ["investors.json source-of-truth profiles"]
GD["Google Drive Deck Β· PDF Β· Meeting notes"]
DB_AEP["AEP Prod Postgres read-only (Alex β backlog)"]
end
subgraph INGEST["Ingest + Profile Layer (Tim's Machine β Faucet)"]
MI["meeting-ingestor skill 14-step extraction JSON + Markdown output"]
FP["founder-profiler skill 5-dim profile founders.json"]
IP["investor-profiler skill 3-dim profile investors.json"]
end
subgraph MATCH["Match Layer (Tim's Machine β Faucet)"]
FM["founder-matcher skill Additive scoring Β· no hard gates matches.json direction=investors_for_founder"]
IM["investor-matcher skill Additive scoring Β· no hard gates matches.json direction=founders_for_investor"]
MJ["assets/matches.json ranked pairs Β· flags Β· scores"]
end
subgraph CONTENT["Content-Generation Skills (Tim's Machine β Faucet)"]
LI["linkedin-post-writer skill 3 posts per run Β· founder voice Capital-One framing"]
IRN["ir-newsletter-writer skill offering_breakdown β Β§1 Β§2 Β§3 350-550 words"]
IID["investor-intro-drafter skill Ben-voiced Β· 3-stage package loads ben-voice skill"]
BV["ben-voice skill voice corpus Β· quote bank loaded by IID"]
end
subgraph STATIC["Static Review Layer (Cloudflare Pages + Access)"]
MR["match-review.html 3-button feedback UI founder Γ investor pairs"]
SL["investor-library.html founder-library.html"]
MB["investor-match-board.html"]
end
subgraph D1["D1 App Store (Cloudflare D1)"]
MF_T["match_feedback verdict + reviewer + ts"]
REQ["requests status: queuedβcopy_edit βfinalβapproved"]
APR["approvals stage: copy_edit | final"]
MRK["marks kanban stage Β· stamps"]
AUD["audit immutable log"]
USR["app_users role cache"]
end
subgraph HUMANS["Human Review Gate"]
COPY["Copy-Edit Refael (content) Saviour / Cullen"]
FINAL["Final Approval Ben"]
end
subgraph DELIVER["Deliverables"]
LI_OUT["LinkedIn Posts Google Doc β Founder"]
IRN_OUT["IR Newsletter Canva PDF β Investor Network"]
INTRO_OUT["3-Stage Intro Package Google Drive β Ben sends"]
end
TR -->|"transcript"| MI
GD -->|"deck / notes"| FP
GD -->|"meeting notes"| IP
DB_AEP -.->|"future: metrics"| FM
DB_AEP -.->|"future: metrics"| IM
MI -->|"outputs_meetings JSON"| FP
MI -->|"offering_breakdown"| IRN
FJ --> FM
FJ --> IM
IJ --> FM
IJ --> IM
FP -->|"updates"| FJ
IP -->|"updates"| IJ
FM --> MJ
IM --> MJ
MJ -->|"pairs + scores"| MR
MJ -->|"ranked"| MB
FJ --> SL
IJ --> SL
MR -->|"POST /api/feedback"| MF_T
MR -->|"POST /api/requests (good verdict)"| REQ
REQ -->|"queued"| IID
IID -->|"loads"| BV
IID -->|"draft"| COPY
MI -->|"transcript + profile"| LI
MI -->|"offering_breakdown"| IRN
COPY -->|"approved"| FINAL
COPY -->|"changes_requested"| APR
FINAL -->|"approved"| APR
APR -->|"status=approved"| REQ
FINAL -->|"approved"| LI_OUT
FINAL -->|"approved"| IRN_OUT
FINAL -->|"approved"| INTRO_OUT
REQ --> MRK
MF_T --> AUD
REQ --> AUD
APR --> AUD
USR -.->|"role check"| COPY
USR -.->|"role check"| FINAL
style SOURCES fill:#1E222A,stroke:#343A44,color:#E8E6E0
style INGEST fill:#15252A,stroke:#2E6E5E,color:#E8E6E0
style MATCH fill:#1A1F2A,stroke:#46546F,color:#E8E6E0
style CONTENT fill:#1F1A0A,stroke:#B5651D,color:#E8E6E0
style STATIC fill:#1A1F2A,stroke:#46546F,color:#E8E6E0
style D1 fill:#1C1A26,stroke:#6B5EA8,color:#E8E6E0
style HUMANS fill:#1A2012,stroke:#2E6E5E,color:#E8E6E0
style DELIVER fill:#201A0A,stroke:#B5651D,color:#E8E6E0
Inferred: AEP Prod path is backlogged (ROADMAP.md obj 9). "Tim's machine β faucet" label is from ARCHITECTURE doc rule 4: agents run only on Tim's approval, humans drain. Static review pages are behind Cloudflare Access per ARCHITECTURE phase 1.
Three parallel content tracks seeded from the same cycle interview. All three converge at the two-gate review before delivery. The IR newsletter feeds LinkedIn themes each cycle (per sop-ir-newsletter).
flowchart TD
INT["Cycle Interview TFG-driven 15-30 min recorded sop-six-week-cycle step 1"]
TR["Transcript Client meeting Transcripts/"]
MI2["meeting-ingestor 14-step pipeline JSON schema v1"]
INT --> TR --> MI2
MI2 --> JS["outputs_meetings JSON exec_summary Β· action_items promises Β· offering_breakdown"]
JS --> OB["offering_breakdown object fresh_wins Β· needs_besides_capital current_raise Β· linkedin_guidance investor_intro_feedback + 4 more"]
OB -->|"fresh_wins β Β§1"| IRN2["ir-newsletter-writer Β§1 Good News Β§2 Asks Β§3 Fundraise 350-550 words Β· founder voice"]
OB -->|"needs_besides_capital β Β§2"| IRN2
OB -->|"current_raise β Β§3"| IRN2
OB -->|"linkedin_guidance"| LI2["linkedin-post-writer 3 posts per run Β· founder voice Capital-One framing >75% people focus"]
MI2 -->|"voice from transcript"| LI2
MI2 -->|"voice profile"| LI2
MJ2["matches.json approved founderΓinvestor pair"]
MJ2 -->|"pair + rationale"| IID2["investor-intro-drafter + ben-voice corpus Stage 1: SMS permission text Stage 2: investor-only email Stage 3: 3-way intro email"]
IRN2 --> IRND["IR Newsletter Draft Google Doc"]
LI2 --> LID["LinkedIn Post Drafts 3 posts Β· Google Doc"]
IID2 --> INTROD["Intro Package Draft All 3 stages Google Drive staged doc"]
IRND --> CE2["Copy-Edit Gate Refael / Saviour / Cullen"]
LID --> CE2
INTROD --> CE2
CE2 -->|"approved"| FA2["Final Approval Ben Wiggins"]
CE2 -->|"changes"| IRND
CE2 -->|"changes"| LID
CE2 -->|"changes"| INTROD
FA2 -->|"approved"| IRN_DEL["IR Newsletter Canva PDF β Investor Network ~week 5 of cycle"]
FA2 -->|"approved"| LI_DEL["LinkedIn Posts 2Γ/week Mon-Thu β Founder publishes"]
FA2 -->|"approved"| INT_DEL["Intro Package Ben sends Stage 1 β 2 β 3 Refael weekly follow-up"]
IRN_DEL -.->|"themes feed"| LI2
style INT fill:#1F1A0A,stroke:#B5651D,color:#E8E6E0
style MI2 fill:#15252A,stroke:#2E6E5E,color:#E8E6E0
style JS fill:#1A1F2A,stroke:#46546F,color:#E8E6E0
style OB fill:#1A1F2A,stroke:#46546F,color:#E8E6E0
style IRN2 fill:#1F1A0A,stroke:#B5651D,color:#E8E6E0
style LI2 fill:#1F1A0A,stroke:#B5651D,color:#E8E6E0
style IID2 fill:#1F1A0A,stroke:#B5651D,color:#E8E6E0
style CE2 fill:#1A2012,stroke:#2E6E5E,color:#E8E6E0
style FA2 fill:#1A2012,stroke:#2E6E5E,color:#E8E6E0
IR newsletter at ~week 5 is from sop-six-week-cycle. Canva PDF step from sop-ir-newsletter step 8. Voice profile capture from ROADMAP.md obj 5 addendum. IRN feeds LI themes confirmed in sop-ir-newsletter note field.
Every draft flows through two named gates before delivery. Match feedback from the review UI either queues an intro request or rotates investor assignments. D1 tables record every state transition immutably.
stateDiagram-v2
[*] --> Drafted : Skill generates draft (LI / IRN / Intro)
Drafted --> CopyEdit : Actor queues request β status=queued, D1 requests row created
state CopyEdit {
direction LR
[*] --> CopyReview : Refael or Saviour/Cullen opens review page
CopyReview --> CopyApproved : decision=approved, D1 approvals row (copy_edit)
CopyReview --> CopyChanges : decision=changes, D1 approvals row
CopyChanges --> [*] : Draft revised and re-queued
}
CopyEdit --> FinalReview : status=final after copy approval
state FinalReview {
direction LR
[*] --> BenReviews : Ben Wiggins, final_approver role
BenReviews --> BenApproved : decision=approved, D1 approvals row (final)
BenReviews --> BenChanges : decision=changes
BenChanges --> [*] : Returns to copy-edit
}
FinalReview --> Approved : status=approved, D1 requests updated
Approved --> Delivered : Human drains faucet (Ben sends intro or Refael posts LI)
Delivered --> [*]
Roles (from _lib.js): copy-edit = Refael & Saviour (Saviour leads LinkedIn/marketing); final approval = Ben (final_approver); editors = Cullen, Adam, Abhijay. Idle-escalation (3-day rule, Cullen owns) is flagged in the SOPs but not yet wired to the app store.
Tracks an investor from discovery through profiling, the QC must-not gate (Cullen), Ben's three-button verdict, the full three-stage intro sequence, and how responses feed back into the matching engine.
flowchart TD
SRC["Investor Sourced Ben network Β· team referral founders supply own lists"]
PROFILED["investor-profiler run 3 dims: Thesis Β· Advisory fit Β· Intangibles Mandatory gap flagging Gap β investors.json marked"]
WARM_CHECK{"Warm contact? (founder's own list)"}
COLD_PATH["Cold Match Path sop-intro-sequence"]
WARM_PATH["Warm Follow-Up Path sop-warm-followup CRM flag required first"]
SRC --> PROFILED
PROFILED --> MATCH_RUN["Matching Run Additive scoring Β· no hard gates Red-lines = dismissable flags only matches.json updated"]
MATCH_RUN --> QC["QC Gate Cullen Martin β gate owner sop-rec-qc Must-not check before any intro"]
QC -->|"fails must-not"| ROTATE["Rotate Investor Next ranked match surfaced D1 marks updated"]
QC -->|"passes"| MR_UI["Match Review UI match-review.html Ben reviews pair"]
MR_UI -->|"Ben votes"| VERDICT{"Ben Verdict 3 buttons"}
VERDICT -->|"Good match queues intro"| QUEUE["D1 requests row status = queued workflow = investor-intro-drafter"]
VERDICT -->|"Worth a shot saves only"| SAVED["D1 match_feedback verdict = worth_a_shot No intro queued yet"]
VERDICT -->|"Not a good fit rotates"| ROTATE
QUEUE --> IID3["investor-intro-drafter skill Ben-voiced 3-stage package Google Drive staged doc"]
IID3 --> CE3["Copy-Edit Gate Refael / Cullen"]
CE3 --> FA3["Final Gate Ben Wiggins"]
FA3 -->|"status = approved"| STAGE1["Stage 1 β SMS Permission Hey first-name I have one you'll like β may I send details?"]
WARM_CHECK -->|"Yes"| WARM_PATH
WARM_CHECK -->|"No"| COLD_PATH
COLD_PATH --> STAGE1
STAGE1 -->|"investor replies yes"| STAGE2["Stage 2 β Investor-Only Email Rationale Β· fit Β· TFG advisory value Refael drafts Β· Ben / BWI sends"]
STAGE2 -->|"investor interested"| STAGE3["Stage 3 β 3-Way Intro Email Ben-voiced Β· SHORT/WARM default cc benwigginsinvestor@ Signed 'Ben Wiggins Investment Team'"]
STAGE3 --> WEEKLY["Weekly Follow-Up Thread Refael owns until investor responds private note to founder"]
WEEKLY --> RESPONSE{"Investor Response?"}
RESPONSE -->|"Interested"| MEETING["Investor x Founder Meeting Pitch call Team may attend case-by-case sop-pitch-attendance"]
RESPONSE -->|"No response / pass"| ARCHIVE["Archive intro thread BWI Zero Inbox rule feedback logged"]
RESPONSE -->|"Feedback on format/fit"| FB_LOOP["Feedback Loop investor_intro_feedback bucket updates investor profile matching weights refined"]
MEETING --> FB_LOOP
ARCHIVE --> FB_LOOP
FB_LOOP --> PROFILED
style PROFILED fill:#15252A,stroke:#2E6E5E,color:#E8E6E0
style QC fill:#201015,stroke:#8B92A0,color:#E8E6E0
style MR_UI fill:#1A1F2A,stroke:#46546F,color:#E8E6E0
style QUEUE fill:#1F1A0A,stroke:#B5651D,color:#E8E6E0
style IID3 fill:#1F1A0A,stroke:#B5651D,color:#E8E6E0
style STAGE1 fill:#15252A,stroke:#2E6E5E,color:#E8E6E0
style STAGE2 fill:#15252A,stroke:#2E6E5E,color:#E8E6E0
style STAGE3 fill:#15252A,stroke:#2E6E5E,color:#E8E6E0
style FB_LOOP fill:#1A1F2A,stroke:#46546F,color:#E8E6E0
style ROTATE fill:#201015,stroke:#8B92A0,color:#E8E6E0
Stage 1 SMS text verbatim from investor-intro-drafter/references/intro-flow.md. "Worth a shot saves only / no intro queued" inferred from match-review.html comment "saves only" vs good which calls /api/requests. QC gate owner Cullen from sop-rec-qc. Warm-contact suppression from sop-warm-followup.
6App-Store Data Model (D1 / SQLite)
Five D1 tables + role cache β from db/schema.sql verbatim
The Cloudflare D1 app store is the only team-writable datastore. Source-of-truth JSON files (founders.json, investors.json, matches.json) are never written by the web tier β only by Tim's local faucet agents.
erDiagram
match_feedback {
INTEGER id PK
TEXT founder
TEXT investor
TEXT verdict "good | worth_a_shot | not_a_fit"
TEXT context
TEXT reviewer_email FK
TEXT ts
}
requests {
INTEGER id PK
TEXT ts
TEXT actor_email FK
TEXT workflow "investor-intro-drafter etc"
TEXT founder
TEXT investor
TEXT status "queued | copy_edit | final | approved | dismissed"
TEXT notes
}
approvals {
INTEGER id PK
INTEGER request_id FK
TEXT stage "copy_edit | final"
TEXT decision "approved | changes"
TEXT actor_email FK
TEXT note
TEXT ts
}
marks {
INTEGER id PK
TEXT entity_kind
TEXT entity_id
TEXT key
TEXT value
TEXT actor_email FK
TEXT updated_at
}
audit {
INTEGER id PK
TEXT ts
TEXT actor_email FK
TEXT action
TEXT detail
}
app_users {
TEXT email PK
TEXT role "owner | final_approver | copy_editor | editor | viewer"
TEXT display_name
}
requests ||--o{ approvals : "has review gates"
app_users ||--o{ match_feedback : "reviewer_email"
app_users ||--o{ requests : "actor_email"
app_users ||--o{ approvals : "actor_email"
app_users ||--o{ marks : "actor_email"
app_users ||--o{ audit : "actor_email"
requests ||--o{ audit : "action logged"
match_feedback ||--o{ audit : "action logged"
Schema is read verbatim from db/schema.sql. Seed data: Tim (owner), Ben (final_approver), Refael (copy_editor), Adam/Cullen/Abhijay (editor). The audit β requests and audit β match_feedback FK relationships are logical (audit.detail references IDs) β not enforced by FK constraint in SQLite. marks UNIQUE(entity_kind, entity_id, key) enforces one value per slot.