KnowledgeRefinery/presentation.html
oho 9dfb9ff684 Update all documentation for Go daemon rewrite
All docs, README, and presentation now reflect the Go daemon architecture:
Python/FastAPI/LanceDB/PyMuPDF references replaced with Go/chi/SQLite/pdftotext.
Updated test counts (97), model names (qwen3-4b-2507), app bundle structure,
installer steps, and tech stack tables.
2026-02-13 19:29:23 +01:00

1574 lines
63 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Knowledge Refinery — Presentation</title>
<style>
/* ============================================================
RESET & BASE
============================================================ */
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
:root {
--bg: #ffffff;
--bg-subtle: #f8f9fc;
--bg-muted: #f0f2f7;
--bg-card: #ffffff;
--fg: #1a1d26;
--fg-muted: #5a6072;
--fg-subtle: #8891a5;
--accent: #4f46e5;
--accent-2: #7c3aed;
--accent-3: #2563eb;
--accent-4: #0891b2;
--accent-5: #059669;
--accent-bg: #eef2ff;
--gradient: linear-gradient(135deg, #4f46e5, #7c3aed, #2563eb);
--border: #e5e7eb;
--shadow: 0 1px 3px rgba(0,0,0,0.06), 0 1px 2px rgba(0,0,0,0.04);
--shadow-lg: 0 10px 40px rgba(0,0,0,0.08);
--radius: 12px;
--radius-sm: 8px;
--radius-xs: 6px;
--font: -apple-system, BlinkMacSystemFont, "SF Pro Display", "Segoe UI", system-ui, sans-serif;
--mono: "SF Mono", "Fira Code", "JetBrains Mono", ui-monospace, monospace;
--slide-w: 100vw;
--slide-h: 100vh;
}
html { font-size: 18px; scroll-behavior: smooth; }
body {
font-family: var(--font);
color: var(--fg);
background: var(--bg);
line-height: 1.6;
-webkit-font-smoothing: antialiased;
overflow: hidden;
}
/* ============================================================
SLIDE ENGINE
============================================================ */
.deck {
width: var(--slide-w);
height: var(--slide-h);
position: relative;
overflow: hidden;
}
.slide {
position: absolute;
top: 0; left: 0;
width: 100%; height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 4rem 6rem;
opacity: 0;
transform: translateX(60px);
transition: opacity 0.5s ease, transform 0.5s ease;
pointer-events: none;
overflow-y: auto;
}
.slide.active {
opacity: 1;
transform: translateX(0);
pointer-events: auto;
}
.slide.prev {
opacity: 0;
transform: translateX(-60px);
}
/* ============================================================
NAVIGATION
============================================================ */
.nav-bar {
position: fixed;
bottom: 0;
left: 0; right: 0;
height: 56px;
background: var(--bg);
border-top: 1px solid var(--border);
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 2rem;
z-index: 100;
backdrop-filter: blur(12px);
-webkit-backdrop-filter: blur(12px);
}
.nav-bar .progress {
flex: 1;
height: 4px;
background: var(--bg-muted);
border-radius: 2px;
margin: 0 1.5rem;
overflow: hidden;
}
.nav-bar .progress-fill {
height: 100%;
background: var(--gradient);
border-radius: 2px;
transition: width 0.4s ease;
}
.nav-btn {
display: inline-flex;
align-items: center;
gap: 0.4rem;
padding: 0.5rem 1rem;
border: none;
border-radius: var(--radius-xs);
background: var(--bg-muted);
color: var(--fg);
font: inherit;
font-size: 0.85rem;
font-weight: 500;
cursor: pointer;
transition: background 0.2s, transform 0.1s;
user-select: none;
-webkit-user-select: none;
}
.nav-btn:hover { background: var(--border); }
.nav-btn:active { transform: scale(0.97); }
.nav-btn:disabled { opacity: 0.3; cursor: default; }
.slide-counter {
font-size: 0.8rem;
color: var(--fg-subtle);
font-variant-numeric: tabular-nums;
min-width: 4rem;
text-align: center;
}
/* ============================================================
TYPOGRAPHY
============================================================ */
.slide-inner { max-width: 1100px; width: 100%; }
h1 {
font-size: 3rem;
font-weight: 800;
letter-spacing: -0.03em;
line-height: 1.15;
margin-bottom: 1rem;
}
h1.gradient {
background: var(--gradient);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
h2 {
font-size: 2.2rem;
font-weight: 700;
letter-spacing: -0.02em;
line-height: 1.2;
margin-bottom: 1.5rem;
}
h3 {
font-size: 1.3rem;
font-weight: 600;
margin-bottom: 0.75rem;
}
.subtitle {
font-size: 1.3rem;
color: var(--fg-muted);
font-weight: 400;
line-height: 1.5;
max-width: 700px;
}
.lead {
font-size: 1.15rem;
color: var(--fg-muted);
line-height: 1.7;
margin-bottom: 2rem;
}
/* ============================================================
COMPONENTS
============================================================ */
.tag {
display: inline-block;
padding: 0.2rem 0.7rem;
border-radius: 999px;
font-size: 0.75rem;
font-weight: 600;
letter-spacing: 0.03em;
text-transform: uppercase;
}
.tag-accent { background: var(--accent-bg); color: var(--accent); }
.tag-green { background: #ecfdf5; color: #059669; }
.tag-amber { background: #fffbeb; color: #d97706; }
.tag-cyan { background: #ecfeff; color: #0891b2; }
.tag-rose { background: #fff1f2; color: #e11d48; }
.badge {
display: inline-flex;
align-items: center;
gap: 0.35rem;
padding: 0.35rem 0.8rem;
border-radius: var(--radius-xs);
font-size: 0.8rem;
font-weight: 500;
}
/* Card grid */
.card-grid {
display: grid;
gap: 1.25rem;
width: 100%;
}
.card-grid.cols-2 { grid-template-columns: 1fr 1fr; }
.card-grid.cols-3 { grid-template-columns: 1fr 1fr 1fr; }
.card-grid.cols-4 { grid-template-columns: 1fr 1fr 1fr 1fr; }
.card {
background: var(--bg-card);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 1.5rem;
box-shadow: var(--shadow);
transition: box-shadow 0.25s, transform 0.25s;
}
.card:hover {
box-shadow: var(--shadow-lg);
transform: translateY(-2px);
}
.card .icon {
width: 44px;
height: 44px;
border-radius: 10px;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.3rem;
margin-bottom: 0.75rem;
}
.card .icon.indigo { background: #eef2ff; color: #4f46e5; }
.card .icon.violet { background: #f5f3ff; color: #7c3aed; }
.card .icon.blue { background: #eff6ff; color: #2563eb; }
.card .icon.cyan { background: #ecfeff; color: #0891b2; }
.card .icon.emerald { background: #ecfdf5; color: #059669; }
.card .icon.amber { background: #fffbeb; color: #d97706; }
.card .icon.rose { background: #fff1f2; color: #e11d48; }
.card .icon.slate { background: #f1f5f9; color: #475569; }
.card p { font-size: 0.9rem; color: var(--fg-muted); line-height: 1.55; }
/* Code block */
.code-block {
background: #1e1e2e;
color: #cdd6f4;
border-radius: var(--radius);
padding: 1.25rem 1.5rem;
font-family: var(--mono);
font-size: 0.82rem;
line-height: 1.65;
overflow-x: auto;
white-space: pre;
box-shadow: var(--shadow-lg);
}
.code-block .comment { color: #6c7086; }
.code-block .keyword { color: #cba6f7; }
.code-block .string { color: #a6e3a1; }
.code-block .number { color: #fab387; }
.code-block .fn { color: #89b4fa; }
.code-block .var { color: #f5e0dc; }
.code-block .op { color: #89dceb; }
/* Pipeline visual */
.pipeline {
display: flex;
align-items: center;
gap: 0;
width: 100%;
margin: 2rem 0;
}
.pipeline-stage {
flex: 1;
text-align: center;
padding: 1rem 0.5rem;
position: relative;
}
.pipeline-stage .num {
width: 36px;
height: 36px;
border-radius: 50%;
display: inline-flex;
align-items: center;
justify-content: center;
font-weight: 700;
font-size: 0.85rem;
margin-bottom: 0.4rem;
color: white;
}
.pipeline-stage .label {
display: block;
font-weight: 600;
font-size: 0.85rem;
margin-bottom: 0.2rem;
}
.pipeline-stage .desc {
font-size: 0.72rem;
color: var(--fg-subtle);
line-height: 1.4;
}
.pipeline-arrow {
width: 32px;
flex-shrink: 0;
text-align: center;
color: var(--fg-subtle);
font-size: 1.2rem;
}
/* Architecture diagram */
.arch-diagram {
display: grid;
grid-template-columns: 1fr auto 1fr;
gap: 1.5rem;
align-items: stretch;
width: 100%;
margin: 1.5rem 0;
}
.arch-box {
border: 2px solid var(--border);
border-radius: var(--radius);
padding: 1.25rem;
position: relative;
}
.arch-box h4 {
font-size: 0.8rem;
text-transform: uppercase;
letter-spacing: 0.08em;
color: var(--fg-subtle);
margin-bottom: 0.75rem;
}
.arch-connector {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
color: var(--fg-subtle);
font-size: 1.5rem;
gap: 0.25rem;
}
.arch-connector .proto {
font-size: 0.65rem;
font-weight: 600;
color: var(--accent);
letter-spacing: 0.05em;
text-transform: uppercase;
}
/* Step list */
.step-list {
list-style: none;
counter-reset: steps;
}
.step-list li {
counter-increment: steps;
padding: 1rem 1rem 1rem 3.5rem;
position: relative;
border-left: 2px solid var(--border);
margin-left: 1rem;
}
.step-list li:last-child { border-left-color: transparent; }
.step-list li::before {
content: counter(steps);
position: absolute;
left: -14px;
top: 1rem;
width: 28px;
height: 28px;
border-radius: 50%;
background: var(--accent);
color: white;
font-weight: 700;
font-size: 0.8rem;
display: flex;
align-items: center;
justify-content: center;
}
.step-list li strong {
display: block;
margin-bottom: 0.25rem;
}
.step-list li p {
font-size: 0.9rem;
color: var(--fg-muted);
}
/* Table */
.data-table {
width: 100%;
border-collapse: collapse;
font-size: 0.85rem;
}
.data-table th {
text-align: left;
padding: 0.6rem 1rem;
border-bottom: 2px solid var(--border);
color: var(--fg-subtle);
font-weight: 600;
font-size: 0.75rem;
text-transform: uppercase;
letter-spacing: 0.05em;
}
.data-table td {
padding: 0.6rem 1rem;
border-bottom: 1px solid var(--bg-muted);
vertical-align: top;
}
.data-table tr:last-child td { border-bottom: none; }
.data-table code {
font-family: var(--mono);
font-size: 0.8rem;
background: var(--bg-muted);
padding: 0.1rem 0.4rem;
border-radius: 4px;
}
/* Title slide decoration */
.title-slide {
position: relative;
background: var(--bg-subtle);
}
.title-slide::before {
content: "";
position: absolute;
top: -200px; right: -200px;
width: 600px; height: 600px;
border-radius: 50%;
background: radial-gradient(circle, rgba(79,70,229,0.06) 0%, transparent 70%);
pointer-events: none;
}
.title-slide::after {
content: "";
position: absolute;
bottom: -150px; left: -150px;
width: 500px; height: 500px;
border-radius: 50%;
background: radial-gradient(circle, rgba(124,58,237,0.05) 0%, transparent 70%);
pointer-events: none;
}
/* Feature highlight */
.feature-row {
display: flex;
gap: 2rem;
align-items: flex-start;
margin-bottom: 1.5rem;
}
.feature-row .feature-icon {
width: 48px;
height: 48px;
border-radius: 12px;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.4rem;
flex-shrink: 0;
}
.feature-row .feature-text h3 {
margin-bottom: 0.3rem;
font-size: 1.1rem;
}
.feature-row .feature-text p {
font-size: 0.9rem;
color: var(--fg-muted);
line-height: 1.5;
}
/* Two-col layout */
.two-col {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 2.5rem;
width: 100%;
align-items: start;
}
/* Stats row */
.stats-row {
display: flex;
gap: 2rem;
margin: 1.5rem 0;
}
.stat {
text-align: center;
}
.stat .stat-num {
font-size: 2.5rem;
font-weight: 800;
background: var(--gradient);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
line-height: 1;
}
.stat .stat-label {
font-size: 0.8rem;
color: var(--fg-subtle);
font-weight: 500;
margin-top: 0.3rem;
}
/* Annotation example */
.annotation-example {
background: var(--bg-subtle);
border: 1px solid var(--border);
border-radius: var(--radius);
padding: 1.5rem;
font-size: 0.85rem;
}
.annotation-example .ann-field {
margin-bottom: 0.6rem;
}
.annotation-example .ann-label {
font-weight: 600;
font-size: 0.75rem;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--fg-subtle);
margin-bottom: 0.25rem;
}
.annotation-example .ann-tags {
display: flex;
flex-wrap: wrap;
gap: 0.4rem;
}
.ann-tag {
padding: 0.15rem 0.55rem;
border-radius: 999px;
font-size: 0.75rem;
font-weight: 500;
}
/* Extractor matrix */
.extractor-grid {
display: grid;
grid-template-columns: repeat(4, 1fr);
gap: 1rem;
}
.extractor-item {
background: var(--bg-subtle);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
padding: 1rem;
text-align: center;
}
.extractor-item .ext-icon {
font-size: 1.8rem;
margin-bottom: 0.4rem;
}
.extractor-item .ext-name {
font-weight: 600;
font-size: 0.85rem;
margin-bottom: 0.2rem;
}
.extractor-item .ext-types {
font-size: 0.72rem;
color: var(--fg-subtle);
}
/* Keyboard hint */
.keyboard-hint {
position: fixed;
top: 1rem;
right: 1.5rem;
font-size: 0.72rem;
color: var(--fg-subtle);
z-index: 50;
opacity: 0.6;
}
.key {
display: inline-block;
padding: 0.1rem 0.45rem;
border: 1px solid var(--border);
border-radius: 4px;
font-family: var(--mono);
font-size: 0.7rem;
background: var(--bg-subtle);
box-shadow: 0 1px 0 var(--border);
}
/* Responsive */
@media (max-width: 900px) {
.slide { padding: 2.5rem 2rem; }
h1 { font-size: 2.2rem; }
h2 { font-size: 1.7rem; }
.card-grid.cols-3 { grid-template-columns: 1fr 1fr; }
.card-grid.cols-4 { grid-template-columns: 1fr 1fr; }
.two-col { grid-template-columns: 1fr; }
.pipeline { flex-wrap: wrap; }
.arch-diagram { grid-template-columns: 1fr; }
.extractor-grid { grid-template-columns: 1fr 1fr; }
}
</style>
</head>
<body>
<div class="keyboard-hint"><span class="key">&larr;</span> <span class="key">&rarr;</span> or swipe to navigate</div>
<div class="deck" id="deck">
<!-- ============================================================
SLIDE 1: TITLE
============================================================ -->
<div class="slide title-slide active" data-slide="0">
<div class="slide-inner" style="text-align:center;">
<div style="margin-bottom:1rem;">
<span class="tag tag-accent">Local-First &middot; Evidence-Native &middot; LLM-Powered</span>
</div>
<h1 class="gradient" style="font-size:3.5rem;">Knowledge Refinery</h1>
<p class="subtitle" style="margin:0 auto 2rem;">
A macOS Tahoe application that ingests heterogeneous document corpora,<br>
extracts structured knowledge via local LLMs, and renders an immersive 3D concept universe.
</p>
<div class="stats-row" style="justify-content:center;">
<div class="stat"><div class="stat-num">7</div><div class="stat-label">Milestones</div></div>
<div class="stat"><div class="stat-num">6</div><div class="stat-label">Pipeline Stages</div></div>
<div class="stat"><div class="stat-num">30</div><div class="stat-label">Unit Tests</div></div>
<div class="stat"><div class="stat-num">0</div><div class="stat-label">Cloud Calls</div></div>
</div>
<div style="margin-top:2rem; color:var(--fg-subtle); font-size:0.85rem;">
macOS &middot; SwiftUI &middot; Go &middot; chi &middot; LM Studio &middot; SQLite &middot; WebGPU &middot; Multi-Workspace
</div>
</div>
</div>
<!-- ============================================================
SLIDE 2: THE PROBLEM
============================================================ -->
<div class="slide" data-slide="1">
<div class="slide-inner">
<span class="tag tag-amber" style="margin-bottom:1rem;">The Problem</span>
<h2>Your knowledge is scattered, siloed, and unsearchable</h2>
<p class="lead">
Research papers, notes, e-books, medical images, code, archives &mdash; spread across folders
with no semantic connections. Keyword search fails. Cloud tools leak your data. You need
something that actually <em>understands</em> your corpus.
</p>
<div class="card-grid cols-3">
<div class="card">
<div class="icon rose">&#x1F50D;</div>
<h3>Search is Broken</h3>
<p>Keyword search misses semantically related content. "Machine learning" won't find your "neural network" papers.</p>
</div>
<div class="card">
<div class="icon amber">&#x1F512;</div>
<h3>Privacy Concerns</h3>
<p>Cloud-based tools send your sensitive documents, medical records, and proprietary research to third-party servers.</p>
</div>
<div class="card">
<div class="icon slate">&#x1F4C1;</div>
<h3>No Connections</h3>
<p>You have thousands of files but no way to see how concepts relate across documents, formats, and domains.</p>
</div>
</div>
</div>
</div>
<!-- ============================================================
SLIDE 3: THE SOLUTION
============================================================ -->
<div class="slide" data-slide="2">
<div class="slide-inner">
<span class="tag tag-green" style="margin-bottom:1rem;">The Solution</span>
<h2>Knowledge Refinery: Your Local Knowledge Engine</h2>
<div class="feature-row">
<div class="feature-icon" style="background:#eef2ff; color:#4f46e5;">&#x1F9E0;</div>
<div class="feature-text">
<h3>Semantic Understanding via Local LLMs</h3>
<p>Uses LM Studio running locally &mdash; your data never leaves your machine. Embeddings for similarity search, structured annotation for deep understanding.</p>
</div>
</div>
<div class="feature-row">
<div class="feature-icon" style="background:#ecfdf5; color:#059669;">&#x1F517;</div>
<div class="feature-text">
<h3>Evidence-Native &mdash; Every Insight Links to Source</h3>
<p>Every annotation, concept, and search result traces back to an exact location: file, page, chapter, even byte offset within nested archives.</p>
</div>
</div>
<div class="feature-row">
<div class="feature-icon" style="background:#ecfeff; color:#0891b2;">&#x1F30C;</div>
<div class="feature-text">
<h3>3D Concept Universe</h3>
<p>WebGPU-powered visualization renders your knowledge as an interactive 3D graph. Zoom from macro concepts to individual chunks. See how ideas connect.</p>
</div>
</div>
<div class="feature-row">
<div class="feature-icon" style="background:#fff1f2; color:#e11d48;">&#x1F6E1;</div>
<div class="feature-text">
<h3>Sandboxed & Incremental</h3>
<p>Archive extraction runs in macOS sandbox-exec. Changed files are detected via content hashing &mdash; only new/modified files are reprocessed.</p>
</div>
</div>
</div>
</div>
<!-- ============================================================
SLIDE 4: ARCHITECTURE
============================================================ -->
<div class="slide" data-slide="3">
<div class="slide-inner">
<span class="tag tag-accent" style="margin-bottom:1rem;">Architecture</span>
<h2>Three-Tier Local Architecture</h2>
<div class="arch-diagram">
<div class="arch-box" style="border-color:#4f46e5;">
<h4 style="color:#4f46e5;">&#x1F4F1; SwiftUI App</h4>
<div style="font-size:0.85rem; color:var(--fg-muted);">
<strong>Search</strong> &mdash; Semantic vector search<br>
<strong>Universe</strong> &mdash; WebGPU 3D visualization<br>
<strong>Concepts</strong> &mdash; Cluster browser + "Why?"<br>
<strong>Ingest</strong> &mdash; Pipeline monitoring<br>
<strong>Volumes</strong> &mdash; Folder management<br>
<strong>Assets</strong> &mdash; File inventory + Quick Look
</div>
</div>
<div class="arch-connector">
<span>&harr;</span>
<span class="proto">HTTP (localhost)</span>
<span style="font-size:0.65rem; color:var(--fg-subtle);">127.0.0.1:8742</span>
</div>
<div class="arch-box" style="border-color:#7c3aed;">
<h4 style="color:#7c3aed;">&#x2699;&#xFE0F; Go Daemon</h4>
<div style="font-size:0.85rem; color:var(--fg-muted);">
<strong>chi</strong> router with CORS<br>
<strong>6-Stage Pipeline</strong> orchestrator<br>
<strong>SQLite</strong> metadata + vectors + graph (WAL)<br>
<strong>11MB</strong> single binary, zero deps<br>
<strong>7 Extractors</strong> + fallback chain
</div>
</div>
</div>
<div style="text-align:center; margin-top:1rem;">
<span style="font-size:1.5rem; color:var(--fg-subtle);">&darr;</span>
<span class="proto" style="display:block; font-size:0.65rem; font-weight:600; color:var(--accent-4); letter-spacing:0.05em; text-transform:uppercase;">OpenAI-Compatible API</span>
</div>
<div style="max-width:360px; margin:0.75rem auto 0;">
<div class="arch-box" style="border-color:#059669;">
<h4 style="color:#059669;">&#x1F916; LM Studio</h4>
<div style="font-size:0.85rem; color:var(--fg-muted);">
<strong>qwen3-4b-2507</strong> &mdash; Chat / Annotation<br>
<strong>nomic-embed-text-v1.5</strong> &mdash; Embeddings<br>
Running on 127.0.0.1:1234
</div>
</div>
</div>
</div>
</div>
<!-- ============================================================
SLIDE 5: THE PIPELINE
============================================================ -->
<div class="slide" data-slide="4">
<div class="slide-inner">
<span class="tag tag-accent" style="margin-bottom:1rem;">Core Engine</span>
<h2>Six-Stage Ingestion Pipeline</h2>
<p class="lead" style="margin-bottom:1rem;">Every file flows through six deterministic stages. The pipeline is incremental &mdash; unchanged files are never reprocessed.</p>
<div class="pipeline">
<div class="pipeline-stage">
<div class="num" style="background:#4f46e5;">1</div>
<span class="label">Scan</span>
<span class="desc">Walk directories, compute SHA-256 content hashes, detect new/changed files</span>
</div>
<div class="pipeline-arrow">&rarr;</div>
<div class="pipeline-stage">
<div class="num" style="background:#7c3aed;">2</div>
<span class="label">Extract</span>
<span class="desc">Produce ContentAtoms with evidence anchors (page, chapter, offset)</span>
</div>
<div class="pipeline-arrow">&rarr;</div>
<div class="pipeline-stage">
<div class="num" style="background:#2563eb;">3</div>
<span class="label">Chunk</span>
<span class="desc">Deterministic 500-800 token splits with 50-token overlap, stable IDs</span>
</div>
<div class="pipeline-arrow">&rarr;</div>
<div class="pipeline-stage">
<div class="num" style="background:#0891b2;">4</div>
<span class="label">Embed</span>
<span class="desc">768-dim vectors via nomic-embed-text stored in SQLite</span>
</div>
<div class="pipeline-arrow">&rarr;</div>
<div class="pipeline-stage">
<div class="num" style="background:#059669;">5</div>
<span class="label">Annotate</span>
<span class="desc">LLM extracts topics, entities, claims, sentiment, summary</span>
</div>
<div class="pipeline-arrow">&rarr;</div>
<div class="pipeline-stage">
<div class="num" style="background:#d97706;">6</div>
<span class="label">Conceptualize</span>
<span class="desc">K-means++ clustering, concept labeling, kNN similarity graph</span>
</div>
</div>
<div style="text-align:center; margin-top:1rem; font-size:0.8rem; color:var(--fg-subtle);">
Status tracked per-asset: <code>pending &rarr; extracted &rarr; chunked &rarr; embedded &rarr; annotated</code>
</div>
</div>
</div>
<!-- ============================================================
SLIDE 6: EXTRACTORS
============================================================ -->
<div class="slide" data-slide="5">
<div class="slide-inner">
<span class="tag tag-cyan" style="margin-bottom:1rem;">Format Support</span>
<h2>Seven Pluggable Extractors</h2>
<p class="lead">Priority-sorted extractor registry. Each extractor produces ContentAtoms with evidence anchors. The Tika fallback handles anything the others miss.</p>
<div class="extractor-grid">
<div class="extractor-item">
<div class="ext-icon">&#x1F4D1;</div>
<div class="ext-name">PDF</div>
<div class="ext-types">.pdf &middot; Per-page text &middot; pdftotext</div>
<div><span class="tag tag-accent" style="font-size:0.6rem;">Priority 20</span></div>
</div>
<div class="extractor-item">
<div class="ext-icon">&#x1F4D6;</div>
<div class="ext-name">EPUB</div>
<div class="ext-types">.epub &middot; OPF spine order &middot; Metadata</div>
<div><span class="tag tag-accent" style="font-size:0.6rem;">Priority 18</span></div>
</div>
<div class="extractor-item">
<div class="ext-icon">&#x1F5BC;</div>
<div class="ext-name">Image + OCR</div>
<div class="ext-types">.png .jpg .heic &middot; macOS Vision</div>
<div><span class="tag tag-accent" style="font-size:0.6rem;">Priority 15</span></div>
</div>
<div class="extractor-item">
<div class="ext-icon">&#x1FA7B;</div>
<div class="ext-name">DICOM</div>
<div class="ext-types">.dcm &middot; Medical metadata &middot; Binary header parsing</div>
<div><span class="tag tag-accent" style="font-size:0.6rem;">Priority 15</span></div>
</div>
<div class="extractor-item">
<div class="ext-icon">&#x1F4DD;</div>
<div class="ext-name">Text</div>
<div class="ext-types">.txt .md .html .rtf &middot; Tag stripping</div>
<div><span class="tag tag-accent" style="font-size:0.6rem;">Priority 10</span></div>
</div>
<div class="extractor-item">
<div class="ext-icon">&#x1F4E6;</div>
<div class="ext-name">Archive</div>
<div class="ext-types">.zip .tar.gz &middot; Sandboxed &middot; Zip-slip safe</div>
<div><span class="tag tag-accent" style="font-size:0.6rem;">Priority 5</span></div>
</div>
<div class="extractor-item">
<div class="ext-icon">&#x1F504;</div>
<div class="ext-name">Tika Fallback</div>
<div class="ext-types">.doc .docx .pptx &middot; textutil &middot; Raw text</div>
<div><span class="tag tag-accent" style="font-size:0.6rem;">Priority 1</span></div>
</div>
<div class="extractor-item" style="background:var(--bg-muted); border-style:dashed;">
<div class="ext-icon" style="opacity:0.4;">&#x2795;</div>
<div class="ext-name" style="color:var(--fg-subtle);">Custom</div>
<div class="ext-types">Extend BaseExtractor &middot; Register in registry</div>
<div><span class="tag" style="font-size:0.6rem; background:var(--bg-muted); color:var(--fg-subtle);">Pluggable</span></div>
</div>
</div>
</div>
</div>
<!-- ============================================================
SLIDE 7: ANNOTATIONS
============================================================ -->
<div class="slide" data-slide="6">
<div class="slide-inner">
<span class="tag tag-green" style="margin-bottom:1rem;">LLM Intelligence</span>
<h2>Rich Structured Annotations</h2>
<p class="lead">Every chunk is annotated by the local LLM, producing structured metadata that enriches search and powers concept formation.</p>
<div class="two-col">
<div>
<div class="annotation-example">
<div class="ann-field">
<div class="ann-label">Topics</div>
<div class="ann-tags">
<span class="ann-tag" style="background:#eef2ff; color:#4f46e5;">cryptography</span>
<span class="ann-tag" style="background:#f5f3ff; color:#7c3aed;">encryption</span>
<span class="ann-tag" style="background:#eff6ff; color:#2563eb;">security</span>
<span class="ann-tag" style="background:#ecfeff; color:#0891b2;">post-quantum</span>
<span class="ann-tag" style="background:#ecfdf5; color:#059669;">digital signatures</span>
</div>
</div>
<div class="ann-field">
<div class="ann-label">Summary</div>
<p style="font-size:0.85rem; color:var(--fg-muted); font-style:italic;">
"This text describes various cryptographic techniques, including symmetric and asymmetric encryption algorithms like AES and RSA..."
</p>
</div>
<div class="ann-field">
<div class="ann-label">Entities</div>
<div class="ann-tags">
<span class="ann-tag" style="background:#fff1f2; color:#e11d48;">AES</span>
<span class="ann-tag" style="background:#fff1f2; color:#e11d48;">RSA</span>
<span class="ann-tag" style="background:#fff1f2; color:#e11d48;">ECC</span>
<span class="ann-tag" style="background:#fffbeb; color:#d97706;">NIST</span>
<span class="ann-tag" style="background:#fff1f2; color:#e11d48;">SHA-256</span>
<span class="ann-tag" style="background:#fff1f2; color:#e11d48;">EdDSA</span>
</div>
</div>
<div class="ann-field" style="margin-bottom:0;">
<div class="ann-label">Sentiment</div>
<span class="badge" style="background:#f0f2f7; color:#5a6072;">&#x2696; neutral &middot; 0.95</span>
</div>
</div>
</div>
<div>
<h3>Annotation Fields</h3>
<table class="data-table">
<tr><th>Field</th><th>Type</th></tr>
<tr><td><code>topics</code></td><td>2-5 multi-label tags</td></tr>
<tr><td><code>entities</code></td><td>Named entities + type</td></tr>
<tr><td><code>claims</code></td><td>Extracted claims + confidence</td></tr>
<tr><td><code>sentiment</code></td><td>Label + confidence score</td></tr>
<tr><td><code>summary</code></td><td>1-2 sentence summary</td></tr>
<tr><td><code>quality_flags</code></td><td>Truncated, technical, etc.</td></tr>
</table>
<div style="margin-top:1.25rem; padding:1rem; background:var(--bg-subtle); border-radius:var(--radius-sm); font-size:0.82rem; color:var(--fg-muted);">
<strong style="color:var(--fg);">Versioned &amp; Immutable:</strong> Annotations are never overwritten. New model/prompt versions create new records with <code>is_current=1</code>, preserving the full audit trail.
</div>
</div>
</div>
</div>
</div>
<!-- ============================================================
SLIDE 8: CONCEPT UNIVERSE
============================================================ -->
<div class="slide" data-slide="7">
<div class="slide-inner">
<span class="tag tag-accent" style="margin-bottom:1rem;">Visualization</span>
<h2>3D Concept Universe</h2>
<p class="lead">Concepts are rendered as a force-directed 3D graph using WebGPU. Orbit, zoom, and click to explore how your knowledge connects.</p>
<div class="two-col">
<div>
<div style="background:#0a0a14; border-radius:var(--radius); padding:2rem; text-align:center; position:relative; overflow:hidden;">
<!-- Simulated universe -->
<svg viewBox="0 0 400 280" style="width:100%; max-width:400px;">
<!-- Edges -->
<line x1="120" y1="90" x2="280" y2="120" stroke="#4f46e560" stroke-width="1"/>
<line x1="120" y1="90" x2="200" y2="210" stroke="#7c3aed40" stroke-width="1"/>
<line x1="280" y1="120" x2="200" y2="210" stroke="#2563eb40" stroke-width="1"/>
<line x1="120" y1="90" x2="80" y2="160" stroke="#4f46e530" stroke-width="0.5"/>
<line x1="120" y1="90" x2="160" y2="50" stroke="#4f46e530" stroke-width="0.5"/>
<line x1="280" y1="120" x2="320" y2="70" stroke="#2563eb30" stroke-width="0.5"/>
<line x1="280" y1="120" x2="340" y2="170" stroke="#2563eb30" stroke-width="0.5"/>
<line x1="200" y1="210" x2="160" y2="250" stroke="#7c3aed30" stroke-width="0.5"/>
<line x1="200" y1="210" x2="240" y2="260" stroke="#7c3aed30" stroke-width="0.5"/>
<!-- Concept nodes -->
<circle cx="120" cy="90" r="22" fill="#4f46e5" opacity="0.9"/>
<circle cx="280" cy="120" r="20" fill="#2563eb" opacity="0.9"/>
<circle cx="200" cy="210" r="18" fill="#7c3aed" opacity="0.9"/>
<!-- Chunk nodes -->
<circle cx="80" cy="160" r="5" fill="#4f46e580"/>
<circle cx="160" cy="50" r="5" fill="#4f46e580"/>
<circle cx="320" cy="70" r="5" fill="#2563eb80"/>
<circle cx="340" cy="170" r="5" fill="#2563eb80"/>
<circle cx="160" cy="250" r="5" fill="#7c3aed80"/>
<circle cx="240" cy="260" r="5" fill="#7c3aed80"/>
<!-- Labels -->
<text x="120" y="94" text-anchor="middle" fill="white" font-size="7" font-weight="600">AI Learning</text>
<text x="280" y="124" text-anchor="middle" fill="white" font-size="7" font-weight="600">Data Systems</text>
<text x="200" y="214" text-anchor="middle" fill="white" font-size="7" font-weight="600">Security</text>
</svg>
<div style="position:absolute; top:0.75rem; left:0.75rem; display:flex; gap:0.5rem;">
<span style="background:rgba(255,255,255,0.1); color:rgba(255,255,255,0.7); font-size:0.6rem; padding:0.2rem 0.5rem; border-radius:4px; backdrop-filter:blur(8px);">9 nodes</span>
<span style="background:rgba(255,255,255,0.1); color:rgba(255,255,255,0.7); font-size:0.6rem; padding:0.2rem 0.5rem; border-radius:4px;">MACRO</span>
<span style="background:rgba(255,255,255,0.1); color:rgba(255,255,255,0.7); font-size:0.6rem; padding:0.2rem 0.5rem; border-radius:4px;">60 fps</span>
</div>
</div>
</div>
<div>
<h3>Rendering Engine</h3>
<table class="data-table">
<tr><td><strong>Renderer</strong></td><td>WebGPU in WKWebView</td></tr>
<tr><td><strong>Shaders</strong></td><td>WGSL (214 lines)</td></tr>
<tr><td><strong>Layout</strong></td><td>Force-directed (Velocity Verlet)</td></tr>
<tr><td><strong>Nodes</strong></td><td>Billboarded quads with circle SDF + glow</td></tr>
<tr><td><strong>Camera</strong></td><td>Orbit (drag), Pan (right-drag), Zoom (scroll)</td></tr>
</table>
<h3 style="margin-top:1.25rem;">Level-of-Detail System</h3>
<table class="data-table">
<tr><th>LOD</th><th>Shows</th><th>Zoom</th></tr>
<tr><td><span class="tag tag-accent" style="font-size:0.65rem;">MACRO</span></td><td>Concept clusters only</td><td>Distant</td></tr>
<tr><td><span class="tag tag-cyan" style="font-size:0.65rem;">MID</span></td><td>Concepts + sub-concepts</td><td>Medium</td></tr>
<tr><td><span class="tag tag-green" style="font-size:0.65rem;">NEAR</span></td><td>All nodes + all edges</td><td>Close</td></tr>
</table>
</div>
</div>
</div>
</div>
<!-- ============================================================
SLIDE 9: DATA MODEL
============================================================ -->
<div class="slide" data-slide="8">
<div class="slide-inner">
<span class="tag tag-accent" style="margin-bottom:1rem;">Data Model</span>
<h2>Evidence-Native Knowledge Graph</h2>
<p class="lead">Every derived artifact links back to its source. The data model captures the full provenance chain from file to concept.</p>
<div class="two-col">
<div>
<div class="code-block" style="font-size:0.72rem;">
<span class="comment">-- Provenance chain:</span>
WatchedVolume
<span class="op">&darr;</span> <span class="comment">(contains files)</span>
FileAsset <span class="comment">-- SHA-256 ID, content hash</span>
<span class="op">&darr;</span> <span class="comment">(extracted into)</span>
ContentAtom <span class="comment">-- text/image/table/metadata</span>
<span class="op">&darr;</span> <span class="comment">(split into)</span>
Chunk <span class="comment">-- deterministic ID, 500-800 tokens</span>
<span class="op">&darr;</span>
<span class="op">├──&gt;</span> Vector <span class="comment">(SQLite BLOB, 768-dim)</span>
<span class="op">├──&gt;</span> Annotation <span class="comment">(versioned, immutable)</span>
<span class="op">└──&gt;</span> GraphEdge
<span class="op">&darr;</span>
ConceptNode <span class="comment">(hierarchical clusters)</span></div>
</div>
<div>
<h3>Evidence Anchors</h3>
<p style="font-size:0.85rem; color:var(--fg-muted); margin-bottom:1rem;">Every ContentAtom, Chunk, and Edge stores a JSON evidence anchor linking to the exact source location.</p>
<div class="code-block" style="font-size:0.72rem;">
{
<span class="string">"asset_id"</span>: <span class="string">"abc123..."</span>,
<span class="string">"page"</span>: <span class="number">5</span>,
<span class="string">"chapter"</span>: <span class="string">"Introduction"</span>,
<span class="string">"archive_chain"</span>: <span class="string">"docs.zip/paper.pdf"</span>,
<span class="string">"line_start"</span>: <span class="number">42</span>,
<span class="string">"line_end"</span>: <span class="number">58</span>
}</div>
<h3 style="margin-top:1rem;">Storage</h3>
<table class="data-table" style="font-size:0.8rem;">
<tr><td><strong>SQLite</strong></td><td>Metadata, vectors (BLOB), graph, jobs (WAL mode)</td></tr>
<tr><td><strong>Disk</strong></td><td>~/.knowledge-refinery/</td></tr>
</table>
</div>
</div>
</div>
</div>
<!-- ============================================================
SLIDE 10: SECURITY
============================================================ -->
<div class="slide" data-slide="9">
<div class="slide-inner">
<span class="tag tag-rose" style="margin-bottom:1rem;">Security</span>
<h2>Defense in Depth</h2>
<p class="lead">Zero cloud calls. Localhost-only daemon. Sandboxed extraction. Every security layer works locally.</p>
<div class="card-grid cols-3">
<div class="card">
<div class="icon indigo">&#x1F510;</div>
<h3>Localhost-Only Binding</h3>
<p>Daemon binds exclusively to <code>127.0.0.1</code> — not reachable from the network. No tokens needed for a single-user local app.</p>
</div>
<div class="card">
<div class="icon violet">&#x1F6E1;</div>
<h3>macOS Sandbox</h3>
<p>Archive extraction runs in <code>sandbox-exec</code> with: no network, restricted filesystem, CPU and memory limits.</p>
</div>
<div class="card">
<div class="icon blue">&#x1F6AB;</div>
<h3>Zip-Slip Prevention</h3>
<p>All archive member paths are validated and resolved against the extraction base directory. Traversal attempts are blocked.</p>
</div>
<div class="card">
<div class="icon cyan">&#x1F4A3;</div>
<h3>Archive Bomb Detection</h3>
<p>Limits enforced: 10,000 max files, 500MB total extracted, 50MB per file, max 3 nesting levels.</p>
</div>
<div class="card">
<div class="icon emerald">&#x1F4BB;</div>
<h3>100% Local</h3>
<p>LM Studio runs on localhost. Data stays on disk. No telemetry, no cloud APIs, no external network calls. Zero data leakage.</p>
</div>
<div class="card">
<div class="icon amber">&#x1F50D;</div>
<h3>Content Hashing</h3>
<p>SHA-256 streaming hash for change detection. Deterministic chunk IDs ensure stable references across re-processing.</p>
</div>
</div>
</div>
</div>
<!-- ============================================================
SLIDE 11: MASTER CONTROL APP
============================================================ -->
<div class="slide" data-slide="10">
<div class="slide-inner">
<span class="tag tag-accent" style="margin-bottom:1rem;">Milestone 7</span>
<h2>Master Control App</h2>
<p class="lead">One dashboard to manage everything. LM Studio monitoring, multi-workspace lifecycle, visual data lake mapping &mdash; all from a single window.</p>
<div class="card-grid cols-3">
<div class="card">
<div class="icon indigo">&#x1F4CA;</div>
<h3>Dashboard</h3>
<p>LM Studio status card with model names. Workspace grid with start/stop toggles, vector counts, and color-coded cards. "Start All" for one-click launch.</p>
</div>
<div class="card">
<div class="icon violet">&#x1F4E6;</div>
<h3>Multi-Workspace</h3>
<p>Each workspace gets its own data directory, daemon port (8742, 8743, ...), and SQLite database (metadata + vectors + graph). Independent lifecycle management.</p>
</div>
<div class="card">
<div class="icon blue">&#x1F5FA;</div>
<h3>Data Lake Mapping</h3>
<p>Visual Canvas view showing which folders feed which workspaces. B&eacute;zier curves connect data lakes to knowledge bases with color-coded workspace tags.</p>
</div>
<div class="card">
<div class="icon cyan">&#x1F9E0;</div>
<h3>LM Studio Monitor</h3>
<p>Direct polling of <code>/v1/models</code> every 5 seconds. Auto-classifies chat vs. embedding models. Independent of daemon status &mdash; green means ready.</p>
</div>
<div class="card">
<div class="icon emerald">&#x1F527;</div>
<h3>Daemon Lifecycle</h3>
<p>Start, stop, restart per-workspace daemons. Environment variables <code>KR_DATA_DIR</code> and <code>KR_PORT</code> injected automatically. Live log capture (last 500 lines).</p>
</div>
<div class="card">
<div class="icon amber">&#x1F4C1;</div>
<h3>Workspace Setup</h3>
<p>Create workspaces with name, color tag, and folder picker. Native <code>NSOpenPanel</code> for multi-selecting data lake paths including external drives.</p>
</div>
</div>
<div style="margin-top:1.5rem; text-align:center;">
<div style="display:inline-flex; gap:0.75rem; flex-wrap:wrap; font-size:0.8rem;">
<div class="badge" style="background:var(--accent-bg); color:var(--accent);">WorkspaceConfig.swift</div>
<div class="badge" style="background:#f5f3ff; color:#7c3aed;">LMStudioMonitor.swift</div>
<div class="badge" style="background:#ecfdf5; color:#059669;">MasterDashboardView.swift</div>
<div class="badge" style="background:#ecfeff; color:#0891b2;">DataLakeMappingView.swift</div>
<div class="badge" style="background:#fffbeb; color:#d97706;">WorkspaceDetailView.swift</div>
</div>
</div>
</div>
</div>
<!-- ============================================================
SLIDE 12: INSTALLATION
============================================================ -->
<div class="slide" data-slide="11">
<div class="slide-inner">
<span class="tag tag-green" style="margin-bottom:1rem;">Installation</span>
<h2>From Clone to Running in One Command</h2>
<div class="two-col">
<div>
<h3>Prerequisites</h3>
<table class="data-table" style="margin-bottom:1.5rem;">
<tr><td><strong>macOS</strong></td><td>Tahoe (26.x) on Apple Silicon</td></tr>
<tr><td><strong>Xcode</strong></td><td>26.x or Command Line Tools</td></tr>
<tr><td><strong>Go</strong></td><td>1.22+ (from go.dev or Homebrew)</td></tr>
<tr><td><strong>LM Studio</strong></td><td>From lmstudio.ai (free)</td></tr>
</table>
<h3>What the Installer Does</h3>
<ol class="step-list">
<li>
<strong>Checks prerequisites</strong>
<p>Validates macOS version, architecture, Xcode tools, Swift, and Go version.</p>
</li>
<li>
<strong>Builds Go daemon</strong>
<p>Compiles the Go daemon into a single 17MB binary with zero runtime dependencies.</p>
</li>
<li>
<strong>Builds the .app bundle</strong>
<p>Swift release build &rarr; proper <code>.app</code> with Info.plist, bundled daemon, and WebGPU resources.</p>
</li>
<li>
<strong>Installs to /Applications</strong>
<p>Copies the app bundle. Appears in Launchpad and Spotlight immediately.</p>
</li>
</ol>
</div>
<div>
<h3>One-Line Install</h3>
<div class="code-block" style="font-size:0.75rem; margin-bottom:1.25rem;">
<span class="comment"># Clone and install</span>
<span class="fn">git</span> clone &lt;repo-url&gt;
<span class="keyword">cd</span> LongLocalTimeHorizonInfoRetrieval
<span class="fn">bash</span> scripts/install.sh</div>
<h3>Make Targets</h3>
<div class="code-block" style="font-size:0.75rem; margin-bottom:1.25rem;">
<span class="fn">make</span> build <span class="comment"># Build .app bundle to dist/</span>
<span class="fn">make</span> install <span class="comment"># Full install to /Applications</span>
<span class="fn">make</span> test <span class="comment"># Run all tests</span>
<span class="fn">make</span> app-run <span class="comment"># Dev mode (swift run)</span>
<span class="fn">make</span> daemon-run <span class="comment"># Run daemon directly</span>
<span class="fn">make</span> clean <span class="comment"># Remove build artifacts</span></div>
<h3>App Bundle Structure</h3>
<div class="code-block" style="font-size:0.72rem;">
Knowledge Refinery.app/
Contents/
Info.plist
MacOS/
KnowledgeRefinery <span class="comment"># launcher</span>
KnowledgeRefinery-bin <span class="comment"># Swift binary</span>
Resources/
knowledge-refinery-daemon <span class="comment"># Go binary (17MB)</span>
WebGPU/ <span class="comment"># 3D renderer</span>
universe.html/js/wgsl</div>
</div>
</div>
</div>
</div>
<!-- ============================================================
SLIDE 13: APP WALKTHROUGH
============================================================ -->
<div class="slide" data-slide="12">
<div class="slide-inner">
<span class="tag tag-accent" style="margin-bottom:1rem;">App Walkthrough</span>
<h2>Dashboard + Workspace: Two-Level UI</h2>
<div class="two-col">
<div>
<h3 style="color:var(--accent);">Level 1: Dashboard</h3>
<div class="card" style="margin-bottom:0.75rem;">
<div class="icon indigo">&#x1F4CA;</div>
<h3>LM Studio Card</h3>
<p>Green/red status, loaded model names (chat + embedding), port number. Polls directly at <code>/v1/models</code>.</p>
</div>
<div class="card" style="margin-bottom:0.75rem;">
<div class="icon violet">&#x1F4E6;</div>
<h3>Workspace Grid</h3>
<p>Color-coded cards with daemon toggle, vector count, data lake count. Click "Open" to enter a workspace.</p>
</div>
<div class="card">
<div class="icon blue">&#x1F5FA;</div>
<h3>Data Lake Map</h3>
<p>Canvas-drawn B&eacute;zier curves connecting folder paths to workspaces. See which folders feed which knowledge bases.</p>
</div>
</div>
<div>
<h3 style="color:var(--accent-2);">Level 2: Workspace</h3>
<div class="card" style="margin-bottom:0.75rem;">
<div class="icon emerald">&#x1F50E;</div>
<h3>Search + Universe + Concepts</h3>
<p>Full NavigationSplitView with semantic search, WebGPU 3D concept graph, hierarchical concept browser with "Why?" explanations.</p>
</div>
<div class="card" style="margin-bottom:0.75rem;">
<div class="icon cyan">&#x2B07;</div>
<h3>Ingest + Volumes + Assets</h3>
<p>Pipeline monitoring, volume management, file inventory. Each workspace has its own daemon process and data directory.</p>
</div>
<div class="card">
<div class="icon amber">&#x1F527;</div>
<h3>Daemon Controls + Logs</h3>
<p>Play/stop/restart buttons in the header bar. Live log viewer showing last 500 lines of daemon stdout/stderr.</p>
</div>
</div>
</div>
<div style="margin-top:1.5rem; text-align:center;">
<div style="display:inline-flex; gap:1rem; align-items:center; padding:0.75rem 1.5rem; background:var(--bg-subtle); border-radius:var(--radius-sm); font-size:0.8rem; color:var(--fg-muted);">
<span>&#x1F7E2; LM Studio (shared)</span>
<span>&#x1F7E2; Workspace 1 :8742</span>
<span>&#x1F7E2; Workspace 2 :8743</span>
<span style="margin-left:0.5rem;">Each workspace runs its own daemon</span>
</div>
</div>
</div>
</div>
<!-- ============================================================
SLIDE 14: SEARCH DEEP DIVE
============================================================ -->
<div class="slide" data-slide="13">
<div class="slide-inner">
<span class="tag tag-accent" style="margin-bottom:1rem;">Deep Dive</span>
<h2>How Search Works</h2>
<div class="two-col">
<div>
<h3>Query Flow</h3>
<div style="background:var(--bg-subtle); border-radius:var(--radius); padding:1.25rem; font-size:0.85rem; line-height:2;">
<div style="display:flex; align-items:center; gap:0.75rem;">
<span style="background:var(--accent); color:white; width:24px; height:24px; border-radius:50%; display:inline-flex; align-items:center; justify-content:center; font-size:0.7rem; font-weight:700; flex-shrink:0;">1</span>
User types: <code>"cryptography encryption"</code>
</div>
<div style="color:var(--fg-subtle); padding-left:2.3rem;">&darr;</div>
<div style="display:flex; align-items:center; gap:0.75rem;">
<span style="background:#0891b2; color:white; width:24px; height:24px; border-radius:50%; display:inline-flex; align-items:center; justify-content:center; font-size:0.7rem; font-weight:700; flex-shrink:0;">2</span>
Embed query via nomic-embed-text &rarr; 768-dim vector
</div>
<div style="color:var(--fg-subtle); padding-left:2.3rem;">&darr;</div>
<div style="display:flex; align-items:center; gap:0.75rem;">
<span style="background:#7c3aed; color:white; width:24px; height:24px; border-radius:50%; display:inline-flex; align-items:center; justify-content:center; font-size:0.7rem; font-weight:700; flex-shrink:0;">3</span>
Brute-force cosine similarity search (in-memory vectors)
</div>
<div style="color:var(--fg-subtle); padding-left:2.3rem;">&darr;</div>
<div style="display:flex; align-items:center; gap:0.75rem;">
<span style="background:#059669; color:white; width:24px; height:24px; border-radius:50%; display:inline-flex; align-items:center; justify-content:center; font-size:0.7rem; font-weight:700; flex-shrink:0;">4</span>
Enrich with annotations (topics, summary, entities)
</div>
<div style="color:var(--fg-subtle); padding-left:2.3rem;">&darr;</div>
<div style="display:flex; align-items:center; gap:0.75rem;">
<span style="background:#d97706; color:white; width:24px; height:24px; border-radius:50%; display:inline-flex; align-items:center; justify-content:center; font-size:0.7rem; font-weight:700; flex-shrink:0;">5</span>
Return ranked results with evidence anchors
</div>
</div>
</div>
<div>
<h3>Example Result</h3>
<div class="card" style="border-left:3px solid var(--accent);">
<div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:0.5rem;">
<strong style="font-size:0.9rem;">&#x1F4C4; cryptography_basics.html</strong>
<span class="badge" style="background:#ecfdf5; color:#059669; font-size:0.7rem;">score: 0.378</span>
</div>
<div style="margin-bottom:0.75rem;">
<div style="font-size:0.75rem; font-weight:600; color:var(--fg-subtle); margin-bottom:0.2rem;">LLM SUMMARY</div>
<p style="font-size:0.82rem; color:var(--fg-muted); font-style:italic;">"This text describes various cryptographic techniques, including symmetric and asymmetric encryption..."</p>
</div>
<div style="margin-bottom:0.75rem;">
<div style="font-size:0.75rem; font-weight:600; color:var(--fg-subtle); margin-bottom:0.2rem;">ENTITIES</div>
<div style="display:flex; flex-wrap:wrap; gap:0.3rem;">
<span class="ann-tag" style="background:#eef2ff; color:#4f46e5; font-size:0.7rem;">AES</span>
<span class="ann-tag" style="background:#eef2ff; color:#4f46e5; font-size:0.7rem;">RSA</span>
<span class="ann-tag" style="background:#eef2ff; color:#4f46e5; font-size:0.7rem;">ECC</span>
<span class="ann-tag" style="background:#fffbeb; color:#d97706; font-size:0.7rem;">NIST</span>
<span class="ann-tag" style="background:#eef2ff; color:#4f46e5; font-size:0.7rem;">SHA-256</span>
</div>
</div>
<div>
<span class="badge" style="background:#f0f2f7; font-size:0.7rem;">&#x2696; neutral</span>
</div>
</div>
<div style="margin-top:1rem; font-size:0.82rem; color:var(--fg-muted);">
<strong>Key insight:</strong> A search for "cryptography" finds the right file even though the query doesn't match any specific keywords in other documents. Semantic similarity beats keyword search.
</div>
</div>
</div>
</div>
</div>
<!-- ============================================================
SLIDE 15: API REFERENCE
============================================================ -->
<div class="slide" data-slide="14">
<div class="slide-inner">
<span class="tag tag-cyan" style="margin-bottom:1rem;">API Reference</span>
<h2>RESTful API Endpoints</h2>
<p class="lead">The daemon exposes a clean REST API on localhost. All endpoints are accessible without authentication — the daemon only binds to 127.0.0.1.</p>
<table class="data-table" style="font-size:0.82rem;">
<thead>
<tr><th>Method</th><th>Endpoint</th><th>Description</th></tr>
</thead>
<tbody>
<tr><td><span class="badge" style="background:#ecfdf5; color:#059669; font-size:0.65rem;">GET</span></td><td><code>/health</code></td><td>Health check + LM Studio status (no auth)</td></tr>
<tr><td><span class="badge" style="background:#eff6ff; color:#2563eb; font-size:0.65rem;">POST</span></td><td><code>/volumes/add</code></td><td>Register a folder to watch</td></tr>
<tr><td><span class="badge" style="background:#ecfdf5; color:#059669; font-size:0.65rem;">GET</span></td><td><code>/volumes/list</code></td><td>List all watched volumes</td></tr>
<tr><td><span class="badge" style="background:#eff6ff; color:#2563eb; font-size:0.65rem;">POST</span></td><td><code>/ingest/start</code></td><td>Trigger full 6-stage pipeline</td></tr>
<tr><td><span class="badge" style="background:#ecfdf5; color:#059669; font-size:0.65rem;">GET</span></td><td><code>/ingest/status</code></td><td>Pipeline progress + per-stage counts</td></tr>
<tr><td><span class="badge" style="background:#eff6ff; color:#2563eb; font-size:0.65rem;">POST</span></td><td><code>/search</code></td><td>Semantic vector search with annotation enrichment</td></tr>
<tr><td><span class="badge" style="background:#ecfdf5; color:#059669; font-size:0.65rem;">GET</span></td><td><code>/search/quick?q=...</code></td><td>Quick search via query parameter</td></tr>
<tr><td><span class="badge" style="background:#ecfdf5; color:#059669; font-size:0.65rem;">GET</span></td><td><code>/universe/snapshot?lod=macro</code></td><td>Graph snapshot at given LOD level</td></tr>
<tr><td><span class="badge" style="background:#eff6ff; color:#2563eb; font-size:0.65rem;">POST</span></td><td><code>/universe/focus</code></td><td>Focus on node and return neighborhood</td></tr>
<tr><td><span class="badge" style="background:#ecfdf5; color:#059669; font-size:0.65rem;">GET</span></td><td><code>/concepts/list</code></td><td>List all concept clusters</td></tr>
<tr><td><span class="badge" style="background:#ecfdf5; color:#059669; font-size:0.65rem;">GET</span></td><td><code>/concepts/{id}</code></td><td>Concept detail with member chunks</td></tr>
<tr><td><span class="badge" style="background:#ecfdf5; color:#059669; font-size:0.65rem;">GET</span></td><td><code>/concepts/{id}/why</code></td><td>"Why this concept?" with evidence chain</td></tr>
<tr><td><span class="badge" style="background:#ecfdf5; color:#059669; font-size:0.65rem;">GET</span></td><td><code>/evidence/chunk/{id}/annotation</code></td><td>Full annotation for a specific chunk</td></tr>
</tbody>
</table>
</div>
</div>
<!-- ============================================================
SLIDE 16: TECH STACK
============================================================ -->
<div class="slide" data-slide="15">
<div class="slide-inner">
<span class="tag tag-accent" style="margin-bottom:1rem;">Technology</span>
<h2>Technology Stack</h2>
<div class="two-col">
<div>
<h3>Frontend (macOS App)</h3>
<table class="data-table">
<tr><td><strong>Framework</strong></td><td>SwiftUI (macOS Tahoe / 26.x)</td></tr>
<tr><td><strong>Language</strong></td><td>Swift 6.2.3</td></tr>
<tr><td><strong>Architecture</strong></td><td>Multi-workspace + dashboard</td></tr>
<tr><td><strong>3D Rendering</strong></td><td>WebGPU via WKWebView</td></tr>
<tr><td><strong>File Preview</strong></td><td>QuickLook framework</td></tr>
<tr><td><strong>Build</strong></td><td>SPM + build.sh &rarr; .app bundle</td></tr>
<tr><td><strong>Install</strong></td><td><code>make install</code> or install.sh</td></tr>
</table>
</div>
<div>
<h3>Backend (Go Daemon)</h3>
<table class="data-table">
<tr><td><strong>Language</strong></td><td>Go 1.22+ (single 17MB binary)</td></tr>
<tr><td><strong>HTTP Router</strong></td><td>chi/v5 + CORS middleware</td></tr>
<tr><td><strong>Storage</strong></td><td>SQLite (metadata + vectors + graph, WAL mode)</td></tr>
<tr><td><strong>SQLite Driver</strong></td><td>modernc.org/sqlite (pure Go, no CGo)</td></tr>
<tr><td><strong>LLM Client</strong></td><td>net/http &rarr; LM Studio</td></tr>
<tr><td><strong>PDF</strong></td><td>pdftotext (poppler-utils)</td></tr>
<tr><td><strong>Tokenizer</strong></td><td>tiktoken-go (cl100k_base)</td></tr>
<tr><td><strong>Math</strong></td><td>Pure Go (k-means++, cosine sim)</td></tr>
</table>
<h3 style="margin-top:1.5rem;">LM Studio Models</h3>
<table class="data-table">
<tr><td><strong>Chat</strong></td><td>qwen3-4b-2507</td></tr>
<tr><td><strong>Embeddings</strong></td><td>nomic-embed-text-v1.5 (768-dim)</td></tr>
</table>
</div>
</div>
</div>
</div>
<!-- ============================================================
SLIDE 17: FINAL
============================================================ -->
<div class="slide title-slide" data-slide="16">
<div class="slide-inner" style="text-align:center;">
<h1 class="gradient">Your Knowledge,<br>Refined.</h1>
<p class="subtitle" style="margin:0.5rem auto 2.5rem;">
Fully local. Evidence-native. LLM-powered. Installable.<br>
Clone, install, launch &mdash; from raw documents to searchable knowledge in minutes.
</p>
<div class="stats-row" style="justify-content:center; margin-bottom:2.5rem;">
<div class="stat"><div class="stat-num">97</div><div class="stat-label">Tests Passing</div></div>
<div class="stat"><div class="stat-num">0</div><div class="stat-label">Compiler Warnings</div></div>
<div class="stat"><div class="stat-num">~90</div><div class="stat-label">Source Files</div></div>
<div class="stat"><div class="stat-num">100%</div><div class="stat-label">Local</div></div>
</div>
<div style="display:flex; gap:1rem; justify-content:center; flex-wrap:wrap; font-size:0.82rem;">
<div class="badge" style="background:var(--accent-bg); color:var(--accent);">&#x1F4C1; daemon-go/</div>
<div class="badge" style="background:#f5f3ff; color:#7c3aed;">&#x1F4F1; apps/macos/KnowledgeRefinery/</div>
<div class="badge" style="background:#ecfdf5; color:#059669;">&#x1F9EA; daemon-go/internal/*/</div>
<div class="badge" style="background:#fffbeb; color:#d97706;">&#x1F6E0; scripts/install.sh</div>
</div>
<div style="margin-top:1.5rem;">
<div class="code-block" style="display:inline-block; font-size:0.8rem; padding:0.6rem 1.5rem; text-align:left;">
<span class="fn">git</span> clone &lt;repo&gt; &amp;&amp; <span class="keyword">cd</span> LongLocalTimeHorizonInfoRetrieval &amp;&amp; <span class="fn">make</span> install</div>
</div>
<div style="margin-top:1.5rem; color:var(--fg-subtle); font-size:0.8rem;">
Built with SwiftUI, Go, chi, SQLite, WebGPU, and local LLMs
</div>
</div>
</div>
</div><!-- /deck -->
<!-- ============================================================
NAVIGATION BAR
============================================================ -->
<div class="nav-bar">
<button class="nav-btn" id="btn-prev" onclick="navigate(-1)">&#x2190; Prev</button>
<div class="progress"><div class="progress-fill" id="progress-fill"></div></div>
<span class="slide-counter" id="slide-counter">1 / 17</span>
<button class="nav-btn" id="btn-next" onclick="navigate(1)">Next &#x2192;</button>
</div>
<script>
// ============================================================
// SLIDE ENGINE
// ============================================================
const slides = document.querySelectorAll('.slide');
let current = 0;
const total = slides.length;
function goTo(n) {
if (n < 0 || n >= total) return;
const prev = current;
current = n;
slides.forEach((s, i) => {
s.classList.remove('active', 'prev');
if (i === current) s.classList.add('active');
else if (i === prev) s.classList.add('prev');
});
document.getElementById('slide-counter').textContent = `${current + 1} / ${total}`;
document.getElementById('progress-fill').style.width = `${((current + 1) / total) * 100}%`;
document.getElementById('btn-prev').disabled = current === 0;
document.getElementById('btn-next').disabled = current === total - 1;
// Scroll active slide to top if overflowing
slides[current].scrollTop = 0;
}
function navigate(dir) {
goTo(current + dir);
}
// Keyboard
document.addEventListener('keydown', e => {
if (e.key === 'ArrowRight' || e.key === ' ') { e.preventDefault(); navigate(1); }
else if (e.key === 'ArrowLeft') { e.preventDefault(); navigate(-1); }
else if (e.key === 'Home') { e.preventDefault(); goTo(0); }
else if (e.key === 'End') { e.preventDefault(); goTo(total - 1); }
});
// Touch/swipe
let touchStartX = 0;
let touchStartY = 0;
document.addEventListener('touchstart', e => {
touchStartX = e.touches[0].clientX;
touchStartY = e.touches[0].clientY;
}, { passive: true });
document.addEventListener('touchend', e => {
const dx = e.changedTouches[0].clientX - touchStartX;
const dy = e.changedTouches[0].clientY - touchStartY;
if (Math.abs(dx) > Math.abs(dy) && Math.abs(dx) > 50) {
navigate(dx < 0 ? 1 : -1);
}
}, { passive: true });
// Init
goTo(0);
</script>
</body>
</html>