new file mode 100644
index 0000000..9650230
@@ -0,0 +1,365 @@
+---
+visibility: public
+---
+
+<!DOCTYPE html>
+<html lang="en">
+<head>
+<meta charset="UTF-8">
+<title>Essential Infrastructure — Meeting Whiteboard · 2026-04-20</title>
+<style>
+ :root {
+ --bg: #f5f2ea;
+ --card: #ffffff;
+ --ink: #1a1a1a;
+ --muted: #5c5c5c;
+ --line: #dcd6c8;
+ --tier1: #065f46;
+ --tier2: #b45309;
+ --tier3: #6b21a8;
+ --box-fill: #fefcf7;
+ --flow-line: #1a1a1a;
+ }
+ * { box-sizing: border-box; }
+ body {
+ margin: 0;
+ padding: 24px 32px 48px;
+ font-family: -apple-system, BlinkMacSystemFont, "Helvetica Neue", sans-serif;
+ background: var(--bg);
+ background-image: radial-gradient(circle, #00000010 1px, transparent 1px);
+ background-size: 22px 22px;
+ color: var(--ink);
+ line-height: 1.45;
+ }
+ header {
+ display: flex;
+ justify-content: space-between;
+ align-items: baseline;
+ border-bottom: 2px solid var(--ink);
+ padding-bottom: 12px;
+ margin-bottom: 24px;
+ }
+ h1 { margin: 0; font-size: 26px; letter-spacing: -0.5px; }
+ .meta { color: var(--muted); font-size: 13px; }
+ a { color: #1e40af; }
+
+ .intro {
+ background: #fff;
+ border: 1px solid var(--line);
+ border-left: 4px solid var(--tier1);
+ border-radius: 8px;
+ padding: 14px 18px;
+ margin-bottom: 28px;
+ font-size: 14px;
+ }
+ .intro strong { color: var(--tier1); }
+
+ .section-title {
+ font-size: 11px;
+ font-weight: 700;
+ letter-spacing: 2px;
+ text-transform: uppercase;
+ color: var(--muted);
+ margin: 36px 0 10px;
+ }
+
+ /* DATA FLOW DIAGRAM */
+ .diagram {
+ background: #fff;
+ border: 1px solid var(--line);
+ border-radius: 10px;
+ padding: 24px;
+ margin-bottom: 28px;
+ box-shadow: 2px 3px 0 rgba(0,0,0,0.04);
+ }
+ .flow {
+ display: grid;
+ grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
+ gap: 12px;
+ align-items: center;
+ margin: 16px 0;
+ position: relative;
+ }
+ .flow-box {
+ background: var(--box-fill);
+ border: 2px solid var(--flow-line);
+ border-radius: 6px;
+ padding: 14px 10px;
+ text-align: center;
+ font-size: 13px;
+ font-weight: 600;
+ position: relative;
+ }
+ .flow-box .lbl {
+ display: block;
+ font-size: 10px;
+ font-weight: 700;
+ letter-spacing: 1px;
+ text-transform: uppercase;
+ color: var(--muted);
+ margin-bottom: 4px;
+ }
+ .arrow {
+ font-size: 24px;
+ color: var(--flow-line);
+ text-align: center;
+ font-weight: 700;
+ }
+ .flow-row-2 {
+ display: grid;
+ grid-template-columns: 1fr 1fr 1fr 1fr 1fr;
+ gap: 12px;
+ align-items: center;
+ margin-top: 12px;
+ }
+ .flow-caption {
+ font-size: 11px;
+ color: var(--muted);
+ text-align: center;
+ font-style: italic;
+ margin-top: 6px;
+ }
+
+ /* COMPONENT CARDS */
+ .tiers {
+ display: grid;
+ grid-template-columns: 1.2fr 1fr 1fr;
+ gap: 18px;
+ }
+ .tier {
+ background: var(--card);
+ border: 1px solid var(--line);
+ border-radius: 10px;
+ padding: 18px 20px;
+ box-shadow: 2px 3px 0 rgba(0,0,0,0.04);
+ }
+ .tier.t1 { border-top: 4px solid var(--tier1); }
+ .tier.t2 { border-top: 4px solid var(--tier2); }
+ .tier.t3 { border-top: 4px solid var(--tier3); }
+
+ .tier h2 { margin: 0 0 4px 0; font-size: 17px; }
+ .tier .sub { font-size: 12px; color: var(--muted); margin-bottom: 12px; font-style: italic; }
+
+ .component {
+ margin: 12px 0;
+ padding: 10px 12px;
+ border-left: 3px solid var(--line);
+ background: #fafaf5;
+ border-radius: 0 6px 6px 0;
+ }
+ .component.stated { background: #ecfdf5; border-left-color: var(--tier1); }
+ .component .name {
+ font-weight: 700;
+ font-size: 13.5px;
+ margin-bottom: 3px;
+ }
+ .component .name .badge {
+ display: inline-block;
+ font-size: 9px;
+ font-weight: 700;
+ letter-spacing: 0.5px;
+ padding: 1px 6px;
+ border-radius: 3px;
+ background: #d1fae5;
+ color: var(--tier1);
+ margin-left: 6px;
+ vertical-align: middle;
+ }
+ .component .desc { font-size: 12.5px; color: var(--ink); }
+ .component .why { font-size: 11.5px; color: var(--muted); margin-top: 4px; font-style: italic; }
+
+ .key-question {
+ background: #fef3c7;
+ border-radius: 6px;
+ padding: 10px 12px;
+ font-size: 12.5px;
+ margin-top: 8px;
+ }
+ .key-question strong { color: #92400e; }
+
+ footer {
+ margin-top: 32px;
+ padding-top: 12px;
+ border-top: 1px dashed var(--line);
+ font-size: 11px;
+ color: var(--muted);
+ text-align: center;
+ }
+
+ @media (max-width: 1000px) {
+ .flow, .flow-row-2 { grid-template-columns: 1fr; }
+ .arrow { transform: rotate(90deg); }
+ .tiers { grid-template-columns: 1fr; }
+ }
+</style>
+</head>
+<body>
+
+<header>
+ <div>
+ <h1>Essential Infrastructure</h1>
+ <div class="meta">What the minimum loop actually needs · <a href="meeting-dashboard-2026-04-20.html">← back to dashboard</a></div>
+ </div>
+ <div class="meta">2026-04-20</div>
+</header>
+
+<div class="intro">
+ Jacob's stated essentials: <strong>(1) a bot on a sync/async channel</strong> and <strong>(2) an LLM wiki (graph or markdown)</strong>. Those are right but incomplete. The minimum working loop needs <strong>five</strong> components — without any one of them, the system breaks.
+</div>
+
+<!-- DATA FLOW DIAGRAM -->
+<div class="section-title">The Minimum Loop</div>
+<div class="diagram">
+
+ <div class="flow-caption" style="text-align:left; margin-bottom:8px;">Write path: raw content → structured memory</div>
+ <div class="flow">
+ <div class="flow-box"><span class="lbl">Source</span>Meeting audio<br/>Chat messages<br/>Docs</div>
+ <div class="arrow">→</div>
+ <div class="flow-box"><span class="lbl">Capture</span>Transcription<br/>Ingestion<br/>(Otter / Granola / API)</div>
+ <div class="arrow">→</div>
+ <div class="flow-box"><span class="lbl">Writer Agent</span>Extract · Route · Merge<br/>into wiki pages</div>
+ </div>
+
+ <div style="text-align:center; margin: 16px 0;">
+ <div style="display: inline-block; border: 2px dashed var(--flow-line); border-radius: 8px; padding: 12px 28px; background: #fff3bf; font-weight: 700; font-size: 14px;">
+ <span style="font-size: 10px; letter-spacing: 1px; color: var(--muted); display: block; margin-bottom: 2px;">PERSISTENT MEMORY</span>
+ LLM Wiki (Noos graph / Karpathy markdown)
+ </div>
+ </div>
+
+ <div class="flow-caption" style="text-align:left; margin: 16px 0 8px;">Read path: current context → right memory surfaced back</div>
+ <div class="flow">
+ <div class="flow-box"><span class="lbl">Interaction Surface</span>Bot (Slack/iMessage)<br/>Outliner UI<br/>Ambient display</div>
+ <div class="arrow">←</div>
+ <div class="flow-box"><span class="lbl">Retriever</span>Context-aware<br/>semantic + graph lookup</div>
+ <div class="arrow">←</div>
+ <div class="flow-box"><span class="lbl">Wiki</span>(same wiki<br/>as above)</div>
+ </div>
+
+ <div class="flow-caption">Every product track reuses this same loop. The differences are <em>which interaction surface</em> and <em>what input source</em>.</div>
+</div>
+
+<!-- COMPONENT TIERS -->
+<div class="section-title">Components by Tier</div>
+<div class="tiers">
+
+ <!-- TIER 1 -->
+ <section class="tier t1">
+ <h2>Tier 1 — Essential</h2>
+ <div class="sub">Remove any of these and the loop breaks.</div>
+
+ <div class="component stated">
+ <div class="name">Interaction Surface <span class="badge">Jacob noted</span></div>
+ <div class="desc">Bot on sync/async channel (Slack, iMessage, WhatsApp, email). Generalizes to UI/display for tracks 3–5 (outliner, ambient display, Note Stream).</div>
+ </div>
+
+ <div class="component stated">
+ <div class="name">LLM Wiki <span class="badge">Jacob noted</span></div>
+ <div class="desc">The persistent memory. Structure-agnostic — Noos graph, Karpathy-style markdown corpus, or hybrid.</div>
+ <div class="why">Scope decision on dashboard: wiki-hub vs Noos graph. Architecturally both satisfy this slot.</div>
+ </div>
+
+ <div class="component">
+ <div class="name">Capture / Ingestion</div>
+ <div class="desc">How raw content gets in. Meeting transcription (Otter / Granola / Gemini / own) plus chat-history ingestion.</div>
+ <div class="why">This is where the "build own note app vs. integrate" fork lives. Architecturally it's <em>one slot</em>; strategically it's "do we own this layer or rent it?"</div>
+ </div>
+
+ <div class="component">
+ <div class="name">Writer Agent</div>
+ <div class="desc">Turns unstructured transcript / messages into structured wiki updates. Routes action items → task list, gripes → relationship page, vision → vision doc. Maintains consistency across pages.</div>
+ <div class="why"><strong>The hardest technical piece and the biggest moat.</strong> Not summarization — <em>routing</em> and <em>consistency</em>. Everyone can generate a summary. Almost nobody updates an evolving structured KB well.</div>
+ </div>
+
+ <div class="component">
+ <div class="name">Retriever</div>
+ <div class="desc">Context-aware lookup. Not generic RAG — knows which wiki entries are relevant to the <em>current</em> Slack thread, meeting, scheduling request, gripe moment.</div>
+ <div class="why">"Hey you didn't respond for 3 days, this is an instance of the existing gripe" requires retrieval that understands <em>this moment</em>, not just "find similar text."</div>
+ </div>
+ </section>
+
+ <!-- TIER 2 -->
+ <section class="tier t2">
+ <h2>Tier 2 — Important, Deferrable</h2>
+ <div class="sub">Not needed for v0, but you'll feel the pain fast without them.</div>
+
+ <div class="component">
+ <div class="name">Background Worker</div>
+ <div class="desc">Periodic scans for patterns: "person X hasn't responded for N days," weekly summarization, vision-doc rollup, stale-wiki-page detection.</div>
+ <div class="why">The "3-day no-response" pattern detection literally requires time-aware background scanning — it's not triggered by a user action.</div>
+ </div>
+
+ <div class="component">
+ <div class="name">Provenance / Citations</div>
+ <div class="desc">Every wiki claim links back to the source meeting / message / document that generated it.</div>
+ <div class="why">Without this, the wiki becomes un-auditable. When it's wrong (and it will be), users can't fix it because they can't find where it came from.</div>
+ </div>
+
+ <div class="component">
+ <div class="name">Versioning / Undo</div>
+ <div class="desc">Wiki will be continuously AI-written. Need diff history, rollback, and per-edit attribution (human vs agent).</div>
+ </div>
+
+ <div class="component">
+ <div class="name">Trust UX layer</div>
+ <div class="desc">Visibility rules, consent flow, expiration, correction workflow — especially for the gripes / conflicts / patterns feature.</div>
+ <div class="why"><strong>Codex's warning:</strong> the gripes feature is socially dangerous. Get this wrong → product feels creepy or politically explosive. May be the real moat, not the graph structure.</div>
+ </div>
+ </section>
+
+ <!-- TIER 3 -->
+ <section class="tier t3">
+ <h2>Tier 3 — Track-specific</h2>
+ <div class="sub">Only needed for particular product tracks.</div>
+
+ <div class="component">
+ <div class="name">Privacy / Consent Layer</div>
+ <div class="desc">Cross-privacy scoping. "Can you share your availability on this date?" → user clicks approve.</div>
+ <div class="why">Essential for <strong>Track 2 (Group Chat Bot)</strong>. Not needed for B2B team wiki where everyone already has shared context.</div>
+ </div>
+
+ <div class="component">
+ <div class="name">Agent Execution Environment</div>
+ <div class="desc">Private server running coding agents (Claude Code / Codex) that can spawn from prompts — "hey AI go build that node."</div>
+ <div class="why">Essential for <strong>Track 6 (Better GPT)</strong> and the "spawn agent per note" feature in <strong>Track 5 (Note Stream)</strong>. Not needed for the core wiki loop.</div>
+ </div>
+
+ <div class="component">
+ <div class="name">Identity / Relationship Model</div>
+ <div class="desc">Per-person pages, relationship graph, role inference. Baked into the wiki schema.</div>
+ <div class="why">Essential for the <strong>gripes/conflicts feature</strong>. If skipping that, the wiki can be person-agnostic.</div>
+ </div>
+
+ <div class="component">
+ <div class="name">Real-time Streaming</div>
+ <div class="desc">Sub-second transcription + retrieval + render pipeline.</div>
+ <div class="why">Essential only for <strong>Track 4 (Ambient Display)</strong>. The rest of the system can be batch / near-real-time.</div>
+ </div>
+ </section>
+
+</div>
+
+<div class="section-title">Open Architecture Questions</div>
+<div class="tiers" style="grid-template-columns: 1fr 1fr;">
+ <section class="tier t2">
+ <h2>The Big Forks</h2>
+ <div class="key-question"><strong>Q1.</strong> Wiki structure: Noos graph vs. markdown corpus vs. hybrid? Affects writer complexity and retrieval surface.</div>
+ <div class="key-question"><strong>Q2.</strong> Writer agent: one-shot LLM or multi-step pipeline with explicit routing rules? Quality vs. predictability tradeoff.</div>
+ <div class="key-question"><strong>Q3.</strong> Retriever: semantic embeddings, graph traversal, keyword, or hybrid? Depends on wiki structure.</div>
+ <div class="key-question"><strong>Q4.</strong> Capture: own it (custom outliner) or rent it (integrate Otter/Granola)? Strategic scope decision.</div>
+ </section>
+ <section class="tier t2">
+ <h2>What's Easy to Get Wrong</h2>
+ <div class="key-question"><strong>W1.</strong> Treating the writer as "summarization." It's not. Summarization loses structure; the writer must <em>preserve and extend</em> structure.</div>
+ <div class="key-question"><strong>W2.</strong> Treating the wiki as write-only. The retriever must be designed <em>alongside</em> the wiki schema — they're dual.</div>
+ <div class="key-question"><strong>W3.</strong> Skipping provenance. Debugging AI-generated KB rot is impossible without source links.</div>
+ <div class="key-question"><strong>W4.</strong> Shipping gripes feature without trust UX. One bad moment → product dies.</div>
+ </section>
+</div>
+
+<footer>
+ <a href="meeting-dashboard-2026-04-20.html">← back to dashboard</a> · Architecture snapshot 2026-04-20
+</footer>
+
+</body>
+</html>
\ No newline at end of file