diff --git a/Cargo.lock b/Cargo.lock
index b2ea7932d..cefe6bfad 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -5669,6 +5669,40 @@ dependencies = [
"ureq 3.1.4",
]
+[[package]]
+name = "ospipe"
+version = "0.1.0"
+dependencies = [
+ "axum",
+ "chrono",
+ "cognitum-gate-kernel 0.1.0",
+ "console_error_panic_hook",
+ "getrandom 0.2.16",
+ "js-sys",
+ "rand 0.8.5",
+ "ruqu-algorithms",
+ "ruvector-attention 0.1.31",
+ "ruvector-cluster",
+ "ruvector-core 2.0.2",
+ "ruvector-delta-core",
+ "ruvector-filter",
+ "ruvector-gnn 2.0.2",
+ "ruvector-graph 2.0.2",
+ "ruvector-router-core",
+ "serde",
+ "serde-wasm-bindgen",
+ "serde_json",
+ "thiserror 2.0.17",
+ "tokio",
+ "tower 0.5.2",
+ "tower-http 0.6.8",
+ "tracing",
+ "tracing-subscriber",
+ "uuid",
+ "wasm-bindgen",
+ "wasm-bindgen-test",
+]
+
[[package]]
name = "owned_ttf_parser"
version = "0.15.2"
@@ -7439,7 +7473,7 @@ dependencies = [
[[package]]
name = "ruqu-algorithms"
-version = "2.0.3"
+version = "2.0.5"
dependencies = [
"approx",
"criterion 0.5.1",
@@ -7453,7 +7487,7 @@ dependencies = [
[[package]]
name = "ruqu-core"
-version = "2.0.3"
+version = "2.0.5"
dependencies = [
"approx",
"criterion 0.5.1",
@@ -7467,7 +7501,7 @@ dependencies = [
[[package]]
name = "ruqu-exotic"
-version = "2.0.3"
+version = "2.0.5"
dependencies = [
"approx",
"rand 0.8.5",
@@ -7478,7 +7512,7 @@ dependencies = [
[[package]]
name = "ruqu-wasm"
-version = "2.0.3"
+version = "2.0.5"
dependencies = [
"getrandom 0.2.16",
"js-sys",
diff --git a/Cargo.toml b/Cargo.toml
index da22f6ead..1cfa05327 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -78,6 +78,7 @@ members = [
"crates/ruqu-wasm",
"crates/ruqu-exotic",
"examples/dna",
+ "examples/OSpipe",
]
resolver = "2"
diff --git a/README.md b/README.md
index f55819c83..f6035ef78 100644
--- a/README.md
+++ b/README.md
@@ -1333,6 +1333,77 @@ let syndrome = gate.assess_coherence(&quantum_state)?;
**rvDNA Features:** 12 ms full pipeline on 5 real human genes, Bayesian variant calling (155 ns/SNP), Horvath epigenetic clock, CYP2D6 pharmacogenomics, `.rvdna` binary format with pre-computed AI features, WASM support for browser-based diagnostics. [Full README](./examples/dna/README.md)
+### Personal AI Memory (OSpipe)
+
+[](https://www.npmjs.com/package/@ruvector/ospipe)
+[](https://www.npmjs.com/package/@ruvector/ospipe-wasm)
+
+| Package | Description | Registry |
+|---------|-------------|----------|
+| [ospipe](./examples/OSpipe) | RuVector-enhanced personal AI memory for Screenpipe | [](https://crates.io/crates/ospipe) |
+| [@ruvector/ospipe](https://www.npmjs.com/package/@ruvector/ospipe) | TypeScript SDK with retry, timeout, and AbortSignal | [](https://www.npmjs.com/package/@ruvector/ospipe) |
+| [@ruvector/ospipe-wasm](https://www.npmjs.com/package/@ruvector/ospipe-wasm) | WASM bindings for browser deployment (145 KB) | [](https://www.npmjs.com/package/@ruvector/ospipe-wasm) |
+
+```bash
+npm install @ruvector/ospipe # TypeScript SDK
+npm install @ruvector/ospipe-wasm # Browser WASM
+cargo add ospipe # Rust crate
+```
+
+**Replaces Screenpipe's SQLite/FTS5 backend with semantic vector search.** Ask your computer what you saw, heard, and did -- with semantic understanding.
+
+
+OSpipe Features & Capabilities
+
+| Feature | Description |
+|---------|-------------|
+| **HNSW Vector Search** | 61us p50 query latency via `ruvector-core` |
+| **Knowledge Graph** | Entity extraction (persons, URLs, emails, mentions) via `ruvector-graph` |
+| **Attention Reranking** | Content prioritization via `ruvector-attention` |
+| **Quantum Diversity** | MMR + quantum-inspired result selection via `ruqu-algorithms` |
+| **GNN Learning** | Search quality improves over time via `ruvector-gnn` |
+| **PII Safety Gate** | Auto-redacts credit cards, SSNs, emails before storage |
+| **Frame Deduplication** | Cosine similarity sliding window eliminates near-duplicates |
+| **Query Router** | Auto-routes to Semantic, Keyword, Graph, Temporal, or Hybrid backend |
+| **4-Tier Quantization** | f32 -> int8 -> product -> binary (97% memory savings over time) |
+| **REST API** | Axum server with `/v2/search`, `/v2/route`, `/v2/stats`, `/v2/health` |
+| **WASM Support** | Runs in browser (145 KB), bundles from 11.8 KB (micro) to 350 KB (full) |
+| **Cross-Platform** | Native: Linux, macOS, Windows; WASM: any browser |
+
+**Comparison: Screenpipe vs OSpipe**
+
+| | Screenpipe (FTS5) | OSpipe (RuVector) |
+|---|---|---|
+| Search | Keyword (FTS5) | Semantic + Keyword + Graph + Temporal |
+| Latency | ~1ms (FTS5) | 61us (HNSW p50) |
+| Relations | None | Knowledge Graph (Cypher) |
+| PII | Basic | Credit card, SSN, email redaction |
+| Dedup | None | Cosine similarity sliding window |
+| Browser | None | WASM (11.8 KB - 350 KB) |
+| Quantization | None | 4-tier age-based (f32 -> binary) |
+
+**Integrates 10 RuVector crates:** ruvector-core, ruvector-filter, ruvector-cluster, ruvector-delta-core, ruvector-router-core, cognitum-gate-kernel, ruvector-graph, ruvector-attention, ruvector-gnn, ruqu-algorithms.
+
+
+
+```rust
+use ospipe::config::OsPipeConfig;
+use ospipe::pipeline::ingestion::IngestionPipeline;
+use ospipe::capture::CapturedFrame;
+
+let config = OsPipeConfig::default();
+let mut pipeline = IngestionPipeline::new(config)?;
+
+// Ingest a screen capture
+let frame = CapturedFrame::new_screen("Firefox", "Meeting Notes", "auth discussion: JWT with refresh tokens", 0);
+pipeline.ingest(frame)?;
+
+// Semantic search
+let results = pipeline.search("what was the authentication discussion?", 5)?;
+```
+
+See [OSpipe README](./examples/OSpipe/README.md) for full documentation, TypeScript/WASM quickstart, and configuration reference.
+
### Standalone Edge Database (rvLite)
| Crate | Description | crates.io |
diff --git a/examples/OSpipe/.github-ci-stub.yml b/examples/OSpipe/.github-ci-stub.yml
new file mode 100644
index 000000000..f42bb3d07
--- /dev/null
+++ b/examples/OSpipe/.github-ci-stub.yml
@@ -0,0 +1,58 @@
+# OSpipe Cross-Platform Build Matrix
+# Copy to .github/workflows/ospipe.yml to activate
+name: OSpipe Build
+on:
+ push:
+ paths: ['examples/OSpipe/**']
+ pull_request:
+ paths: ['examples/OSpipe/**']
+
+jobs:
+ build:
+ strategy:
+ fail-fast: false
+ matrix:
+ include:
+ - os: macos-latest
+ target: aarch64-apple-darwin
+ name: macOS ARM64
+ - os: macos-13
+ target: x86_64-apple-darwin
+ name: macOS x64
+ - os: windows-latest
+ target: x86_64-pc-windows-msvc
+ name: Windows x64
+ - os: ubuntu-latest
+ target: x86_64-unknown-linux-gnu
+ name: Linux x64
+ - os: ubuntu-latest
+ target: wasm32-unknown-unknown
+ name: WASM
+ runs-on: ${{ matrix.os }}
+ name: ${{ matrix.name }}
+ steps:
+ - uses: actions/checkout@v4
+ - uses: dtolnay/rust-toolchain@stable
+ with:
+ targets: ${{ matrix.target }}
+ - name: Build
+ run: cargo build -p ospipe --target ${{ matrix.target }} --release
+ - name: Test
+ run: cargo test -p ospipe
+ if: matrix.target != 'wasm32-unknown-unknown'
+ - name: Upload artifact
+ uses: actions/upload-artifact@v4
+ if: matrix.target != 'wasm32-unknown-unknown'
+ with:
+ name: ospipe-${{ matrix.target }}
+ path: |
+ target/${{ matrix.target }}/release/libospipe*
+ target/${{ matrix.target }}/release/ospipe*
+ if-no-files-found: ignore
+ - name: Upload WASM artifact
+ uses: actions/upload-artifact@v4
+ if: matrix.target == 'wasm32-unknown-unknown'
+ with:
+ name: ospipe-wasm
+ path: target/wasm32-unknown-unknown/release/ospipe.wasm
+ if-no-files-found: ignore
diff --git a/examples/OSpipe/ADR-OSpipe-screenpipe-integration.md b/examples/OSpipe/ADR-OSpipe-screenpipe-integration.md
new file mode 100644
index 000000000..dae9952d2
--- /dev/null
+++ b/examples/OSpipe/ADR-OSpipe-screenpipe-integration.md
@@ -0,0 +1,1986 @@
+# ADR-029: RuVector + Screenpipe (OSpipe) Integration Architecture
+
+**Status**: Proposed
+**Date**: 2026-02-12
+**Parent**: ADR-001 RuVector Core Architecture
+**Authors**: ruv.io, RuVector Architecture Team
+**Deciders**: Architecture Review Board
+**SDK**: Claude-Flow
+
+## Version History
+
+| Version | Date | Author | Changes |
+|---------|------|--------|---------|
+| 0.1 | 2026-02-12 | ruv.io | Initial integration architecture proposal |
+| 0.2 | 2026-02-12 | ruv.io | Added ruvllm local LLM, ruvector-cluster, ruvector-postgres, security architecture, Linux plan, backward compatibility, API versioning, WASM inventory, FFI router, ruvbot agents, burst-scaling, agentic capabilities |
+
+---
+
+## Abstract
+
+This ADR defines the integration architecture for combining **Screenpipe** -- an open-source, local-first desktop recording and AI memory system -- with the **RuVector** ecosystem of 70+ Rust crates and 50+ npm packages. The resulting system, codenamed **OSpipe**, replaces Screenpipe's SQLite + FTS5 storage backend with RuVector's SIMD-accelerated HNSW vector database, enriches its capture pipeline with graph neural networks, attention mechanisms, quantum-enhanced search, and delta-behavior tracking, and extends its platform reach through NAPI-RS native bindings and WASM modules targeting Windows and macOS.
+
+---
+
+## 1. Context
+
+### 1.1 The Personal AI Memory Problem
+
+Desktop operating systems generate an extraordinary volume of information: screen content, spoken words, typed text, application context switches, notifications, meetings, code sessions, design reviews. Current approaches to capturing and querying this data fall into two categories:
+
+1. **Keyword search** (e.g., Spotlight, Windows Search): Fast but semantically shallow. Searching for "budget discussion" will not find a screenshot of a spreadsheet or a spoken conversation about finances.
+2. **Cloud-based AI memory** (e.g., Recall, Rewind.ai): Powerful semantic search but introduces privacy risks, requires internet, and depends on proprietary services.
+
+Screenpipe occupies a unique position: it captures screen and audio locally, performs OCR and transcription on-device, and stores everything in a local SQLite database. However, its search is limited to FTS5 full-text matching -- it lacks true semantic vector search, relationship graphs between content, temporal pattern detection, and the kind of hardware-accelerated performance needed for real-time AI-augmented workflows.
+
+RuVector provides exactly these capabilities: sub-millisecond HNSW vector search (61us p50), graph neural networks for relationship learning, attention mechanisms for content prioritization, and cross-platform deployment via NAPI-RS and WASM.
+
+### 1.2 Why Integrate
+
+| Gap in Screenpipe | RuVector Solution | Crate/Package |
+|-------------------|-------------------|---------------|
+| FTS5 keyword-only search | SIMD-accelerated semantic vector search (HNSW) | `ruvector-core` |
+| No content relationships | Hypergraph knowledge graph with Cypher queries | `ruvector-graph` |
+| No temporal pattern detection | Delta-behavior change tracking with causal ordering | `ruvector-delta-core`, `ruvector-delta-index` |
+| No content prioritization | Multi-head attention for relevance scoring | `ruvector-attention` |
+| No learned search improvement | GNN layers that improve retrieval over time | `ruvector-gnn` |
+| Basic OCR text extraction | Scientific OCR with LaTeX/MathML extraction | `@ruvector/scipix` |
+| No hierarchy-aware search | Hyperbolic embeddings for app/window/tab hierarchies | `ruvector-hyperbolic-hnsw` |
+| No edge/WASM deployment | Neuromorphic HNSW in 11.8KB WASM | `micro-hnsw-wasm` |
+| No AI safety guardrails | Coherence gate for content safety decisions | `cognitum-gate-kernel` |
+| No intelligent routing | Neural router for query-type classification | `ruvector-router-core`, `@ruvector/tiny-dancer` |
+| No distributed sync | CRDT-based delta consensus across devices | `ruvector-delta-consensus` |
+| No quantum-enhanced search | Grover-inspired amplitude amplification for search | `ruqu-algorithms` |
+| Requires external LLM (Ollama/OpenAI) | On-device GGUF inference, fully offline | `ruvllm` |
+| No frame deduplication | Clustering-based duplicate frame detection | `ruvector-cluster` |
+| No enterprise DB backend | PostgreSQL with pgvector for team deployments | `ruvector-postgres` |
+
+### 1.3 Screenpipe Project Analysis
+
+**Repository**: [github.com/screenpipe/screenpipe](https://github.com/screenpipe/screenpipe)
+**License**: MIT
+**Funding**: $2.8M (July 2025)
+**Stack**: Rust (backend), Tauri (desktop), TypeScript/React (frontend), SQLite (storage)
+
+#### Architecture Layers
+
+| Layer | Function | Technology |
+|-------|----------|------------|
+| **Capture** | Screen frames, audio streams, UI events | CoreGraphics (macOS), DXGI (Windows), X11/PipeWire (Linux) |
+| **Processing** | OCR, speech-to-text, speaker ID, PII redaction | Apple Vision / Windows OCR / Tesseract, Whisper, Deepgram |
+| **Storage** | Structured data, media files | SQLite (`~/.screenpipe/db.sqlite`), MP4/MP3 files (`~/.screenpipe/data/`) |
+| **API** | REST endpoints, raw SQL, streaming | localhost:3030 (`/search`, `/frames/{id}`, `/health`, `/raw_sql`) |
+| **Extension** | Pipes (plugins), MCP server, SDK | TypeScript via Bun, `@screenpipe/js`, Next.js pipe templates |
+
+#### Key Database Tables
+
+| Table | Purpose |
+|-------|---------|
+| `frames` | Screen capture metadata (timestamp, monitor, app, window) |
+| `ocr_results` | Extracted text from screen frames |
+| `audio_chunks` | Audio recording metadata and file references |
+| `transcriptions` | Speech-to-text results |
+| `speakers` | Identified speaker profiles |
+| `tags` | User annotations and labels |
+
+#### Resource Profile
+
+| Metric | Value |
+|--------|-------|
+| CPU usage | 5-15% typical |
+| RAM | 0.5-3 GB |
+| Storage | ~30 GB/month at 1 FPS (M3 MacBook Pro) |
+| Frame rate | 1.0 FPS default (macOS: 0.5 FPS) |
+| Audio chunks | 30-second intervals |
+
+#### Pipe System
+
+Screenpipe pipes are sandboxed TypeScript/JavaScript plugins stored in `~/.screenpipe/pipes/{name}/`. They operate on a cron-like schedule, query the REST API, and can trigger actions (write notes, send notifications, update external systems). The SDK (`@screenpipe/js`) provides:
+
+- `pipe.queryScreenpipe()` -- Filtered content retrieval
+- `pipe.streamVision()` -- Real-time streaming of vision events
+- MCP server integration for Claude Desktop, Cursor, VS Code
+
+---
+
+## 2. RuVector Capabilities Mapping
+
+This section maps every relevant RuVector crate and package to specific Screenpipe integration points. Crate paths reference `/workspaces/ruvector/crates/` and npm packages reference `/workspaces/ruvector/npm/packages/`.
+
+### 2.1 Core Vector Storage and Search
+
+#### `ruvector-core` -- Primary Embedding Store
+
+**Path**: `crates/ruvector-core`
+**Role**: Replaces SQLite FTS5 as the primary search backend for OCR text and audio transcription embeddings.
+
+| Feature | Application in OSpipe |
+|---------|----------------------|
+| HNSW index (M=32, ef=200) | Semantic nearest-neighbor search across all captured text |
+| SIMD distance (AVX2/NEON) | Hardware-accelerated cosine similarity on embedding vectors |
+| Tiered quantization (4x-32x) | Compress month-old embeddings to reduce 30 GB/month footprint |
+| Filtered search | Metadata filters: time range, app name, monitor, content type |
+| Hybrid search (dense + BM25) | Combine semantic understanding with keyword precision |
+| MMR (Maximal Marginal Relevance) | Deduplicate near-identical consecutive screenshots |
+| Conformal prediction | Uncertainty bounds on search result confidence |
+
+**Integration point**: Embeddings generated from OCR text and audio transcriptions are inserted into an HNSW index. The existing `/search` REST endpoint is augmented with a `mode=semantic` parameter that routes to RuVector instead of FTS5.
+
+#### `ruvector-collections` -- Multi-Index Management
+
+**Path**: `crates/ruvector-collections`
+**Role**: Manages separate collections per content type (screen text, audio, UI events) with different embedding dimensions and quantization policies.
+
+#### `ruvector-filter` -- Advanced Metadata Filtering
+
+**Path**: `crates/ruvector-filter`
+**Role**: Enables complex compound filters on vector search results: `app = "VS Code" AND timestamp > "2026-02-01" AND monitor = 2`.
+
+### 2.2 Graph and Relationship Intelligence
+
+#### `ruvector-graph` -- Knowledge Graph
+
+**Path**: `crates/ruvector-graph`
+**npm**: `npm/packages/graph-node` (NAPI-RS) and `npm/packages/graph-wasm` (WASM)
+**Role**: Builds a persistent knowledge graph connecting related screen content.
+
+| Graph Entity | Node Type | Example |
+|-------------|-----------|---------|
+| Application | `:App` | VS Code, Chrome, Slack |
+| Window/Tab | `:Window` | "PR #1234 - GitHub", "Budget.xlsx" |
+| Person | `:Person` | Speaker from audio, @mention in text |
+| Topic | `:Topic` | Extracted via NER/topic modeling |
+| Meeting | `:Meeting` | Time-bounded audio + screen cluster |
+| Code Symbol | `:Symbol` | Function name seen in IDE capture |
+
+**Relationships**: `(:Person)-[:DISCUSSED]->(:Topic)`, `(:App)-[:SHOWED]->(:Window)`, `(:Meeting)-[:INVOLVED]->(:Person)`, `(:Window)-[:REFERENCES]->(:Symbol)`
+
+**Cypher queries** enable powerful contextual search:
+```cypher
+MATCH (p:Person)-[:DISCUSSED]->(t:Topic {name: "budget"})
+WHERE p.last_seen > datetime("2026-02-01")
+RETURN p.name, count(t) ORDER BY count(t) DESC
+```
+
+#### `ruvector-gnn` -- Graph Neural Network Layer
+
+**Path**: `crates/ruvector-gnn`
+**npm**: `npm/packages/graph-node` (includes GNN bindings)
+**Role**: Learns relationship patterns between content nodes to improve retrieval relevance over time.
+
+| GNN Application | Description |
+|-----------------|-------------|
+| Link prediction | Predict which apps/windows are likely viewed together |
+| Node classification | Auto-categorize content into work/personal/creative |
+| Community detection | Identify project clusters across applications |
+| Temporal GNN | Learn daily workflow patterns for proactive suggestions |
+
+#### `ruvector-mincut` -- Network Analysis
+
+**Path**: `crates/ruvector-mincut`
+**Role**: Dynamic min-cut analysis identifies natural topic boundaries in continuous screen recording streams. When the min-cut value drops below a threshold, it signals a context switch (e.g., user moved from coding to email).
+
+### 2.3 Attention and Prioritization
+
+#### `ruvector-attention` -- Multi-Head Attention
+
+**Path**: `crates/ruvector-attention`
+**npm**: `npm/packages/tiny-dancer` (neural routing with attention)
+**Role**: Content prioritization and relevance scoring.
+
+| Attention Mechanism | OSpipe Application |
+|--------------------|--------------------|
+| Geometric attention | Spatial layout analysis of screen regions |
+| Graph attention | Weighted traversal of knowledge graph |
+| Sparse attention | Efficient processing of long temporal sequences |
+| Cross-attention | Align screen content with concurrent audio |
+
+**Key use case**: When a user searches for "that email about the contract", cross-attention between the query embedding and the temporal stream of screen + audio embeddings identifies the most relevant moment, even if the word "contract" never appeared on screen (but was spoken in a concurrent call).
+
+#### `ruvector-nervous-system` -- Bio-Inspired Processing
+
+**Path**: `crates/ruvector-nervous-system`
+**Role**: Spiking neural network (SNN) with BTSP learning and EWC plasticity for always-on background processing of the capture stream.
+
+| SNN Feature | Application |
+|-------------|-------------|
+| Spike-timing dependent plasticity (STDP) | Learn temporal correlations between screen events |
+| Elastic Weight Consolidation (EWC) | Prevent forgetting learned patterns as new data arrives |
+| Winner-take-all circuits | Competitive selection of most salient content per frame |
+| LIF neurons | Energy-efficient continuous processing on CPU |
+
+### 2.4 Temporal and Delta Tracking
+
+#### `ruvector-delta-core` -- Behavioral Change Detection
+
+**Path**: `crates/ruvector-delta-core`
+**Role**: Models screen content changes as first-class delta objects rather than full-frame snapshots.
+
+Instead of storing every OCR result as an independent record, the delta system computes what changed between consecutive frames:
+
+```
+Frame N: "function calculateTotal(items) { return items.reduce(...) }"
+Frame N+1: "function calculateTotal(items, tax) { return items.reduce(...) * tax }"
+Delta: { position: 35, removed: ")", added: ", tax)", position: 72, added: " * tax" }
+```
+
+This reduces storage by 60-80% for static content (e.g., reading a document) and enables temporal queries: "Show me all code changes in VS Code between 2pm and 4pm."
+
+#### `ruvector-delta-index` -- Delta-Aware HNSW
+
+**Path**: `crates/ruvector-delta-index`
+**Role**: HNSW index that supports incremental updates via deltas rather than full re-embedding, reducing compute cost for minor text changes.
+
+#### `ruvector-delta-consensus` -- Cross-Device Sync
+
+**Path**: `crates/ruvector-delta-consensus`
+**Role**: CRDT-based distributed consensus for synchronizing OSpipe data across multiple devices (work laptop + home desktop) without a central server.
+
+#### `ruvector-delta-graph` -- Graph Delta Operations
+
+**Path**: `crates/ruvector-delta-graph`
+**Role**: Incremental updates to the knowledge graph as new content is captured, without rebuilding the entire graph.
+
+#### `ruvector-temporal-tensor` -- Temporal Compression
+
+**Path**: `crates/ruvector-temporal-tensor`
+**Role**: Tiered temporal compression for embedding storage:
+
+| Age | Compression | Latency | Storage |
+|-----|-------------|---------|---------|
+| < 1 hour | None (f32) | 61us | 100% |
+| 1-24 hours | Scalar (u8) | ~70us | 25% |
+| 1-7 days | Product quantization | ~100us | 6-12% |
+| 7-30 days | Binary quantization | ~1ms | 3% |
+| > 30 days | Archive + delta only | ~10ms | <1% |
+
+### 2.5 Quantum-Enhanced Search
+
+#### `ruqu-core` -- Quantum Circuit Simulation
+
+**Path**: `crates/ruqu-core`
+**Role**: State-vector quantum circuit simulation with SIMD acceleration for enhanced search algorithms.
+
+#### `ruqu-algorithms` -- Quantum Search Algorithms
+
+**Path**: `crates/ruqu-algorithms`
+**Role**: Production-ready quantum-inspired algorithms applicable to OSpipe:
+
+| Algorithm | Application |
+|-----------|-------------|
+| Grover's search | Amplitude amplification for searching unstructured screen data |
+| QAOA | Optimization of graph traversal paths in knowledge graph |
+| VQE | Variational eigensolver for topic clustering of captured content |
+
+#### `ruqu-exotic` -- Quantum-Classical Hybrids
+
+**Path**: `crates/ruqu-exotic`
+**Role**: Experimental quantum-classical hybrid algorithms for AI-enhanced search:
+
+- **Quantum memory decay**: Natural forgetting of irrelevant screen captures
+- **Interference search**: Quantum interference patterns for multi-modal query resolution
+- **Reasoning error correction**: Surface code-inspired error correction for search result consistency
+
+### 2.6 Routing and Intelligence
+
+#### `ruvector-router-core` -- Neural Query Router
+
+**Path**: `crates/ruvector-router-core`
+**npm**: `npm/packages/router`
+**Role**: Routes incoming search queries to the optimal backend based on query characteristics.
+
+| Query Type | Route | Backend |
+|-----------|-------|---------|
+| Exact keyword | FTS5 | SQLite (legacy) |
+| Semantic similarity | HNSW | `ruvector-core` |
+| Relationship query | Cypher | `ruvector-graph` |
+| Temporal pattern | Delta replay | `ruvector-delta-core` |
+| Multi-modal | Cross-attention | `ruvector-attention` |
+
+#### `@ruvector/tiny-dancer` -- Agent Orchestration Router
+
+**Path**: `npm/packages/tiny-dancer`
+**Role**: FastGRNN-based neural router with circuit breaker, uncertainty estimation, and hot-reload for routing pipe requests to appropriate processing backends.
+
+#### `sona` -- Self-Optimizing Neural Architecture
+
+**Path**: `crates/sona`
+**npm**: `npm/packages/sona`
+**Role**: Runtime-adaptive learning for the query router. SONA learns from user search patterns to improve routing accuracy over time:
+
+- **Two-tier LoRA**: Lightweight adaptation layers for user-specific preferences
+- **EWC++**: Prevents catastrophic forgetting when learning new patterns
+- **ReasoningBank**: Trajectory-based learning from search outcomes
+- **Sub-millisecond overhead**: <0.05ms adaptation latency
+
+### 2.7 Specialized Processing
+
+#### `@ruvector/scipix` -- Scientific OCR
+
+**Path**: `npm/packages/scipix`
+**Role**: Extends Screenpipe's OCR capabilities for scientific and technical content:
+
+- LaTeX equation extraction from screen captures
+- MathML conversion for mathematical notation
+- Technical diagram recognition
+- Research paper structure extraction
+
+When a user captures a screen showing a research paper or whiteboard equation, SciPix provides structured extraction that goes beyond raw OCR text.
+
+#### `@ruvector/rvdna` -- Genomic Analysis (Health Monitoring)
+
+**Path**: `npm/packages/rvdna`
+**Role**: For health-monitoring OSpipe pipes. If the user is a researcher viewing genomic data, rvDNA can:
+
+- Parse .rvdna format files captured on screen
+- Perform variant calling on captured genomic visualizations
+- HNSW vector search over protein sequence embeddings
+
+#### `@ruvector/spiking-neural` -- Spiking Neural Networks
+
+**Path**: `npm/packages/spiking-neural`
+**Role**: Energy-efficient continuous background processing of the capture stream using biologically-inspired spiking neural networks. Ideal for always-on pattern detection with minimal CPU impact.
+
+#### `ruvector-fpga-transformer` -- Deterministic Latency Processing
+
+**Path**: `crates/ruvector-fpga-transformer`
+**Role**: For enterprise OSpipe deployments requiring guaranteed latency bounds on search queries. The FPGA transformer backend provides deterministic processing times with quantization-first design.
+
+### 2.8 Infrastructure and Safety
+
+#### `ruvector-raft` -- Distributed Consensus
+
+**Path**: `crates/ruvector-raft`
+**Role**: Raft consensus for multi-device OSpipe clusters where a family or team shares a coordinated memory system.
+
+#### `ruvector-replication` -- Data Replication
+
+**Path**: `crates/ruvector-replication`
+**Role**: Replicates vector indices across devices for redundancy and faster local search.
+
+#### `ruvector-snapshot` -- Point-in-Time Backup
+
+**Path**: `crates/ruvector-snapshot`
+**Role**: Consistent snapshots of the vector index for backup and recovery.
+
+#### `cognitum-gate-kernel` -- AI Safety Gate
+
+**Path**: `crates/cognitum-gate-kernel`
+**npm**: `npm/packages/cognitum-gate-wasm`
+**Role**: Real-time permit/defer/deny decisions for content safety:
+
+- Prevent storage of detected sensitive content (credit cards, SSNs)
+- Gate pipe access to specific content categories
+- Enforce PII redaction policies before vector storage
+- Coherence verification on search results
+
+#### `prime-radiant` -- Coherence Engine
+
+**Path**: `crates/prime-radiant`
+**Role**: Sheaf Laplacian mathematics for structural consistency verification. Ensures that knowledge graph updates maintain logical coherence and detects hallucinated relationships.
+
+#### `mcp-gate` -- MCP Protocol Server
+
+**Path**: `crates/mcp-gate`
+**Role**: Production MCP server implementation that exposes OSpipe capabilities to Claude Desktop, Cursor, VS Code, and other MCP-compatible AI assistants.
+
+#### `ruvector-server` -- REST API Server
+
+**Path**: `crates/ruvector-server`
+**Role**: High-performance REST API server that can either replace or augment Screenpipe's existing localhost:3030 API with vector-aware endpoints.
+
+#### `ruvector-metrics` -- Observability
+
+**Path**: `crates/ruvector-metrics`
+**Role**: Prometheus-compatible metrics for monitoring OSpipe performance, query latency, index health, and storage utilization.
+
+### 2.9 Edge and WASM Deployment
+
+#### `micro-hnsw-wasm` -- Ultra-Lightweight Vector Search
+
+**Path**: `crates/micro-hnsw-wasm`
+**Role**: 11.8KB WASM module with neuromorphic HNSW for in-browser OSpipe pipes. Features LIF neurons, STDP learning, and winner-take-all selection.
+
+#### `ruvector-wasm` -- Full WASM Vector DB
+
+**Path**: `crates/ruvector-wasm`
+**npm**: `npm/packages/ruvector-wasm`
+**Role**: Complete vector database in WASM for pipes running in the browser-based pipe editor.
+
+#### `ruvector-dag` -- Query Plan Optimization
+
+**Path**: `crates/ruvector-dag`
+**Role**: DAG-based query plan optimization with neural learning for complex multi-step OSpipe queries.
+
+#### `ruvector-hyperbolic-hnsw` -- Hierarchy-Aware Search
+
+**Path**: `crates/ruvector-hyperbolic-hnsw`
+**Role**: Poincare ball model embeddings for hierarchy-aware search. Maps the natural hierarchy of OS > App > Window > Tab > Content into hyperbolic space where hierarchical distance is preserved.
+
+#### `ruvector-sparse-inference` -- Edge Inference
+
+**Path**: `crates/ruvector-sparse-inference`
+**Role**: PowerInfer-style sparse inference for efficient neural network inference on edge devices. Enables local embedding generation without GPU.
+
+#### `rvlite` -- Standalone Lightweight DB
+
+**Path**: `crates/rvlite`
+**npm**: `npm/packages/rvlite`
+**Role**: Standalone vector database with SQL, SPARQL, and Cypher support. Can serve as a drop-in replacement for Screenpipe's SQLite while adding vector capabilities.
+
+### 2.10 Learning and Adaptation
+
+#### `ruvector-learning-wasm` -- MicroLoRA Adaptation
+
+**Path**: `crates/ruvector-learning-wasm`
+**Role**: Ultra-fast MicroLoRA adaptation in WASM (<100us latency) for per-user learning of search preferences and content relevance.
+
+#### `ruvector-economy-wasm` -- Compute Economy
+
+**Path**: `crates/ruvector-economy-wasm`
+**Role**: CRDT-based autonomous credit economy for distributed OSpipe networks where multiple users contribute compute resources.
+
+#### `ruvector-exotic-wasm` -- Emergent Behavior
+
+**Path**: `crates/ruvector-exotic-wasm`
+**Role**: Exotic AI mechanisms for emergent behavior in multi-agent pipe systems:
+
+- Neural Autonomous Orgs for pipe governance
+- Morphogenetic Networks for adaptive UI
+- Time Crystals for periodic pattern detection
+
+### 2.11 Local LLM Inference
+
+#### `ruvllm` -- On-Device Language Model Inference
+
+**Path**: `crates/ruvllm`
+**npm**: `npm/packages/ruvllm` + 5 platform-specific binary packages
+**Role**: GGUF-based local LLM inference for on-device summarization, embedding generation, and pipe intelligence -- without any external API dependency.
+
+| Feature | Application in OSpipe |
+|---------|----------------------|
+| GGUF model loading | Load quantized LLMs (Q4_K_M, Q5_K_M) for on-device inference |
+| Embedding generation | Replace external APIs for embedding -- fully offline operation |
+| Text summarization | Summarize captured screen sessions, meetings, and code activity |
+| Classification | Classify captured content into categories (work, personal, sensitive) |
+| Named Entity Recognition | Extract people, organizations, projects from OCR/transcription text |
+| Pipe intelligence | Power autonomous pipe decision-making without cloud LLM calls |
+
+**Platform binaries** (pre-built NAPI-RS):
+
+| Platform | Package |
+|----------|---------|
+| macOS ARM64 | `npm/packages/ruvllm-darwin-arm64` |
+| macOS x64 | `npm/packages/ruvllm-darwin-x64` |
+| Windows x64 | `npm/packages/ruvllm-win32-x64-msvc` |
+| Linux ARM64 | `npm/packages/ruvllm-linux-arm64-gnu` |
+| Linux x64 | `npm/packages/ruvllm-linux-x64-gnu` |
+
+**WASM fallback**: `npm/packages/ruvllm-wasm` for browser-based pipes.
+
+**Integration point**: RuvLLM replaces the current Ollama/OpenAI dependency for pipes that need LLM capabilities, making OSpipe fully self-contained and offline-capable.
+
+```typescript
+import { RuvLLM } from "@ruvector/ruvllm";
+
+const llm = new RuvLLM({ model: "ruvltra-0.5b-q4_k_m.gguf" });
+
+// Summarize a capture session
+const summary = await llm.generate({
+ prompt: `Summarize this screen activity:\n${ocrText}`,
+ maxTokens: 200,
+});
+
+// Generate embeddings locally (no API needed)
+const embedding = await llm.embed(ocrText); // 384-dim vector
+```
+
+#### `ruvllm-cli` -- CLI for Model Management
+
+**Path**: `crates/ruvllm-cli`
+**Role**: Download, manage, and test GGUF models for OSpipe deployment.
+
+### 2.12 Clustering and Frame Deduplication
+
+#### `ruvector-cluster` -- Content Clustering
+
+**Path**: `crates/ruvector-cluster`
+**Role**: Groups similar screen captures, deduplicates near-identical consecutive frames, and auto-categorizes content into sessions.
+
+| Feature | Application in OSpipe |
+|---------|----------------------|
+| K-means clustering | Group similar screenshots into activity sessions |
+| DBSCAN | Density-based detection of content clusters without predefined K |
+| Hierarchical clustering | Multi-level grouping: project > task > sub-task |
+| Frame deduplication | Detect and skip near-identical consecutive frames (static content) |
+| Session segmentation | Automatic work session boundaries from capture stream |
+
+**Key use case**: When the user is reading a document for 30 minutes, `ruvector-cluster` detects that consecutive frames are >95% similar and stores only the first frame + a duration marker, reducing storage by 90%+ for static reading sessions.
+
+### 2.13 Advanced Attention and Gated Transformers
+
+#### `ruvector-mincut-gated-transformer` -- Gated Transformer with MinCut Attention
+
+**Path**: `crates/ruvector-mincut-gated-transformer`
+**npm WASM**: `crates/ruvector-mincut-gated-transformer-wasm`
+**Role**: Advanced gated transformer architecture combining MinCut-based attention with learned gating for superior context-switch detection and content segmentation.
+
+| Feature | Application in OSpipe |
+|---------|----------------------|
+| Gated MinCut attention | Detect context switches with learned gating thresholds |
+| Multi-scale segmentation | Identify topic changes at sentence, paragraph, and session level |
+| Cross-modal gating | Gate attention between screen and audio modalities |
+
+#### `ruvector-attention-unified-wasm` -- Unified Attention in WASM
+
+**Path**: `crates/ruvector-attention-unified-wasm`
+**Role**: All attention mechanisms (geometric, graph, sparse, cross) compiled to a single WASM module for browser-based pipes.
+
+### 2.14 Enterprise and Database Backends
+
+#### `ruvector-postgres` -- PostgreSQL Backend
+
+**Path**: `crates/ruvector-postgres`
+**npm**: `npm/packages/postgres-cli`
+**Role**: PostgreSQL-backed vector storage for enterprise OSpipe deployments. Replaces the local HNSW index with pgvector for centralized team deployments.
+
+| Feature | Application in OSpipe |
+|---------|----------------------|
+| pgvector integration | Server-side vector search with PostgreSQL |
+| Team deployment | Shared OSpipe instance for organizations |
+| Backup/recovery | Leverage PostgreSQL's mature backup tooling |
+| Access control | Row-level security for multi-user capture data |
+
+### 2.15 Agentic Capabilities
+
+#### `agentic-integration` -- Autonomous Pipe Orchestration
+
+**Path**: `npm/packages/agentic-integration`
+**Role**: Framework for building autonomous, self-orchestrating OSpipe pipes that can chain operations, make decisions, and coordinate with other pipes.
+
+#### `agentic-synth` -- Synthetic Data Generation
+
+**Path**: `npm/packages/agentic-synth`
+**Role**: Generate synthetic screen capture data for testing OSpipe pipes without requiring real user data. Essential for CI/CD and privacy-safe development.
+
+#### `ruvbot` -- Long-Running Agent Templates
+
+**Path**: `npm/packages/ruvbot`
+**Role**: Pre-built agent templates for persistent OSpipe pipes. Deploy always-on agents that monitor capture streams, generate summaries, trigger notifications, and learn from user behavior.
+
+| Template | Application |
+|----------|-------------|
+| `code-reviewer` | Monitors IDE captures and suggests improvements |
+| `meeting-summarizer` | Auto-generates meeting notes from audio + screen |
+| `research-assistant` | Builds knowledge base from browsing sessions |
+| `self-learning-bot` | Continuously improves search relevance from usage |
+
+### 2.16 Scaling and Performance
+
+#### `burst-scaling` -- Capture Load Spike Handling
+
+**Path**: `npm/packages/burst-scaling`
+**Role**: Dynamic scaling for handling capture load spikes -- rapid window switching, multi-monitor setups, high-FPS capture modes. Manages backpressure and queuing to prevent dropped frames.
+
+| Feature | Application in OSpipe |
+|---------|----------------------|
+| Backpressure management | Queue frames during CPU spikes without dropping |
+| Adaptive batch sizing | Increase embedding batch size during high-load periods |
+| Resource budgeting | Cap CPU/memory usage per-component with dynamic allocation |
+| Multi-monitor balancing | Distribute capture load across cores by monitor |
+
+### 2.17 Quantum Meta-Package
+
+#### `ruQu` -- Unified Quantum Package
+
+**Path**: `crates/ruQu`
+**Role**: Meta-crate that re-exports `ruqu-core`, `ruqu-algorithms`, and `ruqu-exotic` under a single dependency. Simplifies quantum integration for OSpipe.
+
+```toml
+[dependencies]
+ruqu = { version = "2.0.5", path = "../ruQu" }
+# Instead of adding ruqu-core, ruqu-algorithms, ruqu-exotic separately
+```
+
+### 2.18 Complete WASM Module Inventory
+
+All WASM packages available for browser-based OSpipe pipes:
+
+| Package | Size | Purpose |
+|---------|------|---------|
+| `micro-hnsw-wasm` | 11.8 KB | Ultra-lightweight vector search |
+| `ruvector-wasm` | ~200 KB | Full vector DB |
+| `ruvector-wasm-unified` | ~350 KB | All-in-one unified bundle |
+| `ruvllm-wasm` | ~2 MB | Local LLM inference |
+| `ruvector-delta-wasm` | ~50 KB | Delta behavior tracking |
+| `ruvector-math-wasm` | ~30 KB | Mathematical primitives |
+| `ruvector-hyperbolic-hnsw-wasm` | ~80 KB | Hyperbolic embeddings |
+| `ruvector-sparse-inference-wasm` | ~120 KB | Edge neural inference |
+| `ruvector-temporal-tensor-wasm` | ~60 KB | Temporal compression |
+| `ruvector-attention-unified-wasm` | ~150 KB | All attention mechanisms |
+| `ruvector-mincut-wasm` | ~40 KB | MinCut network analysis |
+| `ruvector-mincut-gated-transformer-wasm` | ~90 KB | Gated transformer |
+| `ruvector-gnn-wasm` | ~100 KB | Graph neural networks |
+| `ruvector-dag-wasm` | ~45 KB | Query plan optimization |
+| `ruvector-nervous-system-wasm` | ~70 KB | Spiking neural network |
+| `ruvector-fpga-transformer-wasm` | ~80 KB | Deterministic inference |
+| `ruvector-economy-wasm` | ~55 KB | Compute economy CRDT |
+| `ruvector-exotic-wasm` | ~65 KB | Emergent AI mechanisms |
+| `ruvector-learning-wasm` | ~45 KB | MicroLoRA adaptation |
+| `cognitum-gate-wasm` | ~25 KB | Safety gate decisions |
+| `ruqu-wasm` | ~105 KB | Quantum simulation |
+
+### 2.19 FFI and CLI Tools
+
+#### `ruvector-router-ffi` -- Foreign Function Interface
+
+**Path**: `crates/ruvector-router-ffi`
+**Role**: C-compatible FFI bindings for the query router. Allows Screenpipe's Rust backend to call the router directly without NAPI-RS overhead -- zero-copy, in-process routing.
+
+**Integration point**: Screenpipe's Rust capture engine links `ruvector-router-ffi` directly, avoiding the TypeScript → NAPI-RS → Rust round-trip for the hot path.
+
+```rust
+// In Screenpipe's Rust backend (zero-overhead)
+use ruvector_router_ffi::{route_query, QueryType};
+
+let route = route_query(query_text, QueryType::Auto);
+match route {
+ QueryType::Semantic => hnsw_search(query_embedding),
+ QueryType::Graph => cypher_query(query_text),
+ QueryType::Temporal => delta_replay(query_text),
+ QueryType::Keyword => fts5_search(query_text),
+}
+```
+
+#### `ruvector-router-cli` / `ruvector-attention-cli` -- CLI Debugging Tools
+
+**Path**: `crates/ruvector-router-cli`, `crates/ruvector-attention-cli`
+**Role**: CLI tools for debugging query routing decisions and attention scores during OSpipe development.
+
+### 2.20 Node.js and NAPI-RS Bindings
+
+#### `ruvector-node` -- Core NAPI-RS Bindings
+
+**Path**: `crates/ruvector-node`
+**npm**: `npm/packages/node`
+**Role**: Native Node.js bindings for `ruvector-core` via NAPI-RS. Provides direct access to SIMD-accelerated vector operations from Screenpipe's TypeScript pipe runtime.
+
+#### `ruvector-gnn-node` -- GNN NAPI-RS Bindings
+
+**Path**: `crates/ruvector-gnn-node`
+**Role**: Native Node.js bindings for graph neural network operations.
+
+#### `ruvector-attention-node` -- Attention NAPI-RS Bindings
+
+**Path**: `crates/ruvector-attention-node`
+**Role**: Native Node.js bindings for attention mechanism operations.
+
+#### `ruvector-graph-node` -- Graph DB NAPI-RS Bindings
+
+**Path**: `npm/packages/graph-node`
+**Role**: Native Node.js bindings for the hypergraph database. 10x faster than the WASM equivalent.
+
+#### `ruvector-tiny-dancer-node` -- Router NAPI-RS Bindings
+
+**Path**: `crates/ruvector-tiny-dancer-node`
+**Role**: Native Node.js bindings for the neural router.
+
+#### `ruvector-mincut-node` -- MinCut NAPI-RS Bindings
+
+**Path**: `crates/ruvector-mincut-node`
+**Role**: Native Node.js bindings for network analysis and context-switch detection.
+
+#### Platform-Specific NAPI-RS Binaries
+
+Pre-built binaries are available for all Screenpipe-supported platforms:
+
+| Platform | Router | RuvLLM | Tiny Dancer |
+|----------|--------|--------|-------------|
+| macOS ARM64 | `npm/packages/router-darwin-arm64` | `npm/packages/ruvllm-darwin-arm64` | `npm/packages/tiny-dancer-darwin-arm64` |
+| macOS x64 | `npm/packages/router-darwin-x64` | `npm/packages/ruvllm-darwin-x64` | `npm/packages/tiny-dancer-darwin-x64` |
+| Windows x64 | `npm/packages/router-win32-x64-msvc` | `npm/packages/ruvllm-win32-x64-msvc` | `npm/packages/tiny-dancer-win32-x64-msvc` |
+| Linux ARM64 | `npm/packages/router-linux-arm64-gnu` | `npm/packages/ruvllm-linux-arm64-gnu` | `npm/packages/tiny-dancer-linux-arm64-gnu` |
+| Linux x64 | `npm/packages/router-linux-x64-gnu` | `npm/packages/ruvllm-linux-x64-gnu` | `npm/packages/tiny-dancer-linux-x64-gnu` |
+
+---
+
+## 3. Architecture Diagrams
+
+### 3.1 Overall Integration Architecture
+
+
+Click to expand: Overall OSpipe Architecture
+
+```mermaid
+graph TB
+ subgraph "OS Layer"
+ SC[Screen Capture
CoreGraphics / DXGI]
+ AC[Audio Capture
CoreAudio / WASAPI]
+ UI[UI Events
Accessibility API]
+ end
+
+ subgraph "Screenpipe Capture Engine"
+ OCR[OCR Engine
Apple Vision / Windows OCR / Tesseract]
+ STT[Speech-to-Text
Whisper / Deepgram]
+ SPK[Speaker ID
Diarization]
+ PII[PII Redaction
Configurable]
+ end
+
+ subgraph "RuVector Processing Layer"
+ EMB[Embedding Generation
ruvllm / ruvector-sparse-inference
Local GGUF + ONNX models]
+ ATT[Attention Scoring
ruvector-attention
Content prioritization]
+ GATE[Safety Gate
cognitum-gate-kernel
PII/content filtering]
+ DELTA[Delta Extraction
ruvector-delta-core
Change detection]
+ CLUST[Frame Clustering
ruvector-cluster
Dedup + session segmentation]
+ LLM[Local LLM
ruvllm
Summarization + NER]
+ end
+
+ subgraph "RuVector Storage Layer"
+ HNSW[Vector Index
ruvector-core
HNSW + SIMD]
+ GRAPH[Knowledge Graph
ruvector-graph
Cypher queries]
+ TEMP[Temporal Store
ruvector-temporal-tensor
Tiered compression]
+ SNAP[Snapshots
ruvector-snapshot
Point-in-time backup]
+ end
+
+ subgraph "RuVector Intelligence Layer"
+ GNN[Graph Neural Net
ruvector-gnn
Relationship learning]
+ ROUTER[Query Router
ruvector-router-core
Intent classification]
+ SONA[SONA Learning
sona
Adaptive optimization]
+ SNN[Spiking Neural Net
ruvector-nervous-system
Pattern detection]
+ end
+
+ subgraph "API and Extension Layer"
+ REST[REST API
ruvector-server
localhost:3030]
+ MCP[MCP Server
mcp-gate
Claude/Cursor/VS Code]
+ SDK[TypeScript SDK
@screenpipe/js + @ruvector/node
Pipe development]
+ PIPES[Pipe Runtime
Bun + NAPI-RS bindings
Sandboxed plugins]
+ end
+
+ subgraph "Sync Layer"
+ CRDT[Delta Consensus
ruvector-delta-consensus
CRDT sync]
+ RAFT[Raft Consensus
ruvector-raft
Metadata coordination]
+ REPL[Replication
ruvector-replication
Index mirroring]
+ end
+
+ SC --> OCR
+ AC --> STT
+ AC --> SPK
+ UI --> DELTA
+
+ OCR --> PII --> GATE
+ STT --> PII
+ SPK --> GRAPH
+
+ GATE -->|Permitted| EMB
+ GATE -->|Permitted| CLUST
+ EMB --> ATT
+ CLUST -->|Unique frames| ATT
+ ATT --> HNSW
+ ATT --> GRAPH
+ DELTA --> TEMP
+ EMB --> LLM
+ LLM --> GRAPH
+
+ HNSW --> GNN
+ GRAPH --> GNN
+ GNN --> SONA
+
+ REST --> ROUTER
+ MCP --> ROUTER
+ SDK --> ROUTER
+ ROUTER --> HNSW
+ ROUTER --> GRAPH
+ ROUTER --> TEMP
+
+ PIPES --> SDK
+ SNAP --> REPL
+ CRDT --> RAFT
+```
+
+
+
+### 3.2 Data Flow Pipeline
+
+
+Click to expand: Data Flow from Capture to Query
+
+```mermaid
+sequenceDiagram
+ participant OS as Operating System
+ participant CAP as Capture Engine
+ participant PROC as Processing Pipeline
+ participant GATE as Safety Gate
+ participant EMB as Embedding Engine
+ participant DELTA as Delta Tracker
+ participant HNSW as Vector Index
+ participant GRAPH as Knowledge Graph
+ participant GNN as GNN Layer
+ participant API as REST/MCP API
+
+ Note over OS,API: Ingestion Flow (continuous, 0.5-1 FPS)
+
+ OS->>CAP: Screen frame + Audio chunk
+ CAP->>PROC: Raw frame data
+
+ par OCR Processing
+ PROC->>PROC: OCR extraction (Apple Vision / Windows OCR)
+ and Audio Processing
+ PROC->>PROC: Whisper transcription + Speaker ID
+ end
+
+ PROC->>GATE: Text content for safety check
+ GATE-->>GATE: PII detection, content policy
+
+ alt Content Permitted
+ GATE->>EMB: Clean text for embedding
+ GATE->>DELTA: Text for delta computation
+
+ EMB->>EMB: Generate 384-dim embedding (ONNX local)
+
+ par Vector Storage
+ EMB->>HNSW: Insert embedding + metadata
+ and Graph Update
+ EMB->>GRAPH: Create/update entity nodes
+ and Delta Storage
+ DELTA->>DELTA: Compute diff from previous frame
+ DELTA-->>HNSW: Store only if significant change
+ end
+
+ HNSW->>GNN: Periodic batch: learn from access patterns
+ GRAPH->>GNN: Periodic batch: learn from graph structure
+ else Content Denied
+ GATE-->>GATE: Log denial, skip storage
+ end
+
+ Note over OS,API: Query Flow (on-demand)
+
+ API->>API: Receive search query
+ API->>EMB: Generate query embedding
+
+ alt Semantic Search
+ EMB->>HNSW: k-NN search (k=10, ef=100)
+ HNSW-->>API: Ranked results with distances
+ else Graph Query
+ API->>GRAPH: Cypher query execution
+ GRAPH-->>API: Relationship-aware results
+ else Temporal Query
+ API->>DELTA: Reconstruct state at timestamp T
+ DELTA-->>API: Historical state via delta replay
+ else Hybrid
+ EMB->>HNSW: Semantic candidates
+ HNSW->>GRAPH: Enrich with graph context
+ GRAPH-->>API: Combined results
+ end
+```
+
+
+
+### 3.3 Platform-Specific Deployment
+
+
+Click to expand: Windows and macOS Deployment Architecture
+
+```mermaid
+graph LR
+ subgraph "macOS Deployment"
+ direction TB
+ M_CAP[Screen Capture
ScreenCaptureKit / CoreGraphics]
+ M_OCR[OCR
Apple Vision Framework]
+ M_GPU[GPU Acceleration
Metal Performance Shaders]
+ M_NEON[SIMD
ARM64 NEON intrinsics]
+ M_SIGN[Code Signing
Apple Notarization]
+ M_TRAY[Menu Bar App
Tauri + SwiftUI]
+ M_PERM[Permissions
Screen Recording + Accessibility]
+ M_UB[Universal Binary
x86_64 + arm64 fat binary]
+
+ M_CAP --> M_OCR
+ M_OCR --> M_GPU
+ M_GPU --> M_NEON
+ M_SIGN --> M_TRAY
+ M_PERM --> M_CAP
+ end
+
+ subgraph "Windows Deployment"
+ direction TB
+ W_CAP[Screen Capture
DXGI Desktop Duplication]
+ W_OCR[OCR
Windows.Media.Ocr / Tesseract]
+ W_GPU[GPU Acceleration
DirectML]
+ W_AVX[SIMD
x86_64 AVX2/AVX-512]
+ W_SIGN[Code Signing
Authenticode]
+ W_TRAY[System Tray
Tauri + WinUI]
+ W_PERM[Permissions
UAC + Screen Access]
+ W_MSVC[Build Target
x86_64-pc-windows-msvc]
+
+ W_CAP --> W_OCR
+ W_OCR --> W_GPU
+ W_GPU --> W_AVX
+ W_SIGN --> W_TRAY
+ W_PERM --> W_CAP
+ end
+
+ subgraph "Shared NAPI-RS Layer"
+ direction TB
+ N_CORE["@ruvector/core
Vector DB bindings"]
+ N_ROUTER["@ruvector/router
Query routing"]
+ N_GRAPH["@ruvector/graph-node
Knowledge graph"]
+ N_TD["@ruvector/tiny-dancer
Neural router"]
+ N_SONA["@ruvector/sona
Adaptive learning"]
+ end
+
+ M_NEON --> N_CORE
+ W_AVX --> N_CORE
+ N_CORE --> N_ROUTER
+ N_CORE --> N_GRAPH
+ N_ROUTER --> N_TD
+ N_TD --> N_SONA
+```
+
+
+
+### 3.4 Pipe Architecture with RuVector
+
+
+Click to expand: Enhanced Pipe System Architecture
+
+```mermaid
+graph TB
+ subgraph "Pipe Runtime (Bun)"
+ P1[Meeting Summarizer Pipe]
+ P2[Code Activity Tracker Pipe]
+ P3[Research Assistant Pipe]
+ P4[Health Monitor Pipe]
+ P5[Custom User Pipe]
+ end
+
+ subgraph "OSpipe SDK (@screenpipe/js + @ruvector/node)"
+ QSP[queryScreenpipe
Original API]
+ QRV[queryRuVector
Semantic search]
+ QGR[queryGraph
Cypher queries]
+ QDT[queryDelta
Temporal queries]
+ STR[streamVision
Real-time events]
+ STA[streamAttention
Prioritized events]
+ end
+
+ subgraph "NAPI-RS Bindings (Native Performance)"
+ BN_CORE["ruvector-node
Vector operations"]
+ BN_GNN["ruvector-gnn-node
Graph learning"]
+ BN_ATT["ruvector-attention-node
Attention scoring"]
+ BN_GRAPH["ruvector-graph-node
Hypergraph DB"]
+ BN_MC["ruvector-mincut-node
Context detection"]
+ BN_TD["ruvector-tiny-dancer-node
Neural routing"]
+ end
+
+ subgraph "WASM Fallback (Browser Pipes)"
+ W_HNSW["micro-hnsw-wasm
11.8KB vector search"]
+ W_GATE["@cognitum/gate
Safety decisions"]
+ W_LEARN["ruvector-learning-wasm
MicroLoRA"]
+ W_RVLITE["rvlite
SQL + Cypher"]
+ end
+
+ P1 --> QRV
+ P1 --> QGR
+ P2 --> QDT
+ P2 --> STA
+ P3 --> QRV
+ P3 --> QGR
+ P4 --> STR
+ P5 --> QSP
+
+ QRV --> BN_CORE
+ QGR --> BN_GRAPH
+ QDT --> BN_CORE
+ STA --> BN_ATT
+ STR --> BN_CORE
+
+ QRV -.->|Browser fallback| W_HNSW
+ QGR -.->|Browser fallback| W_RVLITE
+```
+
+
+
+---
+
+## 4. Windows Integration Plan
+
+### 4.1 Screen Capture Pipeline
+
+**Screenpipe's existing approach**: DXGI Desktop Duplication API for screen capture, Windows.Media.Ocr for text extraction.
+
+**OSpipe enhancement**:
+
+| Component | Technology | Purpose |
+|-----------|------------|---------|
+| Capture | DXGI `IDXGIOutputDuplication` | Zero-copy GPU-to-CPU frame transfer |
+| GPU preprocessing | DirectML | Resize/normalize frames on GPU before OCR |
+| OCR primary | Windows.Media.Ocr (WinRT) | Native Windows OCR with language detection |
+| OCR fallback | Tesseract via `leptonica` | Cross-platform fallback |
+| Scientific OCR | `@ruvector/scipix` | LaTeX/MathML extraction for technical content |
+
+### 4.2 NAPI-RS Bindings for Windows
+
+Pre-built native binaries are already available for Windows x64:
+
+| Package | Binary | Size |
+|---------|--------|------|
+| `@ruvector/router` | `router-win32-x64-msvc` | Pre-built |
+| `@ruvector/ruvllm` | `ruvllm-win32-x64-msvc` | Pre-built |
+| `@ruvector/tiny-dancer` | `tiny-dancer-win32-x64-msvc` | Pre-built |
+
+**Build configuration** for Windows-specific crates:
+
+```toml
+[target.x86_64-pc-windows-msvc]
+rustflags = ["-C", "target-feature=+avx2,+fma"]
+
+[target.x86_64-pc-windows-msvc.ruvector-core]
+features = ["simd", "parallel", "storage", "hnsw"]
+```
+
+### 4.3 System Tray Integration
+
+Screenpipe uses Tauri for its desktop application. OSpipe extends this with:
+
+| Feature | Implementation |
+|---------|---------------|
+| System tray icon | Tauri `SystemTray` with recording status indicator |
+| Quick search | Global hotkey (Win+Shift+S) opens search overlay |
+| Capture status | Real-time CPU/RAM/storage metrics in tray tooltip |
+| Privacy controls | One-click pause/resume, app exclusion list |
+| Auto-start | Windows Task Scheduler registration |
+| Background service | Windows Service via `windows-service` crate for headless operation |
+
+### 4.4 Windows-Specific Performance Optimizations
+
+| Optimization | Details |
+|-------------|---------|
+| AVX2 SIMD | 8-wide float operations for distance calculations (16M ops/sec) |
+| AVX-512 detection | Runtime detection and dispatch for newer Intel/AMD CPUs |
+| Large pages | 2MB pages for HNSW index memory via `VirtualAlloc` with `MEM_LARGE_PAGES` |
+| NUMA awareness | Pin HNSW search threads to local NUMA node on multi-socket systems |
+| Memory-mapped I/O | `CreateFileMapping` for zero-copy vector persistence |
+| IO completion ports | Async I/O for concurrent embedding generation and index operations |
+| DirectML acceleration | GPU-accelerated embedding generation via DirectML ONNX runtime |
+
+### 4.5 Windows Installer and Distribution
+
+| Aspect | Approach |
+|--------|----------|
+| Installer | NSIS or WiX via Tauri bundler |
+| Code signing | Authenticode with EV certificate |
+| Auto-update | Tauri updater with delta updates |
+| Registry | `HKCU\Software\OSpipe` for configuration |
+| Data location | `%LOCALAPPDATA%\OSpipe\` for database, `%LOCALAPPDATA%\OSpipe\data\` for media |
+| Uninstaller | Clean removal including database, with optional data export |
+
+---
+
+## 5. macOS Integration Plan
+
+### 5.1 Screen Capture Pipeline
+
+**Screenpipe's existing approach**: CoreGraphics `CGWindowListCreateImage` for screen capture, Apple Vision framework for OCR.
+
+**OSpipe enhancement**:
+
+| Component | Technology | Purpose |
+|-----------|------------|---------|
+| Capture (macOS 12.3+) | ScreenCaptureKit (`SCStream`) | Modern, efficient screen capture with per-window/per-app filtering |
+| Capture (legacy) | CoreGraphics `CGDisplayStream` | Fallback for older macOS versions |
+| GPU preprocessing | Metal Performance Shaders | Resize/normalize on Apple GPU |
+| OCR primary | Apple Vision (`VNRecognizeTextRequest`) | Highest quality on-device OCR |
+| OCR scientific | `@ruvector/scipix` | LaTeX/MathML for research content |
+| Audio capture | CoreAudio `AVCaptureSession` | System audio + microphone |
+
+### 5.2 macOS Permissions Model
+
+| Permission | Purpose | API |
+|-----------|---------|-----|
+| Screen Recording | Capture screen content | `CGPreflightScreenCaptureAccess()` |
+| Accessibility | UI event tracking, keyboard/mouse | `AXIsProcessTrusted()` |
+| Microphone | Audio capture for transcription | `AVCaptureDevice.authorizationStatus` |
+| Automation | Control other apps (optional for pipes) | AppleScript/Shortcuts |
+| Full Disk Access | Read application data (optional) | System Preferences manual grant |
+
+**Permission flow**: On first launch, OSpipe guides users through each permission with explanatory dialogs. The Tauri app monitors permission status and degrades gracefully if specific permissions are denied.
+
+### 5.3 Metal GPU Acceleration
+
+Apple Silicon Macs (M1-M4) provide significant GPU acceleration opportunities:
+
+| Operation | CPU (ARM64 NEON) | Metal GPU | Speedup |
+|-----------|------------------|-----------|---------|
+| Embedding generation (384-dim) | ~5ms | ~0.8ms | 6.2x |
+| Batch cosine distance (1000 vectors) | ~237us | ~45us | 5.3x |
+| HNSW search (10K vectors, k=10) | 61us | N/A (CPU optimal) | -- |
+| OCR preprocessing (1080p frame) | ~12ms | ~2ms | 6x |
+
+**Implementation**: Metal acceleration is used for embedding generation and OCR preprocessing. HNSW graph traversal remains CPU-bound (pointer-chasing workload unsuitable for GPU).
+
+```rust
+// Metal compute pipeline for batch embedding
+#[cfg(target_os = "macos")]
+mod metal_accel {
+ use metal::*;
+
+ pub fn batch_embed(texts: &[String], device: &Device) -> Vec> {
+ let pipeline = device.new_compute_pipeline_state_with_function(
+ &library.get_function("embed_kernel", None).unwrap()
+ ).unwrap();
+ // ... Metal command buffer setup
+ }
+}
+```
+
+### 5.4 Universal Binary Support
+
+OSpipe ships as a Universal Binary (fat binary) supporting both architectures:
+
+| Architecture | SIMD | Target Triple |
+|-------------|------|---------------|
+| Apple Silicon (M1-M4) | ARM64 NEON | `aarch64-apple-darwin` |
+| Intel Mac | x86_64 AVX2 | `x86_64-apple-darwin` |
+
+**Build command**:
+```bash
+# Build universal binary
+cargo build --release --target aarch64-apple-darwin
+cargo build --release --target x86_64-apple-darwin
+lipo -create \
+ target/aarch64-apple-darwin/release/ospipe \
+ target/x86_64-apple-darwin/release/ospipe \
+ -output target/universal/ospipe
+```
+
+### 5.5 Spotlight Integration
+
+OSpipe can optionally register as a Spotlight importer, making captured content searchable via macOS Spotlight (Cmd+Space):
+
+| Feature | Implementation |
+|---------|---------------|
+| Spotlight importer | `mdimporter` plugin with custom UTI for `.ospipe` content |
+| Indexed attributes | `kMDItemTextContent`, `kMDItemContentCreationDate`, `kMDItemCreator` |
+| Search routing | Spotlight queries forwarded to RuVector HNSW for semantic results |
+| Quick Look | Preview panel showing captured frame + OCR text |
+
+### 5.6 macOS-Specific Performance Optimizations
+
+| Optimization | Details |
+|-------------|---------|
+| ARM64 NEON | 4-wide float SIMD for distance calculations (8M ops/sec) |
+| Unified Memory | Zero-copy between CPU and GPU for Metal acceleration |
+| Grand Central Dispatch | `libdispatch` for concurrent embedding processing |
+| IOSurface | Hardware-accelerated screen frame sharing between capture and OCR |
+| Memory pressure | Respond to `os_proc_available_memory()` by increasing quantization |
+| Energy efficiency | Reduce capture FPS when on battery (`IOPSCopyPowerSourcesInfo`) |
+| App Nap prevention | `NSProcessInfo.processInfo.beginActivity` for background processing |
+
+### 5.7 macOS Distribution
+
+| Aspect | Approach |
+|--------|----------|
+| Format | `.dmg` with drag-to-Applications |
+| Code signing | Apple Developer ID + Notarization |
+| Auto-update | Sparkle framework via Tauri updater |
+| Sandbox | App Sandbox with `com.apple.security.temporary-exception` for screen recording |
+| Data location | `~/Library/Application Support/OSpipe/` for database |
+| Menu bar | Native SwiftUI menu bar extra via Tauri plugin |
+| Login item | `SMAppService.register` for launch-at-login |
+
+---
+
+## 6. WebAssembly (WASM) Integration Plan
+
+Screenpipe pipes run in a sandboxed runtime (Bun). For **browser-based pipes** -- the pipe editor, web dashboard, and third-party web tools -- OSpipe provides a complete WASM stack that mirrors the NAPI-RS native bindings.
+
+### 6.1 WASM Bundle Strategy
+
+Not every pipe needs every module. OSpipe uses a tiered loading strategy:
+
+| Tier | Modules | Combined Size | Use Case |
+|------|---------|---------------|----------|
+| **Micro** | `micro-hnsw-wasm` | ~12 KB | Minimal vector search (embedded widgets, mobile web) |
+| **Standard** | `ruvector-wasm` + `cognitum-gate-wasm` | ~225 KB | Semantic search + safety gate |
+| **Full** | `ruvector-wasm-unified` | ~350 KB | All-in-one bundle (search, graph, delta, attention) |
+| **AI** | `ruvector-wasm-unified` + `ruvllm-wasm` + `ruqu-wasm` | ~2.5 MB | Full local AI (LLM + quantum + vector) |
+
+**Lazy loading**: Only the Micro tier loads on page init. Higher tiers load on first use via dynamic `import()`:
+
+```typescript
+// Pipe loads micro-hnsw on init (12KB)
+import init, { MicroHNSW } from "@ruvector/micro-hnsw-wasm";
+await init();
+
+// Full vector DB loads lazily on first semantic search
+let ruvector: typeof import("@ruvector/ruvector-wasm-unified") | null = null;
+async function semanticSearch(query: string) {
+ if (!ruvector) {
+ ruvector = await import("@ruvector/ruvector-wasm-unified");
+ await ruvector.default();
+ }
+ return ruvector.search(query, { k: 10 });
+}
+```
+
+### 6.2 Web Worker Deployment
+
+Heavy WASM operations run in Web Workers to avoid blocking the UI:
+
+```typescript
+// ospipe-worker.ts -- runs in Web Worker
+import init, { RuVector, RuvLLM } from "@ruvector/ruvector-wasm-unified";
+
+let db: RuVector;
+let llm: RuvLLM;
+
+self.onmessage = async (e) => {
+ const { type, payload } = e.data;
+
+ switch (type) {
+ case "init":
+ await init();
+ db = new RuVector({ dimensions: 384, metric: "cosine" });
+ break;
+
+ case "init-llm":
+ // Load LLM WASM module (~2MB) only when needed
+ const ruvllm = await import("@ruvector/ruvllm-wasm");
+ await ruvllm.default();
+ llm = new ruvllm.RuvLLM({ model: payload.modelUrl });
+ break;
+
+ case "embed":
+ const embedding = await llm.embed(payload.text);
+ self.postMessage({ type: "embedding", data: embedding });
+ break;
+
+ case "search":
+ const results = db.search(payload.embedding, { k: payload.k });
+ self.postMessage({ type: "results", data: results });
+ break;
+
+ case "insert":
+ db.insert(payload.id, payload.embedding, payload.metadata);
+ break;
+
+ case "graph-query":
+ const { RvLite } = await import("@ruvector/rvlite");
+ const graph = new RvLite();
+ const graphResults = graph.query(payload.cypher);
+ self.postMessage({ type: "graph-results", data: graphResults });
+ break;
+ }
+};
+```
+
+### 6.3 SharedArrayBuffer for Zero-Copy
+
+When available (COOP/COEP headers set), OSpipe uses `SharedArrayBuffer` for zero-copy data sharing between the main thread and WASM workers:
+
+```typescript
+// Main thread creates shared memory for vector index
+const sharedIndex = new SharedArrayBuffer(1024 * 1024 * 50); // 50MB
+const worker = new Worker("ospipe-worker.js");
+
+// Worker maps HNSW index into shared memory
+worker.postMessage({ type: "init", sharedMemory: sharedIndex });
+
+// Main thread can read search results without copying
+const resultsView = new Float32Array(sharedIndex, resultOffset, resultLength);
+```
+
+**Required headers** (set by OSpipe's local server):
+
+```
+Cross-Origin-Opener-Policy: same-origin
+Cross-Origin-Embedder-Policy: require-corp
+```
+
+### 6.4 Service Worker for Offline Pipes
+
+Pipes can work fully offline using Service Worker + IndexedDB:
+
+```typescript
+// service-worker.ts
+import { MicroHNSW } from "@ruvector/micro-hnsw-wasm";
+
+self.addEventListener("fetch", (event) => {
+ if (event.request.url.includes("/api/v2/search")) {
+ event.respondWith(handleOfflineSearch(event.request));
+ }
+});
+
+async function handleOfflineSearch(request: Request): Promise {
+ const { query } = await request.json();
+
+ // Search local WASM index while offline
+ const index = await getLocalIndex(); // from IndexedDB
+ const results = index.search(query, { k: 10 });
+
+ return new Response(JSON.stringify(results), {
+ headers: { "Content-Type": "application/json" },
+ });
+}
+```
+
+### 6.5 WASM Performance vs NAPI-RS
+
+| Operation | NAPI-RS (native) | WASM (browser) | Ratio |
+|-----------|-------------------|----------------|-------|
+| HNSW search (10K, k=10) | 61us | ~250us | 4.1x slower |
+| Cosine distance (1000 vecs) | 237us | ~900us | 3.8x slower |
+| Embedding generation (ruvllm) | ~5ms | ~20ms | 4x slower |
+| Graph Cypher query (1-hop) | ~0.8ms | ~3ms | 3.7x slower |
+| Delta computation | ~0.1ms | ~0.4ms | 4x slower |
+| Safety gate check | ~0.05ms | ~0.15ms | 3x slower |
+
+**Guidance**: Use NAPI-RS for desktop pipes (default). WASM is for browser-based pipe editor, web dashboard, and portable tools. For latency-critical operations, WASM pipes should pre-compute and cache results.
+
+### 6.6 WASM SIMD Acceleration
+
+All RuVector WASM modules compile with WASM SIMD128 for hardware-accelerated vector operations:
+
+```bash
+# Build with SIMD support
+RUSTFLAGS="-C target-feature=+simd128" wasm-pack build --target web
+```
+
+| Browser | WASM SIMD | Speedup vs scalar |
+|---------|-----------|-------------------|
+| Chrome 91+ | Yes | 2-4x |
+| Firefox 89+ | Yes | 2-4x |
+| Safari 16.4+ | Yes | 2-3x |
+| Edge 91+ | Yes | 2-4x |
+
+### 6.7 Pipe Editor Integration
+
+Screenpipe's browser-based pipe editor gets embedded RuVector capabilities:
+
+| Feature | WASM Module | Description |
+|---------|-------------|-------------|
+| Live semantic search preview | `ruvector-wasm` | Test queries against sample data while editing pipe code |
+| Inline graph visualizer | `rvlite` | Render knowledge graph subgraphs in the editor |
+| Attention heatmap | `ruvector-attention-unified-wasm` | Visualize attention scores across captured content |
+| Safety gate tester | `cognitum-gate-wasm` | Test content safety rules before deployment |
+| Quantum circuit playground | `ruqu-wasm` | Interactive quantum circuit builder for experimental pipes |
+| Embedding inspector | `ruvllm-wasm` | Generate and compare embeddings in-browser |
+| Delta diff viewer | `ruvector-delta-wasm` | Visualize content changes over time |
+
+### 6.8 WASM Build Pipeline
+
+All WASM modules use a unified build pipeline:
+
+```bash
+# Build all WASM modules for OSpipe
+cargo install wasm-pack
+
+# Individual module build
+wasm-pack build crates/ruvector-wasm --target web --out-dir ../../npm/packages/ruvector-wasm
+
+# Optimized production build (with wasm-opt)
+wasm-pack build crates/ruvector-wasm --target web --release
+
+# Bundle size analysis
+wasm-opt -Oz --strip-debug target/wasm32-unknown-unknown/release/ruvector_wasm.wasm -o optimized.wasm
+ls -lh optimized.wasm
+```
+
+**Tree shaking**: Each WASM module is independently importable. The unified bundle (`ruvector-wasm-unified`) uses `wasm-bindgen` feature flags to include only requested capabilities:
+
+```toml
+[features]
+default = ["search"]
+search = [] # HNSW vector search only (~200KB)
+graph = ["search"] # + knowledge graph (~+80KB)
+delta = ["search"] # + delta tracking (~+50KB)
+attention = [] # attention mechanisms (~+150KB)
+full = ["search", "graph", "delta", "attention"] # everything (~350KB)
+```
+
+### 6.9 Cross-Platform WASM Deployment Matrix
+
+| Deployment Target | Bundle Tier | Worker | SharedArrayBuffer | Offline |
+|-------------------|-------------|--------|-------------------|---------|
+| Pipe Editor (browser) | Full | Yes | Yes (local server) | No |
+| Web Dashboard | Standard | Yes | Yes (local server) | Yes (Service Worker) |
+| Embedded Widget | Micro | Optional | No | No |
+| Tauri WebView (desktop) | Full | Yes | Yes | N/A (native fallback) |
+| Mobile PWA | Standard | Yes | Depends on browser | Yes |
+| Electron (if used) | Full | Yes | Yes | Yes |
+| Cloudflare Worker (edge) | Micro | N/A | No | N/A |
+
+
+Click to expand: WASM Deployment Architecture Diagram
+
+```mermaid
+graph TB
+ subgraph "Browser Runtime"
+ direction TB
+ MAIN[Main Thread
Pipe UI + Pipe Editor]
+ SW[Service Worker
Offline search cache]
+ WW1[Web Worker 1
ruvector-wasm-unified
Vector search + Graph]
+ WW2[Web Worker 2
ruvllm-wasm
Local LLM inference]
+ WW3[Web Worker 3
ruqu-wasm
Quantum circuits]
+ IDB[(IndexedDB
Cached embeddings
+ offline index)]
+ end
+
+ subgraph "WASM Modules (loaded on demand)"
+ MICRO["micro-hnsw-wasm
12KB - always loaded"]
+ STD["ruvector-wasm
200KB - on first search"]
+ FULL["ruvector-wasm-unified
350KB - on graph/delta query"]
+ LLM["ruvllm-wasm
2MB - on LLM request"]
+ QU["ruqu-wasm
105KB - on quantum pipe"]
+ GATE["cognitum-gate-wasm
25KB - on content check"]
+ end
+
+ subgraph "Data Sources"
+ API[OSpipe REST API
localhost:3030/v2]
+ SAB[SharedArrayBuffer
Zero-copy index]
+ end
+
+ MAIN --> MICRO
+ MAIN -->|lazy import| WW1
+ MAIN -->|lazy import| WW2
+ MAIN -->|lazy import| WW3
+
+ WW1 --> STD
+ WW1 --> FULL
+ WW1 --> GATE
+ WW2 --> LLM
+ WW3 --> QU
+
+ WW1 <-->|SharedArrayBuffer| SAB
+ WW1 <--> IDB
+ SW <--> IDB
+ SW <--> API
+
+ MAIN --> SW
+ MAIN <--> API
+```
+
+
+
+---
+
+## 7. Security Architecture
+
+### 6.1 Data Encryption
+
+| Layer | Mechanism | Details |
+|-------|-----------|---------|
+| At-rest encryption | AES-256-GCM | All vector indices, graph data, and delta stores encrypted on disk |
+| Key derivation | Argon2id | User passphrase → encryption key with 64MB memory cost |
+| Key storage (macOS) | Keychain Services | `SecItemAdd` with `kSecAttrAccessibleWhenUnlockedThisDeviceOnly` |
+| Key storage (Windows) | DPAPI | `CryptProtectData` bound to user SID |
+| Key storage (Linux) | libsecret / GNOME Keyring | D-Bus Secret Service API |
+| Cross-device sync | X25519 + ChaCha20-Poly1305 | End-to-end encrypted CRDT deltas |
+| Memory protection | `mlock()` / `VirtualLock()` | Prevent key material from being swapped to disk |
+
+### 6.2 Content Safety
+
+| Threat | Mitigation | Component |
+|--------|------------|-----------|
+| PII in screen captures | Pre-storage PII redaction | `cognitum-gate-kernel` |
+| Credit card numbers | Regex + ML detection, auto-redact before embedding | `cognitum-gate-kernel` |
+| Password fields | Detect password input fields via Accessibility API, skip capture | Capture engine |
+| Sensitive apps | User-configurable app exclusion list (e.g., banking apps) | OSpipe settings |
+| Incognito/private windows | Auto-detect and skip private browsing windows | Capture engine |
+| Data exfiltration via pipes | Pipe sandboxing with capability-based permissions | `cognitum-gate-kernel` |
+
+### 6.3 Pipe Sandboxing
+
+Pipes operate under a capability model enforced by `cognitum-gate-kernel`:
+
+```typescript
+// Pipe manifest declares required capabilities
+{
+ "name": "meeting-summarizer",
+ "capabilities": {
+ "read_audio": true, // Can access audio transcriptions
+ "read_screen": false, // Cannot access raw screen captures
+ "write_external": false, // Cannot send data outside OSpipe
+ "local_llm": true, // Can use ruvllm for local inference
+ "network": false // No network access
+ }
+}
+```
+
+### 6.4 Audit Trail
+
+All data access is logged via `ruvector-metrics` with cryptographic witnesses (`ruqu-core` witness module):
+
+- Every search query is logged with timestamp, query hash, and result count
+- Every pipe data access is logged with capability verification
+- Witness logs are tamper-evident (hash chain)
+- Optional export for compliance audits
+
+---
+
+## 8. Linux Integration Plan
+
+While Windows and macOS are primary targets, Screenpipe supports Linux and OSpipe maintains that support.
+
+### 7.1 Screen Capture Pipeline
+
+| Component | Technology | Notes |
+|-----------|------------|-------|
+| X11 capture | `XShmGetImage` / `XComposite` | Legacy X11 applications |
+| Wayland capture | PipeWire + `xdg-desktop-portal` | Modern Wayland compositors (GNOME, KDE) |
+| Audio capture | PipeWire / PulseAudio | System audio + microphone |
+| OCR | Tesseract via `leptonica` | No native OS OCR equivalent |
+
+### 7.2 Linux-Specific Optimizations
+
+| Optimization | Details |
+|-------------|---------|
+| AVX2/AVX-512 SIMD | Runtime detection via `cpuid`, same as Windows |
+| io_uring | Async I/O for embedding + index operations (kernel 5.1+) |
+| huge pages | `madvise(MADV_HUGEPAGE)` for HNSW index memory |
+| cgroups v2 | Resource limits for background capture process |
+| D-Bus integration | System tray via `StatusNotifierItem` (SNI) protocol |
+| systemd service | `ospipe.service` for headless server operation |
+| Flatpak / AppImage | Distribution for distro-agnostic deployment |
+
+### 7.3 Linux Pre-Built Binaries
+
+| Package | Binary |
+|---------|--------|
+| `@ruvector/router` | `router-linux-x64-gnu`, `router-linux-arm64-gnu` |
+| `@ruvector/ruvllm` | `ruvllm-linux-x64-gnu`, `ruvllm-linux-arm64-gnu` |
+| `@ruvector/tiny-dancer` | `tiny-dancer-linux-x64-gnu`, `tiny-dancer-linux-arm64-gnu` |
+
+---
+
+## 9. Backward Compatibility and Migration
+
+### 8.1 Existing Pipe Compatibility
+
+All existing Screenpipe pipes continue to work unchanged:
+
+| Existing API | Status | Notes |
+|-------------|--------|-------|
+| `pipe.queryScreenpipe()` | Unchanged | Routes through FTS5 by default |
+| `pipe.streamVision()` | Unchanged | Same event format |
+| `/search` REST endpoint | Backward compatible | New `mode` parameter defaults to `keyword` |
+| `/raw_sql` endpoint | Unchanged | Direct SQLite access preserved |
+| `@screenpipe/js` SDK | Unchanged | Enhanced SDK is additive, not breaking |
+
+### 8.2 Migration Path for Pipe Developers
+
+| Phase | Action | Breaking Changes |
+|-------|--------|-----------------|
+| Phase 0 (now) | Existing pipes work as-is | None |
+| Phase 1 | Add optional `@ruvector/node` import | None -- opt-in |
+| Phase 2 | New SDK methods: `queryRuVector()`, `queryGraph()`, `queryDelta()` | None -- additive |
+| Phase 3 | Deprecate `queryScreenpipe()` with `mode=semantic` redirect | Warning only |
+| Phase 4 | `queryScreenpipe()` internally routes through RuVector | None -- transparent |
+
+### 8.3 Data Migration
+
+Historical SQLite data is migrated to RuVector in background:
+
+```
+1. Dual-write begins (new data → both SQLite + RuVector)
+2. Background batch job embeds historical OCR text (oldest first)
+3. Background batch job builds knowledge graph from historical entities
+4. Progress tracked via ruvector-metrics (estimated: ~1 hour per month of data)
+5. After full migration, SQLite becomes read-only fallback
+```
+
+### 8.4 API Versioning Strategy
+
+| Version | Endpoint | Backend |
+|---------|----------|---------|
+| v1 (current) | `/search`, `/frames/{id}`, `/health` | SQLite FTS5 |
+| v2 (OSpipe) | `/v2/search`, `/v2/graph`, `/v2/delta`, `/v2/health` | RuVector |
+| v1 compat | `/search` with `Accept: application/json` | Routes to v2 internally |
+
+**Version negotiation**: Pipes declare their API version in their manifest. The OSpipe server automatically routes to the appropriate backend. v1 pipes never see RuVector changes.
+
+```typescript
+// Pipe manifest
+{
+ "name": "my-pipe",
+ "apiVersion": "v2", // or "v1" for legacy
+}
+```
+
+---
+
+## 10. Implementation Milestones
+
+### Phase 0: Pre-Integration (Week 0)
+
+**Goal**: Validate compatibility and set up development environment.
+
+| Task | Deliverable |
+|------|-------------|
+| Fork Screenpipe, add RuVector workspace | Compiling workspace with both codebases |
+| Validate all NAPI-RS binaries load on Windows + macOS | Platform compatibility matrix |
+| Run `ruvllm` model download + inference on target platforms | Offline LLM verified |
+| Set up CI/CD for cross-platform builds | GitHub Actions for Windows, macOS, Linux |
+| Create synthetic test data via `agentic-synth` | 1000 sample frames with OCR text |
+
+### Phase 1: Foundation (Weeks 1-4)
+
+**Goal**: Replace Screenpipe's FTS5 backend with RuVector HNSW while maintaining backward compatibility.
+
+| Task | Crates Used | Deliverable |
+|------|-------------|-------------|
+| Fork Screenpipe, add RuVector as Cargo workspace dependency | `ruvector-core` | Compiling integration |
+| Implement embedding generation pipeline | `ruvector-sparse-inference` | Local ONNX embedding from OCR text |
+| Create dual-write storage adapter | `ruvector-core`, `ruvector-collections` | SQLite + HNSW parallel writes |
+| Add `mode=semantic` to `/search` endpoint | `ruvector-server`, `ruvector-filter` | Semantic search via REST |
+| Implement frame deduplication via clustering | `ruvector-cluster` | Skip near-identical consecutive frames |
+| Integrate ruvllm for local embedding generation | `ruvllm` | Offline-capable, no external API dependency |
+| Implement tiered quantization for historical data | `ruvector-temporal-tensor` | 4x storage reduction for 7+ day old data |
+| Add safety gate to ingestion pipeline | `cognitum-gate-kernel` | PII filtering before vector storage |
+| Unit and integration tests | `ruvector-bench` | >80% coverage on new code |
+
+**Success criteria**: Semantic search returns relevant results for queries where FTS5 fails (e.g., "that spreadsheet with the Q4 numbers" finding a screenshot of Excel).
+
+### Phase 2: Intelligence (Weeks 5-8)
+
+**Goal**: Add knowledge graph, attention mechanisms, and delta tracking.
+
+| Task | Crates Used | Deliverable |
+|------|-------------|-------------|
+| Build knowledge graph from captured entities | `ruvector-graph`, `ruvector-gnn` | Entity extraction + graph construction |
+| Implement delta-based change detection | `ruvector-delta-core`, `ruvector-delta-index` | 60-80% storage reduction for static content |
+| Add attention-based content scoring | `ruvector-attention` | Priority ranking of captured content |
+| Implement query router | `ruvector-router-core`, `@ruvector/tiny-dancer` | Automatic routing: semantic vs. graph vs. temporal |
+| Add context-switch detection | `ruvector-mincut` | Automatic session segmentation |
+| Integrate SONA adaptive learning | `sona` | Router improves with usage |
+| Implement Cypher query endpoint | `ruvector-graph` | `/graph` endpoint for relationship queries |
+| Add ruvllm-powered NER for entity extraction | `ruvllm` | Extract people, orgs, projects from text |
+| Integrate gated transformer for context segmentation | `ruvector-mincut-gated-transformer` | Multi-scale topic change detection |
+| Implement FFI router in Screenpipe's Rust backend | `ruvector-router-ffi` | Zero-overhead in-process query routing |
+
+**Success criteria**: System correctly identifies "the person I was discussing budgets with last week" by combining audio transcription (speaker ID), knowledge graph (person-topic relationships), and temporal query (last week filter).
+
+### Phase 3: Platform Optimization (Weeks 9-12)
+
+**Goal**: Platform-specific optimizations for Windows and macOS.
+
+| Task | Platform | Crates Used | Deliverable |
+|------|----------|-------------|-------------|
+| AVX2/AVX-512 runtime dispatch | Windows | `ruvector-core` | Optimal SIMD on Intel/AMD |
+| Metal GPU embedding generation | macOS | `ruvector-sparse-inference` | 6x faster embedding on Apple Silicon |
+| ScreenCaptureKit integration | macOS | Screenpipe core | Modern capture API |
+| DirectML ONNX runtime | Windows | `ruvector-sparse-inference` | GPU-accelerated embeddings |
+| Universal Binary build | macOS | All crates | Single binary for M1+ and Intel |
+| Windows Service mode | Windows | OSpipe service | Headless background operation |
+| Spotlight importer | macOS | `ruvector-core` | System-wide search integration |
+| System tray enhancements | Both | Tauri | Quick search, privacy controls |
+
+**Success criteria**: <100ms end-to-end search latency on both platforms with platform-native GPU acceleration.
+
+### Phase 4: Ecosystem (Weeks 13-16)
+
+**Goal**: Enhanced pipe SDK, MCP integration, and distributed sync.
+
+| Task | Crates Used | Deliverable |
+|------|-------------|-------------|
+| Extend pipe SDK with RuVector APIs | `ruvector-node`, `ruvector-gnn-node` | `queryRuVector()`, `queryGraph()`, `queryDelta()` |
+| WASM fallback for browser-based pipes | `micro-hnsw-wasm`, `ruvector-wasm` | Vector search in pipe editor |
+| MCP server with full OSpipe capabilities | `mcp-gate` | Claude/Cursor access to knowledge graph |
+| Cross-device sync via CRDT deltas | `ruvector-delta-consensus`, `ruvector-raft` | Multi-device memory sync |
+| Quantum-enhanced search (experimental) | `ruqu-algorithms` | Grover-inspired amplitude amplification |
+| Spiking neural network background processor | `ruvector-nervous-system` | Energy-efficient pattern detection |
+| Deploy ruvbot agent templates for common pipes | `ruvbot` | Meeting summarizer, code tracker, research assistant |
+| PostgreSQL backend for enterprise deployments | `ruvector-postgres` | Team/org-wide shared OSpipe |
+| Burst scaling for multi-monitor capture spikes | `burst-scaling` | Handle high-load without frame drops |
+| Performance dashboard | `ruvector-metrics` | Prometheus metrics + Grafana dashboard |
+| Public beta release | All | OSpipe v0.1.0 |
+
+**Success criteria**: Third-party developers can build pipes that leverage semantic search, knowledge graphs, and temporal queries through the enhanced SDK.
+
+### Phase 5: Advanced Features (Weeks 17-24)
+
+**Goal**: Research features and production hardening.
+
+| Task | Crates Used | Deliverable |
+|------|-------------|-------------|
+| Hyperbolic embeddings for app hierarchy | `ruvector-hyperbolic-hnsw` | Hierarchy-aware search |
+| FPGA transformer for enterprise | `ruvector-fpga-transformer` | Deterministic latency guarantees |
+| Coherence verification on graph updates | `prime-radiant` | Hallucination detection in knowledge graph |
+| Bio-inspired always-on processing | `ruvector-nervous-system`, `@ruvector/spiking-neural` | SNN for continuous pattern detection |
+| Compute economy for distributed networks | `ruvector-economy-wasm` | Multi-user resource sharing |
+| Scientific document analysis pipeline | `@ruvector/scipix` | LaTeX/diagram extraction from screen |
+| Health monitoring pipe template | `@ruvector/rvdna` | Genomic data analysis from screen captures |
+| Production release | All | OSpipe v1.0.0 |
+
+---
+
+## 11. Decision
+
+### 11.1 Recommended Integration Approach
+
+We recommend a **layered replacement strategy** where RuVector components are introduced alongside (not replacing) Screenpipe's existing storage, with a gradual migration path:
+
+1. **Dual-write phase**: Both SQLite/FTS5 and RuVector HNSW receive all data. Existing pipes continue to work unchanged.
+2. **Router phase**: A neural query router directs queries to the optimal backend (FTS5 for exact match, HNSW for semantic, Graph for relational).
+3. **Migration phase**: Historical data is batch-migrated from SQLite to RuVector with tiered quantization.
+4. **Deprecation phase**: FTS5 becomes a compatibility shim that routes to RuVector internally.
+
+### 11.2 Key Architectural Decisions
+
+| Decision | Rationale |
+|----------|-----------|
+| Keep Screenpipe capture layer unchanged | Mature, platform-tested capture code should not be rewritten |
+| Add RuVector as Cargo workspace member | Tight Rust-level integration with zero-copy data sharing |
+| Use NAPI-RS for pipe SDK (not WASM) | 10x performance over WASM for desktop pipes |
+| Provide WASM fallback for browser pipes | Portability for the pipe editor and web-based tools |
+| Implement dual-write before migration | Zero downtime, rollback capability |
+| Use CRDT for cross-device sync (not Raft) | Works without central coordinator, handles network partitions |
+| Store embeddings and raw text separately | Different retention policies, quantization tiers |
+| Default to ruvllm for embeddings and summarization | No external API dependency, fully offline, GGUF models |
+| Use ruvector-router-ffi for hot-path routing | Zero-overhead in-process routing in Screenpipe's Rust backend |
+| Include ruvector-cluster in capture pipeline | Eliminate 90%+ redundant frames from static content |
+| Offer ruvector-postgres for enterprise deployments | PostgreSQL for team/org shared OSpipe instances |
+
+### 11.3 Technology Choices
+
+| Component | Choice | Alternatives Considered |
+|-----------|--------|------------------------|
+| Vector index | ruvector-core HNSW | FAISS (no Rust/WASM), Qdrant (external service) |
+| Knowledge graph | ruvector-graph | Neo4j (external service), SQLite graph extension (limited) |
+| Embedding model | ruvllm (local GGUF) + ONNX fallback (384-dim) | OpenAI API (requires internet), Cohere (cloud) |
+| Local LLM | ruvllm (GGUF Q4_K_M, ~400MB) | Ollama (separate process), llama.cpp (no Rust integration) |
+| Frame deduplication | ruvector-cluster (DBSCAN) | Perceptual hashing (limited), naive diff (slow) |
+| Query routing | ruvector-router-core + SONA | Static rules (no learning), LLM-based (too slow) |
+| Delta tracking | ruvector-delta-core | Git-like (too heavy), custom diffing (reinventing wheel) |
+| Cross-device sync | ruvector-delta-consensus (CRDT) | Raft (requires leader), Paxos (too complex for desktop) |
+| Safety gate | cognitum-gate-kernel | Regex rules (brittle), LLM classification (too slow) |
+
+---
+
+## 12. Consequences
+
+### 12.1 Benefits
+
+1. **Semantic search**: Users can find content by meaning, not just keywords. "That conversation about the contract" finds relevant audio and screen content even without the word "contract" appearing in OCR text.
+2. **Knowledge graph**: Relationships between people, topics, apps, and time are explicitly modeled, enabling queries like "Who did I discuss Project X with this week?"
+3. **Storage efficiency**: Delta tracking + tiered quantization reduces storage from ~30 GB/month to ~8-12 GB/month.
+4. **Performance**: 61us p50 vector search vs. ~5ms FTS5 on equivalent dataset sizes.
+5. **Platform optimization**: AVX2 on Windows, NEON on Apple Silicon, Metal GPU for embedding generation on macOS.
+6. **Learning system**: SONA and GNN layers improve search quality based on user behavior without manual tuning.
+7. **Privacy preservation**: All processing remains local. CRDT sync is end-to-end encrypted without central server.
+8. **Developer ecosystem**: Enhanced pipe SDK gives developers access to semantic search, graph queries, and temporal analysis.
+
+### 12.2 Risks and Mitigations
+
+| Risk | Probability | Impact | Mitigation |
+|------|-------------|--------|------------|
+| Integration complexity increases Screenpipe build times | High | Medium | Feature flags, incremental compilation, pre-built NAPI-RS binaries |
+| HNSW recall < 100% for edge cases | Medium | Medium | Hybrid search (HNSW candidates + exact reranking), ef_search tuning |
+| Increased memory usage from vector index | Medium | Medium | Tiered quantization, memory-pressure responsive compression |
+| Cross-device sync conflicts | Medium | Low | CRDT guarantees eventual consistency, conflict-free by design |
+| macOS permission changes in future OS versions | Low | High | Abstract permission layer, ScreenCaptureKit migration path |
+| Windows Defender flagging background capture | Medium | Medium | Authenticode signing, Microsoft SmartScreen registration |
+| Embedding model quality for non-English content | Medium | Medium | Multilingual model option (paraphrase-multilingual-MiniLM-L12-v2) |
+| Storage migration from SQLite corrupts data | Low | High | Dual-write phase ensures SQLite remains source of truth during migration |
+
+### 12.3 Performance Targets
+
+| Metric | Target | Baseline (Screenpipe) |
+|--------|--------|-----------------------|
+| Semantic search (10K frames, k=10) | < 100us p50 | ~5ms (FTS5) |
+| Graph query (1-hop traversal) | < 1ms | N/A (not available) |
+| Delta compression ratio | 60-80% for static content | 0% (full frame storage) |
+| Embedding generation (local ONNX) | < 5ms per text chunk | N/A (not available) |
+| End-to-end search latency | < 100ms | ~50ms (FTS5 only) |
+| Memory overhead | < 500 MB additional | ~600 MB baseline |
+| CPU overhead (idle) | < 3% additional | ~10% baseline |
+| Storage reduction | 60-70% vs. current | ~30 GB/month |
+
+### 12.4 Non-Goals
+
+The following are explicitly out of scope for this integration:
+
+- **Replacing Screenpipe's UI**: The Tauri desktop application remains Screenpipe's responsibility.
+- **Cloud hosting**: OSpipe is local-first. Cloud deployment is a separate concern.
+- **Mobile platforms**: iOS and Android are not targeted in this ADR.
+- **Real-time video analysis**: Frame-by-frame video understanding (beyond OCR) is future work.
+- **Full conversational AI**: RuVector provides local LLM inference via `ruvllm` for embeddings, summarization, and classification, but does not replace dedicated conversational AI services for complex multi-turn dialogue.
+
+---
+
+## 13. References
+
+1. Screenpipe Project. [github.com/screenpipe/screenpipe](https://github.com/screenpipe/screenpipe). MIT License.
+2. Screenpipe Architecture Documentation. [docs.screenpi.pe/architecture](https://docs.screenpi.pe/architecture).
+3. Screenpipe Pipe SDK. `@screenpipe/js` npm package.
+4. ADR-001: RuVector Core Architecture. `/workspaces/ruvector/docs/adr/ADR-001-ruvector-core-architecture.md`.
+5. ADR-016: Delta-Behavior DDD Architecture. `/workspaces/ruvector/docs/adr/ADR-016-delta-behavior-ddd-architecture.md`.
+6. Malkov, Y., & Yashunin, D. (2018). "Efficient and robust approximate nearest neighbor search using Hierarchical Navigable Small World graphs." arXiv:1603.09320.
+7. Apple ScreenCaptureKit Documentation. [developer.apple.com/documentation/screencapturekit](https://developer.apple.com/documentation/screencapturekit).
+8. Microsoft DXGI Desktop Duplication. [learn.microsoft.com/en-us/windows/win32/direct3ddxgi/desktop-dup-api](https://learn.microsoft.com/en-us/windows/win32/direct3ddxgi/desktop-dup-api).
+9. ONNX Runtime. [onnxruntime.ai](https://onnxruntime.ai). Cross-platform inference engine.
+10. SimSIMD. [github.com/ashvardanian/SimSIMD](https://github.com/ashvardanian/SimSIMD). SIMD distance functions.
+
+---
+
+## Appendix A: Full Crate Dependency Map
+
+The following RuVector crates are directly involved in the OSpipe integration, organized by dependency layer:
+
+```
+Layer 0 (No RuVector deps):
+ ruvector-math - Mathematical primitives (Optimal Transport, Info Geometry)
+ ruqu-core - Quantum circuit simulator
+ cognitum-gate-kernel - Safety gate kernel (no-std)
+ micro-hnsw-wasm - Neuromorphic HNSW (11.8KB)
+ ruvllm - Local LLM inference (GGUF)
+
+Layer 1 (Depends on Layer 0):
+ ruvector-core - Vector DB engine (depends on ruvector-math)
+ ruvector-filter - Metadata filtering
+ ruvector-delta-core - Delta type system
+ ruvector-cluster - Content clustering and frame deduplication
+ ruqu-algorithms - Quantum algorithms (depends on ruqu-core)
+ ruQu - Quantum meta-package (re-exports ruqu-core, algorithms, exotic)
+
+Layer 2 (Depends on Layer 1):
+ ruvector-graph - Knowledge graph (depends on ruvector-core)
+ ruvector-gnn - Graph neural networks (depends on ruvector-core)
+ ruvector-attention - Attention mechanisms (depends on ruvector-core)
+ ruvector-delta-index - Delta-aware HNSW (depends on ruvector-core, ruvector-delta-core)
+ ruvector-delta-consensus - CRDT sync (depends on ruvector-delta-core)
+ ruvector-collections - Collection management (depends on ruvector-core)
+ ruvector-temporal-tensor - Temporal compression (depends on ruvector-core)
+ ruvector-hyperbolic-hnsw - Hyperbolic search (depends on ruvector-core)
+ ruvector-sparse-inference - Edge inference (depends on ruvector-core)
+ ruvector-mincut - Network analysis (depends on ruvector-core)
+ ruvector-mincut-gated-transformer - Gated transformer (depends on ruvector-mincut, ruvector-attention)
+ ruvector-postgres - PostgreSQL backend (depends on ruvector-core)
+
+Layer 3 (Depends on Layer 2):
+ ruvector-router-core - Query routing (depends on ruvector-core, ruvector-gnn)
+ ruvector-router-ffi - FFI bindings for zero-overhead in-process routing
+ sona - Adaptive learning (depends on ruvector-core)
+ ruvector-nervous-system - SNN processing (depends on ruvector-core, ruvector-gnn)
+ prime-radiant - Coherence engine (depends on ruvector-graph)
+ ruvector-raft - Distributed consensus (depends on ruvector-core)
+ ruvector-replication - Data replication (depends on ruvector-core)
+
+Layer 4 (Application layer):
+ ruvector-server - REST API (depends on many Layer 2-3 crates)
+ mcp-gate - MCP server (depends on ruvector-server)
+ ruvector-node - NAPI-RS bindings (depends on ruvector-core)
+ ruvector-gnn-node - GNN NAPI-RS (depends on ruvector-gnn)
+ ruvector-graph-node - Graph NAPI-RS (depends on ruvector-graph)
+ ruvllm (NAPI-RS) - LLM NAPI-RS (5 platform binaries)
+ ruvbot - Agent templates (depends on ruvllm, ruvector-node)
+ agentic-integration - Pipe orchestration (depends on ruvector-node)
+ burst-scaling - Load management (depends on ruvector-core)
+
+WASM layer (browser pipes):
+ 21 WASM packages available (see section 2.18 for complete inventory)
+```
+
+## Appendix B: API Surface for OSpipe Pipes
+
+### Enhanced SDK Methods
+
+```typescript
+import { pipe } from "@screenpipe/js";
+import { RuVector, Graph, Delta } from "@ruvector/node";
+
+// Original Screenpipe API (unchanged)
+const results = await pipe.queryScreenpipe({
+ q: "budget meeting",
+ contentType: "all",
+ limit: 20,
+ startTime: new Date(Date.now() - 86400000).toISOString(),
+});
+
+// New: Semantic vector search via RuVector
+const semanticResults = await pipe.queryRuVector({
+ query: "financial discussion about quarterly targets",
+ k: 10,
+ metric: "cosine",
+ filters: {
+ app: "Zoom",
+ timeRange: { start: "2026-02-01", end: "2026-02-12" },
+ contentType: "audio",
+ },
+ rerank: true, // MMR deduplication
+ confidence: true, // Include conformal prediction bounds
+});
+
+// New: Knowledge graph query via Cypher
+const graphResults = await pipe.queryGraph(`
+ MATCH (p:Person)-[:DISCUSSED]->(t:Topic)
+ WHERE t.name CONTAINS "budget" AND p.last_seen > datetime("2026-02-01")
+ RETURN p.name, t.name, p.last_seen
+ ORDER BY p.last_seen DESC
+ LIMIT 10
+`);
+
+// New: Temporal delta query
+const deltaResults = await pipe.queryDelta({
+ app: "VS Code",
+ file: "src/auth.ts",
+ timeRange: { start: "2026-02-10T14:00:00", end: "2026-02-10T16:00:00" },
+ includeChanges: true, // Return line-by-line diffs
+});
+
+// New: Attention-weighted real-time stream
+const stream = pipe.streamAttention({
+ threshold: 0.7, // Only emit events above attention score 0.7
+ categories: ["code_change", "person_mention", "topic_shift"],
+});
+
+for await (const event of stream) {
+ console.log(`[${event.category}] Score: ${event.attention} - ${event.summary}`);
+}
+```
+
+## Appendix C: Resource Estimates
+
+### Storage Projections (per month, 1 FPS, 8-hour workday)
+
+| Component | Without RuVector | With RuVector | Savings |
+|-----------|-----------------|---------------|---------|
+| Raw media (MP4/MP3) | ~20 GB | ~20 GB (unchanged) | 0% |
+| OCR text (SQLite) | ~2 GB | ~0.5 GB (delta-compressed) | 75% |
+| Embeddings (384-dim, f32) | N/A | ~1.2 GB (tiered quantization) | -- |
+| Knowledge graph | N/A | ~0.3 GB | -- |
+| HNSW index | N/A | ~0.8 GB | -- |
+| **Total** | **~22 GB** | **~22.8 GB** | ~-3.6% (net, with semantic capabilities) |
+| **Total with media compression** | ~22 GB | ~15 GB (delta media + quantized vectors) | **32%** |
+
+### Memory Projections (runtime)
+
+| Component | Baseline (Screenpipe) | Added by RuVector | Total |
+|-----------|----------------------|-------------------|-------|
+| Capture engine | ~200 MB | 0 | ~200 MB |
+| OCR/STT processing | ~300 MB | 0 | ~300 MB |
+| SQLite + FTS5 | ~100 MB | -50 MB (reduced after migration) | ~50 MB |
+| HNSW index (hot tier) | N/A | ~200 MB | ~200 MB |
+| Knowledge graph | N/A | ~100 MB | ~100 MB |
+| GNN model | N/A | ~50 MB | ~50 MB |
+| Router + SONA | N/A | ~30 MB | ~30 MB |
+| **Total** | **~600 MB** | **+330 MB** | **~930 MB** |
+
+### CPU Projections (continuous operation)
+
+| Task | Baseline | Added by RuVector | Notes |
+|------|----------|-------------------|-------|
+| Screen capture | ~3% | 0 | Unchanged |
+| OCR processing | ~5% | 0 | Unchanged |
+| Audio transcription | ~2% | 0 | Unchanged |
+| Embedding generation | N/A | ~2% | Batch, async |
+| Delta computation | N/A | ~0.5% | Lightweight diff |
+| Graph updates | N/A | ~0.3% | Incremental |
+| SNN background | N/A | ~0.2% | Spike-based, efficient |
+| **Total** | **~10%** | **+3%** | **~13%** |
+
+---
+
+## Revision History
+
+| Version | Date | Author | Changes |
+|---------|------|--------|---------|
+| 0.1 | 2026-02-12 | ruv.io | Initial integration architecture proposal |
+| 0.2 | 2026-02-12 | ruv.io | Added: ruvllm (local LLM), ruvector-cluster (dedup), ruvector-postgres (enterprise), security architecture (encryption, sandboxing, audit), Linux integration plan, backward compatibility + migration path, API versioning strategy, 21 WASM modules inventory, ruvector-router-ffi (zero-overhead), ruvbot (agent templates), burst-scaling, agentic-integration/synth, ruQu meta-package, gated transformer, Phase 0 pre-integration |
diff --git a/examples/OSpipe/Cargo.toml b/examples/OSpipe/Cargo.toml
new file mode 100644
index 000000000..cc560d983
--- /dev/null
+++ b/examples/OSpipe/Cargo.toml
@@ -0,0 +1,73 @@
+[package]
+name = "ospipe"
+version = "0.1.0"
+edition = "2021"
+rust-version = "1.77"
+license = "MIT"
+description = "OSpipe: RuVector-enhanced personal AI memory system integrating with Screenpipe"
+authors = ["Ruvector Team"]
+repository = "https://github.com/ruvnet/ruvector"
+
+[dependencies]
+# Serialization (cross-platform)
+serde = { workspace = true }
+serde_json = { workspace = true }
+
+# Error handling and utilities (cross-platform)
+thiserror = { workspace = true }
+tracing = { workspace = true }
+
+# Time and UUID (cross-platform)
+chrono = { version = "0.4", features = ["serde"] }
+uuid = { version = "1.11", features = ["v4", "serde", "js"] }
+
+# Math (cross-platform)
+rand = { workspace = true }
+
+# Native-only: RuVector ecosystem (path dependencies)
+# These crates pull in platform-specific code (mmap, tokio, ring, etc.) that
+# does not compile for wasm32-unknown-unknown.
+[target.'cfg(not(target_arch = "wasm32"))'.dependencies]
+ruvector-core = { version = "2.0", path = "../../crates/ruvector-core" }
+ruvector-filter = { version = "2.0", path = "../../crates/ruvector-filter" }
+ruvector-cluster = { version = "2.0", path = "../../crates/ruvector-cluster" }
+ruvector-delta-core = { version = "0.1", path = "../../crates/ruvector-delta-core", features = ["serde"] }
+ruvector-router-core = { version = "2.0", path = "../../crates/ruvector-router-core" }
+ruvector-graph = { version = "2.0", path = "../../crates/ruvector-graph", default-features = false }
+ruvector-gnn = { version = "2.0", path = "../../crates/ruvector-gnn", default-features = false }
+cognitum-gate-kernel = { version = "0.1", path = "../../crates/cognitum-gate-kernel", default-features = true }
+ruqu-algorithms = { version = "2.0.5", path = "../../crates/ruqu-algorithms", default-features = false }
+ruvector-attention = { version = "0.1", path = "../../crates/ruvector-attention", default-features = false }
+
+# HTTP server dependencies (native only)
+axum = { version = "0.7", features = ["json"] }
+tower-http = { version = "0.6", features = ["cors"] }
+tower = { version = "0.5" }
+tokio = { workspace = true }
+tracing-subscriber = { version = "0.3", features = ["env-filter"] }
+
+# WASM-only dependencies
+[target.'cfg(target_arch = "wasm32")'.dependencies]
+wasm-bindgen = { workspace = true }
+js-sys = { workspace = true }
+serde-wasm-bindgen = "0.6"
+getrandom = { version = "0.2", features = ["js"] }
+console_error_panic_hook = { version = "0.1", optional = true }
+
+[target.'cfg(target_arch = "wasm32")'.dev-dependencies]
+wasm-bindgen-test = "0.3"
+
+[dev-dependencies]
+tokio = { workspace = true }
+uuid = { version = "1.11", features = ["v4"] }
+
+[features]
+default = ["console_error_panic_hook"]
+
+[lib]
+crate-type = ["cdylib", "rlib"]
+
+[[bin]]
+name = "ospipe-server"
+path = "src/bin/ospipe-server.rs"
+required-features = []
diff --git a/examples/OSpipe/README.md b/examples/OSpipe/README.md
new file mode 100644
index 000000000..4570b075b
--- /dev/null
+++ b/examples/OSpipe/README.md
@@ -0,0 +1,666 @@
+# OSpipe
+
+**RuVector-enhanced personal AI memory for Screenpipe**
+
+[](https://crates.io/crates/ospipe)
+[](https://docs.rs/ospipe)
+[](LICENSE)
+[](https://www.rust-lang.org/)
+[](https://webassembly.org/)
+
+---
+
+## What is OSpipe?
+
+[Screenpipe](https://github.com/mediar-ai/screenpipe) is an open-source desktop application that continuously records your screen, audio, and UI interactions locally. It builds a searchable timeline of everything you see, hear, and do on your computer. Out of the box, Screenpipe stores its data in SQLite with FTS5 full-text indexing -- effective for keyword lookups, but limited to literal string matching. If you search for "auth discussion," you will not find a frame that says "we talked about login security."
+
+OSpipe replaces Screenpipe's storage and search backend with the [RuVector](https://github.com/ruvnet/ruvector) ecosystem -- a collection of 70+ Rust crates providing HNSW vector search, graph neural networks, attention mechanisms, delta-change tracking, and more. Instead of keyword matching, OSpipe embeds every captured frame into a high-dimensional vector space and performs approximate nearest neighbor search, delivering true semantic recall. A query like "what was that API we discussed in standup?" will surface the relevant audio transcription even if those exact words never appeared.
+
+Everything stays local and private. OSpipe processes all data on-device with no cloud dependency. The safety gate automatically detects and redacts PII -- credit card numbers, Social Security numbers, and email addresses -- before content ever reaches the vector store. A cosine-similarity deduplication window prevents consecutive identical frames (like a static desktop) from bloating storage. Age-based quantization progressively compresses older embeddings from 32-bit floats down to 1-bit binary, cutting long-term memory usage by 97%.
+
+OSpipe ships as a Rust crate, a TypeScript SDK, and a WASM library. It runs natively on Windows, macOS, and Linux, and can run entirely in the browser via WebAssembly at bundles as small as 11.8KB.
+
+**Ask your computer what you saw, heard, and did -- with semantic understanding.**
+
+---
+
+## Features
+
+- **Semantic Vector Search** -- HNSW index via `ruvector-core` with 61us p50 query latency
+- **PII Safety Gate** -- automatic redaction of credit card numbers, SSNs, and email addresses before storage
+- **Frame Deduplication** -- cosine similarity sliding window eliminates near-duplicate captures
+- **Hybrid Search** -- weighted combination of semantic vector similarity and keyword term overlap
+- **Query Router** -- automatically routes queries to the optimal backend (Semantic, Keyword, Graph, Temporal, or Hybrid)
+- **WASM Support** -- runs entirely in the browser with bundles from 11.8KB (micro) to 350KB (full)
+- **TypeScript SDK** -- `@ruvector/ospipe` for Node.js and browser integration
+- **Configurable Quantization** -- 4-tier age-based compression: f32 -> int8 -> product -> binary
+- **Cross-Platform** -- native builds for Windows, macOS, Linux; WASM for browsers
+
+---
+
+## Architecture
+
+```
+ OSpipe Ingestion Pipeline
+ =========================
+
+ Screenpipe -----> Capture -----> Safety Gate -----> Dedup -----> Embed -----> VectorStore
+ (Screen/Audio/UI) (CapturedFrame) (PII Redaction) (Cosine Window) (HNSW) |
+ |
+ Search Router <------------+
+ | | | | |
+ Semantic Keyword Graph Temporal Hybrid
+```
+
+Frames flow left to right through the ingestion pipeline. Each captured frame passes through:
+
+1. **Safety Gate** -- PII detection and redaction; content may be allowed, redacted, or denied
+2. **Deduplication** -- cosine similarity check against a sliding window of recent embeddings
+3. **Embedding** -- text content is encoded into a normalized vector
+4. **Vector Store** -- the embedding is indexed for approximate nearest neighbor retrieval
+
+Queries enter through the **Search Router**, which analyzes the query string and dispatches to the optimal backend.
+
+---
+
+## Quick Start
+
+### Rust
+
+Add OSpipe to your `Cargo.toml`:
+
+```toml
+[dependencies]
+ospipe = { path = "examples/OSpipe" }
+```
+
+Create a pipeline, ingest frames, and search:
+
+```rust
+use ospipe::config::OsPipeConfig;
+use ospipe::pipeline::ingestion::IngestionPipeline;
+use ospipe::capture::{CapturedFrame, CaptureSource, FrameContent, FrameMetadata};
+
+fn main() -> ospipe::error::Result<()> {
+ // Initialize with default configuration
+ let config = OsPipeConfig::default();
+ let mut pipeline = IngestionPipeline::new(config)?;
+
+ // Ingest a screen capture
+ let frame = CapturedFrame::new_screen(
+ "Firefox",
+ "Meeting Notes - Google Docs",
+ "Discussion about authentication: we decided to use JWT with refresh tokens",
+ 0,
+ );
+ let result = pipeline.ingest(frame)?;
+ println!("Ingest result: {:?}", result);
+
+ // Ingest an audio transcription
+ let audio = CapturedFrame::new_audio(
+ "Built-in Microphone",
+ "Let's revisit the login flow next sprint",
+ Some("Alice"),
+ );
+ pipeline.ingest(audio)?;
+
+ // Search semantically
+ let query_embedding = pipeline.embedding_engine().embed("auth token discussion");
+ let results = pipeline.vector_store().search(&query_embedding, 5)?;
+
+ for hit in &results {
+ println!("Score: {:.4} | {:?}", hit.score, hit.metadata);
+ }
+
+ // Print pipeline statistics
+ let stats = pipeline.stats();
+ println!(
+ "Ingested: {} | Deduped: {} | Denied: {} | Redacted: {}",
+ stats.total_ingested, stats.total_deduplicated,
+ stats.total_denied, stats.total_redacted
+ );
+
+ Ok(())
+}
+```
+
+### TypeScript
+
+```typescript
+import { OsPipe } from "@ruvector/ospipe";
+
+const client = new OsPipe({ baseUrl: "http://localhost:3030" });
+
+// Ingest a captured frame
+await client.ingest({
+ source: "screen",
+ app: "Chrome",
+ window: "Jira Board",
+ content: "Sprint 14 planning: migrate auth to OAuth2",
+});
+
+// Semantic search
+const results = await client.queryRuVector(
+ "what did I discuss in the meeting about authentication?"
+);
+
+for (const hit of results) {
+ console.log(`[${hit.score.toFixed(3)}] ${hit.metadata.text}`);
+}
+```
+
+### WASM (Browser)
+
+```javascript
+import { OsPipeWasm } from "@ruvector/ospipe-wasm";
+
+// Initialize with 384-dimensional embeddings
+const pipe = new OsPipeWasm(384);
+
+// Embed and insert content
+const embedding = pipe.embed_text("meeting notes about auth migration to OAuth2");
+pipe.insert("frame-001", embedding, '{"app":"Chrome","window":"Jira"}', Date.now());
+
+// Embed a query and search
+const queryEmbedding = pipe.embed_text("what was the auth discussion about?");
+const results = pipe.search(queryEmbedding, 5);
+console.log("Results:", results);
+
+// Safety check before storage
+const safety = pipe.safety_check("my card is 4111-1111-1111-1111");
+console.log("Safety:", safety); // "deny"
+
+// Query routing
+const route = pipe.route_query("what happened yesterday?");
+console.log("Route:", route); // "Temporal"
+
+// Pipeline statistics
+console.log("Stats:", pipe.stats());
+```
+
+---
+
+## Comparison: Screenpipe vs OSpipe
+
+| Feature | Screenpipe (FTS5) | OSpipe (RuVector) |
+|---|---|---|
+| Search Type | Keyword (FTS5) | Semantic + Keyword + Graph + Temporal |
+| Search Latency | ~1ms (FTS5) | 61us (HNSW p50) |
+| Content Relations | None | Knowledge Graph (Cypher) |
+| Temporal Analysis | Basic SQL | Delta-behavior tracking |
+| PII Protection | Basic | Credit card, SSN, email redaction |
+| Deduplication | None | Cosine similarity sliding window |
+| Browser Support | None | WASM (11.8KB - 350KB) |
+| Quantization | None | 4-tier age-based (f32 -> binary) |
+| Privacy | Local-first | Local-first + PII redaction |
+| Query Routing | None | Auto-routes to optimal backend |
+| Hybrid Search | None | Weighted semantic + keyword fusion |
+| Metadata Filtering | SQL WHERE | App, time range, content type, monitor |
+
+---
+
+## RuVector Crate Integration
+
+| RuVector Crate | OSpipe Usage | Status |
+|---|---|---|
+| `ruvector-core` | HNSW vector storage and nearest neighbor search | Integrated |
+| `ruvector-filter` | Metadata filtering (app, time, content type) | Integrated |
+| `ruvector-cluster` | Frame deduplication via cosine similarity | Integrated |
+| `ruvector-delta-core` | Change tracking and delta-behavior analysis | Integrated |
+| `ruvector-router-core` | Query routing to optimal search backend | Integrated |
+| `cognitum-gate-kernel` | AI safety gate decisions (allow/redact/deny) | Integrated |
+| `ruvector-graph` | Knowledge graph for entity relationships | Phase 2 |
+| `ruvector-attention` | Content prioritization and relevance weighting | Phase 3 |
+| `ruvector-gnn` | Learned search improvement via graph neural nets | Phase 3 |
+| `ruqu-algorithms` | Quantum-inspired search acceleration | Phase 4 |
+
+---
+
+## Configuration
+
+
+Full Configuration Reference
+
+### `OsPipeConfig`
+
+Top-level configuration with nested subsystem configs. All fields have sensible defaults.
+
+```rust
+use ospipe::config::OsPipeConfig;
+
+let config = OsPipeConfig::default();
+// config.data_dir = "~/.ospipe"
+// config.capture = CaptureConfig { ... }
+// config.storage = StorageConfig { ... }
+// config.search = SearchConfig { ... }
+// config.safety = SafetyConfig { ... }
+```
+
+### `CaptureConfig`
+
+| Field | Type | Default | Description |
+|---|---|---|---|
+| `fps` | `f32` | `1.0` | Frames per second for screen capture |
+| `audio_chunk_secs` | `u32` | `30` | Duration of audio chunks in seconds |
+| `excluded_apps` | `Vec` | `["1Password", "Keychain Access"]` | Applications excluded from capture |
+| `skip_private_windows` | `bool` | `true` | Skip windows marked as private/incognito |
+
+### `StorageConfig`
+
+| Field | Type | Default | Description |
+|---|---|---|---|
+| `embedding_dim` | `usize` | `384` | Dimensionality of embedding vectors |
+| `hnsw_m` | `usize` | `32` | HNSW M parameter (max connections per layer) |
+| `hnsw_ef_construction` | `usize` | `200` | HNSW ef_construction (index build quality) |
+| `hnsw_ef_search` | `usize` | `100` | HNSW ef_search (query-time accuracy) |
+| `dedup_threshold` | `f32` | `0.95` | Cosine similarity threshold for deduplication |
+| `quantization_tiers` | `Vec` | 4 tiers (see below) | Age-based quantization schedule |
+
+### `SearchConfig`
+
+| Field | Type | Default | Description |
+|---|---|---|---|
+| `default_k` | `usize` | `10` | Default number of results to return |
+| `hybrid_weight` | `f32` | `0.7` | Semantic vs keyword weight (1.0 = pure semantic, 0.0 = pure keyword) |
+| `mmr_lambda` | `f32` | `0.5` | MMR diversity vs relevance tradeoff |
+| `rerank_enabled` | `bool` | `false` | Whether to enable result reranking |
+
+### `SafetyConfig`
+
+| Field | Type | Default | Description |
+|---|---|---|---|
+| `pii_detection` | `bool` | `true` | Enable PII detection (emails) |
+| `credit_card_redaction` | `bool` | `true` | Enable credit card number redaction |
+| `ssn_redaction` | `bool` | `true` | Enable SSN redaction |
+| `custom_patterns` | `Vec` | `[]` | Custom substring patterns that trigger denial |
+
+### Example: Custom Configuration
+
+```rust
+use ospipe::config::*;
+use std::path::PathBuf;
+
+let config = OsPipeConfig {
+ data_dir: PathBuf::from("/var/lib/ospipe"),
+ capture: CaptureConfig {
+ fps: 0.5,
+ audio_chunk_secs: 60,
+ excluded_apps: vec![
+ "1Password".into(),
+ "Signal".into(),
+ "Bitwarden".into(),
+ ],
+ skip_private_windows: true,
+ },
+ storage: StorageConfig {
+ embedding_dim: 768, // Use a larger model
+ hnsw_m: 48, // More connections for better recall
+ hnsw_ef_construction: 400,
+ hnsw_ef_search: 200,
+ dedup_threshold: 0.98, // Stricter deduplication
+ ..Default::default()
+ },
+ search: SearchConfig {
+ default_k: 20,
+ hybrid_weight: 0.8, // Lean more toward semantic
+ mmr_lambda: 0.6,
+ rerank_enabled: true,
+ },
+ safety: SafetyConfig {
+ pii_detection: true,
+ credit_card_redaction: true,
+ ssn_redaction: true,
+ custom_patterns: vec![
+ "INTERNAL_ONLY".into(),
+ "CONFIDENTIAL".into(),
+ ],
+ },
+};
+```
+
+
+
+---
+
+## Safety Gate
+
+
+PII Detection Details
+
+The safety gate inspects all captured content before it enters the ingestion pipeline. It operates in three modes:
+
+### Safety Decisions
+
+| Decision | Behavior | When |
+|---|---|---|
+| `Allow` | Content stored as-is | No sensitive patterns detected |
+| `AllowRedacted(String)` | Content stored with PII replaced by tokens | PII detected, redaction enabled |
+| `Deny { reason }` | Content rejected, not stored | Custom deny pattern matched |
+
+### Detected PII Patterns
+
+**Credit Cards** -- sequences of 13-16 digits (with optional spaces or dashes):
+```
+4111111111111111 -> [CC_REDACTED]
+4111 1111 1111 1111 -> [CC_REDACTED]
+4111-1111-1111-1111 -> [CC_REDACTED]
+```
+
+**Social Security Numbers** -- XXX-XX-XXXX format:
+```
+123-45-6789 -> [SSN_REDACTED]
+```
+
+**Email Addresses** -- word@domain.tld patterns:
+```
+user@example.com -> [EMAIL_REDACTED]
+admin@company.org -> [EMAIL_REDACTED]
+```
+
+**Custom Patterns** -- configurable substring deny list. When a custom pattern is matched, the entire frame is denied (not just redacted):
+```rust
+let config = SafetyConfig {
+ custom_patterns: vec!["TOP_SECRET".to_string(), "CLASSIFIED".to_string()],
+ ..Default::default()
+};
+```
+
+### WASM Safety API
+
+The WASM bindings expose a simplified safety classifier:
+
+```javascript
+pipe.safety_check("my card is 4111-1111-1111-1111"); // "deny"
+pipe.safety_check("set password to foo123"); // "redact"
+pipe.safety_check("the weather is nice today"); // "allow"
+```
+
+The WASM classifier also detects sensitive keywords: `password`, `secret`, `api_key`, `api-key`, `apikey`, `token`, `private_key`, `private-key`.
+
+
+
+---
+
+## Advanced Configuration
+
+
+WASM Deployment
+
+### Bundle Tiers
+
+OSpipe provides four WASM bundle sizes depending on which features you need:
+
+| Tier | Size | Features |
+|---|---|---|
+| **Micro** | 11.8KB | Embedding + vector search only |
+| **Standard** | 225KB | Full pipeline (embed, insert, search, filtered search) |
+| **Full** | 350KB | + deduplication + safety gate + query routing |
+| **AI** | 2.5MB | + on-device neural inference (ONNX) |
+
+### Web Worker Setup
+
+For best performance, run OSpipe in a Web Worker to avoid blocking the main thread:
+
+```javascript
+// worker.js
+import { OsPipeWasm } from "@ruvector/ospipe-wasm";
+
+const pipe = new OsPipeWasm(384);
+
+self.onmessage = (event) => {
+ const { type, payload } = event.data;
+
+ switch (type) {
+ case "insert":
+ const emb = pipe.embed_text(payload.text);
+ pipe.insert(payload.id, emb, JSON.stringify(payload.metadata), Date.now());
+ self.postMessage({ type: "inserted", id: payload.id });
+ break;
+
+ case "search":
+ const queryEmb = pipe.embed_text(payload.query);
+ const results = pipe.search(queryEmb, payload.k || 10);
+ self.postMessage({ type: "results", data: results });
+ break;
+ }
+};
+```
+
+### SharedArrayBuffer
+
+For multi-threaded WASM (e.g., parallel batch embedding), set the required headers:
+
+```
+Cross-Origin-Opener-Policy: same-origin
+Cross-Origin-Embedder-Policy: require-corp
+```
+
+
+
+
+Cross-Platform Build
+
+### Build Targets
+
+```bash
+# Native (current platform)
+cargo build -p ospipe --release
+
+# WASM (browser)
+cargo build -p ospipe --target wasm32-unknown-unknown --release
+
+# Generate JS bindings
+wasm-pack build examples/OSpipe --target web --release
+
+# Windows (cross-compile)
+cross build -p ospipe --target x86_64-pc-windows-gnu --release
+
+# macOS ARM (cross-compile)
+cross build -p ospipe --target aarch64-apple-darwin --release
+
+# macOS Intel (cross-compile)
+cross build -p ospipe --target x86_64-apple-darwin --release
+
+# Linux ARM (cross-compile)
+cross build -p ospipe --target aarch64-unknown-linux-gnu --release
+```
+
+### Conditional Compilation
+
+OSpipe uses conditional compilation to separate native and WASM dependencies:
+
+- **Native** (`cfg(not(target_arch = "wasm32"))`) -- links against `ruvector-core`, `ruvector-filter`, `ruvector-cluster`, `ruvector-delta-core`, `ruvector-router-core`, and `cognitum-gate-kernel`
+- **WASM** (`cfg(target_arch = "wasm32")`) -- uses `wasm-bindgen`, `js-sys`, `serde-wasm-bindgen`, and `getrandom` with the `js` feature
+
+The `src/wasm/helpers.rs` module contains pure Rust functions (cosine similarity, hash embedding, safety classification, query routing) that compile on all targets and are tested natively.
+
+
+
+
+Quantization Tiers
+
+OSpipe progressively compresses older embeddings to reduce long-term storage costs. The default quantization schedule:
+
+| Age | Method | Bits/Dim | Memory vs f32 | Description |
+|---|---|---|---|---|
+| 0 hours | None (f32) | 32 | 100% | Full precision for recent content |
+| 24 hours | Scalar (int8) | 8 | 25% | Minimal quality loss, 4x compression |
+| 1 week | Product | ~2 | ~6% | Codebook-based compression |
+| 30 days | Binary | 1 | 3% | Single bit per dimension, 97% savings |
+
+### Custom Tiers
+
+```rust
+use ospipe::config::{StorageConfig, QuantizationTier, QuantizationMethod};
+
+let storage = StorageConfig {
+ quantization_tiers: vec![
+ QuantizationTier { age_hours: 0, method: QuantizationMethod::None },
+ QuantizationTier { age_hours: 12, method: QuantizationMethod::Scalar },
+ QuantizationTier { age_hours: 72, method: QuantizationMethod::Product },
+ QuantizationTier { age_hours: 360, method: QuantizationMethod::Binary },
+ ],
+ ..Default::default()
+};
+```
+
+### Memory Estimate
+
+For 1 million frames at 384 dimensions:
+
+| Tier | Bytes/Vector | Total (1M vectors) |
+|---|---|---|
+| f32 | 1,536 | 1.43 GB |
+| int8 | 384 | 366 MB |
+| Product | ~96 | ~91 MB |
+| Binary | 48 | 46 MB |
+
+With the default age distribution (most content aging past 30 days), long-term average storage is approximately 50-80 MB per million frames.
+
+
+
+---
+
+## API Reference
+
+### Rust API
+
+#### Core Types
+
+| Type | Module | Description |
+|---|---|---|
+| `OsPipeConfig` | `config` | Top-level configuration |
+| `CaptureConfig` | `config` | Capture subsystem settings |
+| `StorageConfig` | `config` | HNSW and quantization settings |
+| `SearchConfig` | `config` | Search weights and defaults |
+| `SafetyConfig` | `config` | PII detection toggles |
+| `CapturedFrame` | `capture` | A captured screen/audio/UI frame |
+| `CaptureSource` | `capture` | Source enum: `Screen`, `Audio`, `Ui` |
+| `FrameContent` | `capture` | Content enum: `OcrText`, `Transcription`, `UiEvent` |
+| `FrameMetadata` | `capture` | Metadata (app, window, monitor, confidence, language) |
+| `OsPipeError` | `error` | Unified error type |
+
+#### Pipeline
+
+| Type / Function | Module | Description |
+|---|---|---|
+| `IngestionPipeline::new(config)` | `pipeline::ingestion` | Create a new pipeline |
+| `IngestionPipeline::ingest(frame)` | `pipeline::ingestion` | Ingest a single frame |
+| `IngestionPipeline::ingest_batch(frames)` | `pipeline::ingestion` | Ingest multiple frames |
+| `IngestionPipeline::stats()` | `pipeline::ingestion` | Get ingestion statistics |
+| `IngestResult` | `pipeline::ingestion` | Enum: `Stored`, `Deduplicated`, `Denied` |
+| `PipelineStats` | `pipeline::ingestion` | Counters for ingested/deduped/denied/redacted |
+| `FrameDeduplicator` | `pipeline::dedup` | Cosine similarity sliding window |
+
+#### Storage
+
+| Type / Function | Module | Description |
+|---|---|---|
+| `VectorStore::new(config)` | `storage::vector_store` | Create a new vector store |
+| `VectorStore::insert(frame, embedding)` | `storage::vector_store` | Insert a frame with its embedding |
+| `VectorStore::search(query, k)` | `storage::vector_store` | Top-k nearest neighbor search |
+| `VectorStore::search_filtered(query, k, filter)` | `storage::vector_store` | Search with metadata filters |
+| `SearchResult` | `storage::vector_store` | Result with id, score, metadata |
+| `SearchFilter` | `storage::vector_store` | Filter by app, time range, content type, monitor |
+| `StoredEmbedding` | `storage::vector_store` | Stored vector with metadata and timestamp |
+| `EmbeddingEngine::new(dim)` | `storage::embedding` | Create an embedding engine |
+| `EmbeddingEngine::embed(text)` | `storage::embedding` | Generate a normalized embedding |
+| `EmbeddingEngine::batch_embed(texts)` | `storage::embedding` | Batch embedding generation |
+| `cosine_similarity(a, b)` | `storage::embedding` | Cosine similarity between two vectors |
+
+#### Search
+
+| Type / Function | Module | Description |
+|---|---|---|
+| `QueryRouter::new()` | `search::router` | Create a query router |
+| `QueryRouter::route(query)` | `search::router` | Route a query to optimal backend |
+| `QueryRoute` | `search::router` | Enum: `Semantic`, `Keyword`, `Graph`, `Temporal`, `Hybrid` |
+| `HybridSearch::new(weight)` | `search::hybrid` | Create a hybrid search with semantic weight |
+| `HybridSearch::search(store, query, emb, k)` | `search::hybrid` | Combined semantic + keyword search |
+
+#### Safety
+
+| Type / Function | Module | Description |
+|---|---|---|
+| `SafetyGate::new(config)` | `safety` | Create a safety gate |
+| `SafetyGate::check(content)` | `safety` | Check content, return safety decision |
+| `SafetyGate::redact(content)` | `safety` | Redact and return cleaned content |
+| `SafetyDecision` | `safety` | Enum: `Allow`, `AllowRedacted(String)`, `Deny { reason }` |
+
+### WASM API (`OsPipeWasm`)
+
+| Method | Parameters | Returns | Description |
+|---|---|---|---|
+| `new(dimension)` | `usize` | `OsPipeWasm` | Constructor |
+| `insert(id, embedding, metadata, timestamp)` | `&str, &[f32], &str, f64` | `Result<(), JsValue>` | Insert a frame |
+| `search(query_embedding, k)` | `&[f32], usize` | `JsValue` (JSON array) | Semantic search |
+| `search_filtered(query_embedding, k, start, end)` | `&[f32], usize, f64, f64` | `JsValue` (JSON array) | Time-filtered search |
+| `is_duplicate(embedding, threshold)` | `&[f32], f32` | `bool` | Deduplication check |
+| `embed_text(text)` | `&str` | `Vec` | Hash-based text embedding |
+| `batch_embed(texts)` | `JsValue` (Array) | `JsValue` (Array) | Batch text embedding |
+| `safety_check(content)` | `&str` | `String` | Returns "allow", "redact", or "deny" |
+| `route_query(query)` | `&str` | `String` | Returns "Semantic", "Keyword", "Graph", or "Temporal" |
+| `len()` | -- | `usize` | Number of stored embeddings |
+| `stats()` | -- | `String` (JSON) | Pipeline statistics |
+
+---
+
+## Testing
+
+```bash
+# Run all 56 tests
+cargo test -p ospipe
+
+# Run with verbose output
+cargo test -p ospipe -- --nocapture
+
+# Run only integration tests
+cargo test -p ospipe --test integration
+
+# Run only unit tests (embedding, WASM helpers)
+cargo test -p ospipe --lib
+
+# Build for WASM (verify compilation)
+cargo build -p ospipe --target wasm32-unknown-unknown
+
+# Build with wasm-pack for JS bindings
+wasm-pack build examples/OSpipe --target web
+```
+
+### Test Coverage
+
+| Test Category | Count | Module |
+|---|---|---|
+| Configuration | 2 | `tests/integration.rs` |
+| Capture frames | 3 | `tests/integration.rs` |
+| Embedding engine | 6 | `src/storage/embedding.rs` |
+| Vector store | 4 | `tests/integration.rs` |
+| Deduplication | 2 | `tests/integration.rs` |
+| Safety gate | 6 | `tests/integration.rs` |
+| Query routing | 4 | `tests/integration.rs` |
+| Hybrid search | 2 | `tests/integration.rs` |
+| Ingestion pipeline | 5 | `tests/integration.rs` |
+| Cosine similarity | 3 | `tests/integration.rs` |
+| WASM helpers | 18 | `src/wasm/helpers.rs` |
+| **Total** | **56** | |
+
+---
+
+## Related
+
+- [ADR: OSpipe Screenpipe Integration](./ADR-OSpipe-screenpipe-integration.md) -- Architecture Decision Record with full design rationale
+- [Screenpipe](https://github.com/mediar-ai/screenpipe) -- Open-source local-first desktop recording + AI memory
+- [RuVector](https://github.com/ruvnet/ruvector) -- 70+ Rust crates for vector search, graph neural networks, and attention mechanisms
+- `@ruvector/ospipe` -- TypeScript SDK (npm)
+- `@ruvector/ospipe-wasm` -- WASM package (npm)
+
+---
+
+## License
+
+Licensed under either of:
+
+- MIT License ([LICENSE-MIT](../../LICENSE-MIT) or http://opensource.org/licenses/MIT)
+- Apache License, Version 2.0 ([LICENSE-APACHE](../../LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0)
+
+at your option.
diff --git a/examples/OSpipe/src/bin/ospipe-server.rs b/examples/OSpipe/src/bin/ospipe-server.rs
new file mode 100644
index 000000000..e26bce815
--- /dev/null
+++ b/examples/OSpipe/src/bin/ospipe-server.rs
@@ -0,0 +1,111 @@
+//! OSpipe REST API server binary.
+//!
+//! Starts the OSpipe HTTP server with a default pipeline configuration.
+//! The server exposes semantic search, query routing, health, and stats endpoints.
+//!
+//! ## Usage
+//!
+//! ```bash
+//! ospipe-server # default port 3030
+//! ospipe-server --port 8080 # custom port
+//! ospipe-server --data-dir /tmp/ospipe # custom data directory
+//! ```
+
+use std::sync::Arc;
+use tokio::sync::RwLock;
+
+fn main() {
+ // Parse CLI arguments
+ let args: Vec = std::env::args().collect();
+ let mut port: u16 = 3030;
+ let mut data_dir: Option = None;
+
+ let mut i = 1;
+ while i < args.len() {
+ match args[i].as_str() {
+ "--port" | "-p" => {
+ if i + 1 < args.len() {
+ port = args[i + 1].parse().unwrap_or_else(|_| {
+ eprintln!("Invalid port: {}", args[i + 1]);
+ std::process::exit(1);
+ });
+ i += 2;
+ } else {
+ eprintln!("--port requires a value");
+ std::process::exit(1);
+ }
+ }
+ "--data-dir" | "-d" => {
+ if i + 1 < args.len() {
+ data_dir = Some(args[i + 1].clone());
+ i += 2;
+ } else {
+ eprintln!("--data-dir requires a value");
+ std::process::exit(1);
+ }
+ }
+ "--help" | "-h" => {
+ println!("OSpipe Server - RuVector-enhanced personal AI memory");
+ println!();
+ println!("Usage: ospipe-server [OPTIONS]");
+ println!();
+ println!("Options:");
+ println!(" -p, --port Listen port (default: 3030)");
+ println!(" -d, --data-dir Data directory (default: ~/.ospipe)");
+ println!(" -h, --help Show this help message");
+ println!(" -V, --version Show version");
+ std::process::exit(0);
+ }
+ "--version" | "-V" => {
+ println!("ospipe-server {}", env!("CARGO_PKG_VERSION"));
+ std::process::exit(0);
+ }
+ other => {
+ eprintln!("Unknown argument: {}", other);
+ eprintln!("Run with --help for usage information");
+ std::process::exit(1);
+ }
+ }
+ }
+
+ // Initialize tracing
+ tracing_subscriber::fmt()
+ .with_env_filter(
+ tracing_subscriber::EnvFilter::try_from_default_env()
+ .unwrap_or_else(|_| tracing_subscriber::EnvFilter::new("info")),
+ )
+ .init();
+
+ // Build configuration
+ let mut config = ospipe::config::OsPipeConfig::default();
+ if let Some(dir) = data_dir {
+ config.data_dir = std::path::PathBuf::from(dir);
+ }
+
+ // Create the pipeline
+ let pipeline = ospipe::pipeline::ingestion::IngestionPipeline::new(config)
+ .unwrap_or_else(|e| {
+ eprintln!("Failed to initialize pipeline: {}", e);
+ std::process::exit(1);
+ });
+
+ let state = ospipe::server::ServerState {
+ pipeline: Arc::new(RwLock::new(pipeline)),
+ router: Arc::new(ospipe::search::QueryRouter::new()),
+ started_at: std::time::Instant::now(),
+ };
+
+ // Start the async runtime and server
+ let rt = tokio::runtime::Runtime::new().unwrap_or_else(|e| {
+ eprintln!("Failed to create Tokio runtime: {}", e);
+ std::process::exit(1);
+ });
+
+ rt.block_on(async {
+ tracing::info!("Starting OSpipe server on port {}", port);
+ if let Err(e) = ospipe::server::start_server(state, port).await {
+ eprintln!("Server error: {}", e);
+ std::process::exit(1);
+ }
+ });
+}
diff --git a/examples/OSpipe/src/capture/frame.rs b/examples/OSpipe/src/capture/frame.rs
new file mode 100644
index 000000000..bc9feb34c
--- /dev/null
+++ b/examples/OSpipe/src/capture/frame.rs
@@ -0,0 +1,164 @@
+//! Captured frame data structures.
+
+use chrono::{DateTime, Utc};
+use serde::{Deserialize, Serialize};
+use uuid::Uuid;
+
+/// A single captured frame from any Screenpipe source.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct CapturedFrame {
+ /// Unique identifier for this frame.
+ pub id: Uuid,
+ /// When this frame was captured.
+ pub timestamp: DateTime,
+ /// The source that produced this frame.
+ pub source: CaptureSource,
+ /// The actual content of the frame.
+ pub content: FrameContent,
+ /// Additional metadata about the frame.
+ pub metadata: FrameMetadata,
+}
+
+/// The source that produced a captured frame.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum CaptureSource {
+ /// Screen capture with OCR.
+ Screen {
+ /// Monitor index.
+ monitor: u32,
+ /// Foreground application name.
+ app: String,
+ /// Window title.
+ window: String,
+ },
+ /// Audio capture with transcription.
+ Audio {
+ /// Audio device name.
+ device: String,
+ /// Detected speaker (if diarization is available).
+ speaker: Option,
+ },
+ /// UI accessibility event.
+ Ui {
+ /// Type of UI event (e.g., "click", "focus", "scroll").
+ event_type: String,
+ },
+}
+
+/// The actual content extracted from a captured frame.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum FrameContent {
+ /// OCR text extracted from a screen capture.
+ OcrText(String),
+ /// Transcribed text from an audio capture.
+ Transcription(String),
+ /// A UI accessibility event description.
+ UiEvent(String),
+}
+
+/// Metadata associated with a captured frame.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct FrameMetadata {
+ /// Name of the foreground application, if known.
+ pub app_name: Option,
+ /// Title of the active window, if known.
+ pub window_title: Option,
+ /// Monitor index, if applicable.
+ pub monitor_id: Option,
+ /// Confidence score for the extracted content (0.0 to 1.0).
+ pub confidence: f32,
+ /// Detected language code (e.g., "en", "es"), if known.
+ pub language: Option,
+}
+
+impl CapturedFrame {
+ /// Create a new frame from a screen capture with OCR text.
+ pub fn new_screen(app: &str, window: &str, ocr_text: &str, monitor: u32) -> Self {
+ Self {
+ id: Uuid::new_v4(),
+ timestamp: Utc::now(),
+ source: CaptureSource::Screen {
+ monitor,
+ app: app.to_string(),
+ window: window.to_string(),
+ },
+ content: FrameContent::OcrText(ocr_text.to_string()),
+ metadata: FrameMetadata {
+ app_name: Some(app.to_string()),
+ window_title: Some(window.to_string()),
+ monitor_id: Some(monitor),
+ confidence: 0.9,
+ language: None,
+ },
+ }
+ }
+
+ /// Create a new frame from an audio transcription.
+ pub fn new_audio(device: &str, transcription: &str, speaker: Option<&str>) -> Self {
+ Self {
+ id: Uuid::new_v4(),
+ timestamp: Utc::now(),
+ source: CaptureSource::Audio {
+ device: device.to_string(),
+ speaker: speaker.map(|s| s.to_string()),
+ },
+ content: FrameContent::Transcription(transcription.to_string()),
+ metadata: FrameMetadata {
+ app_name: None,
+ window_title: None,
+ monitor_id: None,
+ confidence: 0.85,
+ language: None,
+ },
+ }
+ }
+
+ /// Create a new frame from a UI accessibility event.
+ pub fn new_ui_event(event_type: &str, description: &str) -> Self {
+ Self {
+ id: Uuid::new_v4(),
+ timestamp: Utc::now(),
+ source: CaptureSource::Ui {
+ event_type: event_type.to_string(),
+ },
+ content: FrameContent::UiEvent(description.to_string()),
+ metadata: FrameMetadata {
+ app_name: None,
+ window_title: None,
+ monitor_id: None,
+ confidence: 1.0,
+ language: None,
+ },
+ }
+ }
+
+ /// Extract the text content from this frame regardless of source type.
+ pub fn text_content(&self) -> &str {
+ match &self.content {
+ FrameContent::OcrText(text) => text,
+ FrameContent::Transcription(text) => text,
+ FrameContent::UiEvent(text) => text,
+ }
+ }
+
+ /// Return the content type as a string label.
+ pub fn content_type(&self) -> &str {
+ match &self.content {
+ FrameContent::OcrText(_) => "ocr",
+ FrameContent::Transcription(_) => "transcription",
+ FrameContent::UiEvent(_) => "ui_event",
+ }
+ }
+}
+
+impl Default for FrameMetadata {
+ fn default() -> Self {
+ Self {
+ app_name: None,
+ window_title: None,
+ monitor_id: None,
+ confidence: 0.0,
+ language: None,
+ }
+ }
+}
diff --git a/examples/OSpipe/src/capture/mod.rs b/examples/OSpipe/src/capture/mod.rs
new file mode 100644
index 000000000..0fd34c354
--- /dev/null
+++ b/examples/OSpipe/src/capture/mod.rs
@@ -0,0 +1,9 @@
+//! Capture module for processing screen, audio, and UI event data.
+//!
+//! This module defines the data structures that represent captured frames
+//! from Screenpipe sources: OCR text from screen recordings, audio
+//! transcriptions, and UI accessibility events.
+
+pub mod frame;
+
+pub use frame::{CaptureSource, CapturedFrame, FrameContent, FrameMetadata};
diff --git a/examples/OSpipe/src/config.rs b/examples/OSpipe/src/config.rs
new file mode 100644
index 000000000..2dca94cae
--- /dev/null
+++ b/examples/OSpipe/src/config.rs
@@ -0,0 +1,176 @@
+//! Configuration types for all OSpipe subsystems.
+
+use serde::{Deserialize, Serialize};
+use std::path::PathBuf;
+
+/// Top-level OSpipe configuration.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct OsPipeConfig {
+ /// Directory for persistent data storage.
+ pub data_dir: PathBuf,
+ /// Capture subsystem configuration.
+ pub capture: CaptureConfig,
+ /// Storage subsystem configuration.
+ pub storage: StorageConfig,
+ /// Search subsystem configuration.
+ pub search: SearchConfig,
+ /// Safety gate configuration.
+ pub safety: SafetyConfig,
+}
+
+/// Configuration for the capture subsystem.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct CaptureConfig {
+ /// Frames per second for screen capture. Default: 1.0
+ pub fps: f32,
+ /// Duration of audio chunks in seconds. Default: 30
+ pub audio_chunk_secs: u32,
+ /// Application names to exclude from capture.
+ pub excluded_apps: Vec,
+ /// Whether to skip windows marked as private/incognito.
+ pub skip_private_windows: bool,
+}
+
+/// Configuration for the vector storage subsystem.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct StorageConfig {
+ /// Dimensionality of embedding vectors. Default: 384
+ pub embedding_dim: usize,
+ /// HNSW M parameter (max connections per layer). Default: 32
+ pub hnsw_m: usize,
+ /// HNSW ef_construction parameter. Default: 200
+ pub hnsw_ef_construction: usize,
+ /// HNSW ef_search parameter. Default: 100
+ pub hnsw_ef_search: usize,
+ /// Cosine similarity threshold for deduplication. Default: 0.95
+ pub dedup_threshold: f32,
+ /// Quantization tiers for aging data.
+ pub quantization_tiers: Vec,
+}
+
+/// A quantization tier that defines how vectors are compressed based on age.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct QuantizationTier {
+ /// Age in hours after which this quantization is applied.
+ pub age_hours: u64,
+ /// The quantization method to use.
+ pub method: QuantizationMethod,
+}
+
+/// Supported vector quantization methods.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub enum QuantizationMethod {
+ /// No quantization (full precision f32).
+ None,
+ /// Scalar quantization (int8).
+ Scalar,
+ /// Product quantization.
+ Product,
+ /// Binary quantization (1-bit per dimension).
+ Binary,
+}
+
+/// Configuration for the search subsystem.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct SearchConfig {
+ /// Default number of results to return. Default: 10
+ pub default_k: usize,
+ /// Weight for semantic vs keyword search in hybrid mode. Default: 0.7
+ /// 1.0 = pure semantic, 0.0 = pure keyword.
+ pub hybrid_weight: f32,
+ /// MMR lambda for diversity vs relevance tradeoff. Default: 0.5
+ pub mmr_lambda: f32,
+ /// Whether to enable result reranking.
+ pub rerank_enabled: bool,
+}
+
+/// Configuration for the safety gate subsystem.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct SafetyConfig {
+ /// Enable PII detection (names, emails, phone numbers).
+ pub pii_detection: bool,
+ /// Enable credit card number redaction.
+ pub credit_card_redaction: bool,
+ /// Enable SSN redaction.
+ pub ssn_redaction: bool,
+ /// Custom regex-like patterns to redact (simple substring matching).
+ pub custom_patterns: Vec,
+}
+
+impl Default for OsPipeConfig {
+ fn default() -> Self {
+ Self {
+ data_dir: PathBuf::from("~/.ospipe"),
+ capture: CaptureConfig::default(),
+ storage: StorageConfig::default(),
+ search: SearchConfig::default(),
+ safety: SafetyConfig::default(),
+ }
+ }
+}
+
+impl Default for CaptureConfig {
+ fn default() -> Self {
+ Self {
+ fps: 1.0,
+ audio_chunk_secs: 30,
+ excluded_apps: vec![
+ "1Password".to_string(),
+ "Keychain Access".to_string(),
+ ],
+ skip_private_windows: true,
+ }
+ }
+}
+
+impl Default for StorageConfig {
+ fn default() -> Self {
+ Self {
+ embedding_dim: 384,
+ hnsw_m: 32,
+ hnsw_ef_construction: 200,
+ hnsw_ef_search: 100,
+ dedup_threshold: 0.95,
+ quantization_tiers: vec![
+ QuantizationTier {
+ age_hours: 0,
+ method: QuantizationMethod::None,
+ },
+ QuantizationTier {
+ age_hours: 24,
+ method: QuantizationMethod::Scalar,
+ },
+ QuantizationTier {
+ age_hours: 168, // 1 week
+ method: QuantizationMethod::Product,
+ },
+ QuantizationTier {
+ age_hours: 720, // 30 days
+ method: QuantizationMethod::Binary,
+ },
+ ],
+ }
+ }
+}
+
+impl Default for SearchConfig {
+ fn default() -> Self {
+ Self {
+ default_k: 10,
+ hybrid_weight: 0.7,
+ mmr_lambda: 0.5,
+ rerank_enabled: false,
+ }
+ }
+}
+
+impl Default for SafetyConfig {
+ fn default() -> Self {
+ Self {
+ pii_detection: true,
+ credit_card_redaction: true,
+ ssn_redaction: true,
+ custom_patterns: Vec::new(),
+ }
+ }
+}
diff --git a/examples/OSpipe/src/error.rs b/examples/OSpipe/src/error.rs
new file mode 100644
index 000000000..7c333d942
--- /dev/null
+++ b/examples/OSpipe/src/error.rs
@@ -0,0 +1,41 @@
+//! Unified error types for OSpipe.
+
+use thiserror::Error;
+
+/// Top-level error type for all OSpipe operations.
+#[derive(Error, Debug)]
+pub enum OsPipeError {
+ /// An error occurred during screen/audio capture processing.
+ #[error("Capture error: {0}")]
+ Capture(String),
+
+ /// An error occurred in the vector storage layer.
+ #[error("Storage error: {0}")]
+ Storage(String),
+
+ /// An error occurred during search operations.
+ #[error("Search error: {0}")]
+ Search(String),
+
+ /// An error occurred in the ingestion pipeline.
+ #[error("Pipeline error: {0}")]
+ Pipeline(String),
+
+ /// The safety gate denied ingestion of content.
+ #[error("Safety gate denied: {reason}")]
+ SafetyDenied {
+ /// Human-readable reason for denial.
+ reason: String,
+ },
+
+ /// A configuration-related error.
+ #[error("Configuration error: {0}")]
+ Config(String),
+
+ /// A JSON serialization or deserialization error.
+ #[error("Serialization error: {0}")]
+ Serde(#[from] serde_json::Error),
+}
+
+/// Convenience alias for `Result`.
+pub type Result = std::result::Result;
diff --git a/examples/OSpipe/src/graph/entity_extractor.rs b/examples/OSpipe/src/graph/entity_extractor.rs
new file mode 100644
index 000000000..6d59cff30
--- /dev/null
+++ b/examples/OSpipe/src/graph/entity_extractor.rs
@@ -0,0 +1,197 @@
+//! Heuristic named-entity recognition (NER) for extracting entities from text.
+//!
+//! This module performs lightweight, regex-free entity extraction suitable for
+//! processing screen captures and transcriptions. It recognises:
+//!
+//! - **URLs** (`https://...` / `http://...`)
+//! - **Email addresses** (`user@domain.tld`)
+//! - **Mentions** (`@handle`)
+//! - **Capitalized phrases** (two or more consecutive capitalized words -> proper nouns)
+
+/// Extract `(label, name)` pairs from free-form `text`.
+///
+/// Labels returned:
+/// - `"Url"` for HTTP(S) URLs
+/// - `"Email"` for email-like patterns
+/// - `"Mention"` for `@handle` patterns
+/// - `"Person"` for capitalized multi-word phrases (heuristic proper noun)
+pub fn extract_entities(text: &str) -> Vec<(String, String)> {
+ let mut entities: Vec<(String, String)> = Vec::new();
+ let mut seen = std::collections::HashSet::new();
+
+ // --- URL detection ---
+ for word in text.split_whitespace() {
+ let trimmed = word.trim_matches(|c: char| c == ',' || c == '.' || c == ')' || c == '(' || c == ';');
+ if (trimmed.starts_with("http://") || trimmed.starts_with("https://")) && trimmed.len() > 10
+ && seen.insert(("Url", trimmed.to_string())) {
+ entities.push(("Url".to_string(), trimmed.to_string()));
+ }
+ }
+
+ // --- Email detection ---
+ for word in text.split_whitespace() {
+ let trimmed = word.trim_matches(|c: char| c == ',' || c == '.' || c == ')' || c == '(' || c == ';' || c == '<' || c == '>');
+ if is_email_like(trimmed)
+ && seen.insert(("Email", trimmed.to_string())) {
+ entities.push(("Email".to_string(), trimmed.to_string()));
+ }
+ }
+
+ // --- @mention detection ---
+ for word in text.split_whitespace() {
+ let trimmed = word.trim_matches(|c: char| c == ',' || c == '.' || c == ')' || c == '(' || c == ';');
+ if trimmed.starts_with('@') && trimmed.len() > 1 {
+ let handle = trimmed.to_string();
+ if seen.insert(("Mention", handle.clone())) {
+ entities.push(("Mention".to_string(), handle));
+ }
+ }
+ }
+
+ // --- Capitalized phrase detection (proper nouns) ---
+ let cap_phrases = extract_capitalized_phrases(text);
+ for phrase in cap_phrases {
+ if seen.insert(("Person", phrase.clone())) {
+ entities.push(("Person".to_string(), phrase));
+ }
+ }
+
+ entities
+}
+
+/// Returns `true` if `s` looks like an email address (`local@domain.tld`).
+fn is_email_like(s: &str) -> bool {
+ // Must contain exactly one '@', with non-empty parts on both sides,
+ // and the domain part must contain at least one '.'.
+ if let Some(at_pos) = s.find('@') {
+ let local = &s[..at_pos];
+ let domain = &s[at_pos + 1..];
+ !local.is_empty()
+ && !domain.is_empty()
+ && domain.contains('.')
+ && !domain.starts_with('.')
+ && !domain.ends_with('.')
+ && local.chars().all(|c| c.is_alphanumeric() || c == '.' || c == '_' || c == '-' || c == '+')
+ && domain.chars().all(|c| c.is_alphanumeric() || c == '.' || c == '-')
+ } else {
+ false
+ }
+}
+
+/// Extract sequences of two or more consecutive capitalized words as likely
+/// proper nouns. Filters out common sentence-starting words when they appear
+/// alone at what looks like a sentence boundary.
+fn extract_capitalized_phrases(text: &str) -> Vec {
+ let mut phrases = Vec::new();
+ let words: Vec<&str> = text.split_whitespace().collect();
+
+ let mut i = 0;
+ while i < words.len() {
+ // Skip words that start a sentence (preceded by nothing or a sentence-ending punctuation).
+ let word = words[i].trim_matches(|c: char| !c.is_alphanumeric());
+ if is_capitalized(word) && word.len() > 1 {
+ // Accumulate consecutive capitalized words.
+ let start = i;
+ let mut parts = vec![word.to_string()];
+ i += 1;
+ while i < words.len() {
+ let next = words[i].trim_matches(|c: char| !c.is_alphanumeric());
+ if is_capitalized(next) && next.len() > 1 {
+ parts.push(next.to_string());
+ i += 1;
+ } else {
+ break;
+ }
+ }
+ // Only take phrases of 2+ words (single capitalized words are too noisy).
+ if parts.len() >= 2 {
+ // Skip if the first word is at position 0 or follows a sentence terminator
+ // and is a common article/pronoun. We still keep it if part of a longer
+ // multi-word phrase that itself is capitalized.
+ let is_sentence_start = start == 0
+ || words.get(start.wrapping_sub(1)).is_some_and(|prev| {
+ prev.ends_with('.') || prev.ends_with('!') || prev.ends_with('?')
+ });
+
+ if is_sentence_start && parts.len() == 2 && is_common_starter(&parts[0]) {
+ // Skip - likely just a sentence starting with "The Xyz" etc.
+ } else {
+ let phrase = parts.join(" ");
+ phrases.push(phrase);
+ }
+ }
+ } else {
+ i += 1;
+ }
+ }
+
+ phrases
+}
+
+/// Returns `true` if the first character of `word` is uppercase ASCII.
+fn is_capitalized(word: &str) -> bool {
+ word.chars()
+ .next()
+ .is_some_and(|c| c.is_uppercase())
+}
+
+/// Common sentence-starting words that are not proper nouns.
+fn is_common_starter(word: &str) -> bool {
+ matches!(
+ word.to_lowercase().as_str(),
+ "the" | "a" | "an" | "this" | "that" | "these" | "those" | "it" | "i" | "we" | "they" | "he" | "she"
+ )
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ #[test]
+ fn test_extract_urls() {
+ let entities = extract_entities("Visit https://example.com/page and http://foo.bar/baz for info.");
+ let urls: Vec<_> = entities.iter().filter(|(l, _)| l == "Url").collect();
+ assert_eq!(urls.len(), 2);
+ assert_eq!(urls[0].1, "https://example.com/page");
+ assert_eq!(urls[1].1, "http://foo.bar/baz");
+ }
+
+ #[test]
+ fn test_extract_emails() {
+ let entities = extract_entities("Email alice@example.com or bob@company.org for help.");
+ let emails: Vec<_> = entities.iter().filter(|(l, _)| l == "Email").collect();
+ assert_eq!(emails.len(), 2);
+ }
+
+ #[test]
+ fn test_extract_mentions() {
+ let entities = extract_entities("Hey @alice and @bob-dev, check this out.");
+ let mentions: Vec<_> = entities.iter().filter(|(l, _)| l == "Mention").collect();
+ assert_eq!(mentions.len(), 2);
+ assert_eq!(mentions[0].1, "@alice");
+ assert_eq!(mentions[1].1, "@bob-dev");
+ }
+
+ #[test]
+ fn test_extract_capitalized_phrases() {
+ let entities = extract_entities("I met John Smith at the World Trade Center yesterday.");
+ let persons: Vec<_> = entities.iter().filter(|(l, _)| l == "Person").collect();
+ assert!(persons.iter().any(|(_, n)| n == "John Smith"));
+ assert!(persons.iter().any(|(_, n)| n == "World Trade Center"));
+ }
+
+ #[test]
+ fn test_no_false_positives_on_sentence_start() {
+ let entities = extract_entities("The cat sat on the mat.");
+ let persons: Vec<_> = entities.iter().filter(|(l, _)| l == "Person").collect();
+ // "The cat" should not appear as a person (single cap word + lowercase).
+ assert!(persons.is_empty());
+ }
+
+ #[test]
+ fn test_deduplication() {
+ let entities = extract_entities("Visit https://example.com and https://example.com again.");
+ let urls: Vec<_> = entities.iter().filter(|(l, _)| l == "Url").collect();
+ assert_eq!(urls.len(), 1);
+ }
+}
diff --git a/examples/OSpipe/src/graph/mod.rs b/examples/OSpipe/src/graph/mod.rs
new file mode 100644
index 000000000..d3b15f4a6
--- /dev/null
+++ b/examples/OSpipe/src/graph/mod.rs
@@ -0,0 +1,371 @@
+//! Knowledge graph integration for OSpipe.
+//!
+//! Provides entity extraction from captured text and stores entity relationships
+//! in a [`ruvector_graph::GraphDB`] (native) or a lightweight in-memory stub (WASM).
+//!
+//! ## Usage
+//!
+//! ```rust,no_run
+//! use ospipe::graph::KnowledgeGraph;
+//!
+//! let mut kg = KnowledgeGraph::new();
+//! let ids = kg.ingest_frame_entities("frame-001", "Meeting with John Smith at https://meet.example.com").unwrap();
+//! let people = kg.find_by_label("Person");
+//! ```
+
+pub mod entity_extractor;
+
+use crate::error::Result;
+use std::collections::HashMap;
+
+/// A lightweight entity representation returned by query methods.
+#[derive(Debug, Clone, PartialEq, Eq)]
+pub struct Entity {
+ /// Unique identifier for this entity.
+ pub id: String,
+ /// Category label (e.g. "Person", "Url", "Mention", "Email", "Frame").
+ pub label: String,
+ /// Human-readable name or value.
+ pub name: String,
+ /// Additional key-value properties.
+ pub properties: HashMap,
+}
+
+// ---------------------------------------------------------------------------
+// Native implementation (backed by ruvector-graph)
+// ---------------------------------------------------------------------------
+
+#[cfg(not(target_arch = "wasm32"))]
+mod inner {
+ use super::*;
+ use crate::error::OsPipeError;
+ use ruvector_graph::{EdgeBuilder, GraphDB, NodeBuilder, PropertyValue};
+
+ /// A knowledge graph that stores entity relationships extracted from captured
+ /// frames. On native targets this is backed by [`ruvector_graph::GraphDB`].
+ pub struct KnowledgeGraph {
+ db: GraphDB,
+ }
+
+ impl KnowledgeGraph {
+ /// Create a new, empty knowledge graph.
+ pub fn new() -> Self {
+ Self {
+ db: GraphDB::new(),
+ }
+ }
+
+ /// Add an entity node to the graph.
+ ///
+ /// Returns the newly created node ID.
+ pub fn add_entity(
+ &self,
+ label: &str,
+ name: &str,
+ properties: HashMap,
+ ) -> Result {
+ let mut builder = NodeBuilder::new()
+ .label(label)
+ .property("name", name);
+
+ for (k, v) in &properties {
+ builder = builder.property(k.as_str(), v.as_str());
+ }
+
+ let node = builder.build();
+ let id = self
+ .db
+ .create_node(node)
+ .map_err(|e| OsPipeError::Storage(format!("graph: {}", e)))?;
+ Ok(id)
+ }
+
+ /// Create a directed relationship (edge) between two entities.
+ ///
+ /// Both `from_id` and `to_id` must refer to existing nodes.
+ /// Returns the edge ID.
+ pub fn add_relationship(
+ &self,
+ from_id: &str,
+ to_id: &str,
+ rel_type: &str,
+ ) -> Result {
+ let edge = EdgeBuilder::new(from_id.to_string(), to_id.to_string(), rel_type).build();
+ let id = self
+ .db
+ .create_edge(edge)
+ .map_err(|e| OsPipeError::Storage(format!("graph: {}", e)))?;
+ Ok(id)
+ }
+
+ /// Find all entities that carry `label`.
+ pub fn find_by_label(&self, label: &str) -> Vec {
+ self.db
+ .get_nodes_by_label(label)
+ .into_iter()
+ .map(|n| node_to_entity(&n))
+ .collect()
+ }
+
+ /// Find all entities directly connected to `entity_id` (both outgoing and
+ /// incoming edges).
+ pub fn neighbors(&self, entity_id: &str) -> Vec {
+ let mut seen = std::collections::HashSet::new();
+ let mut result = Vec::new();
+
+ let node_id = entity_id.to_string();
+
+ // Outgoing neighbours.
+ for edge in self.db.get_outgoing_edges(&node_id) {
+ if seen.insert(edge.to.clone()) {
+ if let Some(node) = self.db.get_node(&edge.to) {
+ result.push(node_to_entity(&node));
+ }
+ }
+ }
+
+ // Incoming neighbours.
+ for edge in self.db.get_incoming_edges(&node_id) {
+ if seen.insert(edge.from.clone()) {
+ if let Some(node) = self.db.get_node(&edge.from) {
+ result.push(node_to_entity(&node));
+ }
+ }
+ }
+
+ result
+ }
+
+ /// Run heuristic NER on `text` and return extracted `(label, name)` pairs.
+ pub fn extract_entities(text: &str) -> Vec<(String, String)> {
+ entity_extractor::extract_entities(text)
+ }
+
+ /// Extract entities from `text`, create nodes for each, link them to the
+ /// given `frame_id` node (creating the frame node if it does not yet exist),
+ /// and return the IDs of all newly created entity nodes.
+ pub fn ingest_frame_entities(
+ &self,
+ frame_id: &str,
+ text: &str,
+ ) -> Result> {
+ // Ensure frame node exists.
+ let frame_node_id = if self.db.get_node(frame_id).is_some() {
+ frame_id.to_string()
+ } else {
+ let node = NodeBuilder::new()
+ .id(frame_id)
+ .label("Frame")
+ .property("name", frame_id)
+ .build();
+ self.db
+ .create_node(node)
+ .map_err(|e| OsPipeError::Storage(format!("graph: {}", e)))?
+ };
+
+ let extracted = entity_extractor::extract_entities(text);
+ let mut entity_ids = Vec::with_capacity(extracted.len());
+
+ for (label, name) in &extracted {
+ let entity_id = self.add_entity(label, name, HashMap::new())?;
+ self.add_relationship(&frame_node_id, &entity_id, "CONTAINS")?;
+ entity_ids.push(entity_id);
+ }
+
+ Ok(entity_ids)
+ }
+ }
+
+ impl Default for KnowledgeGraph {
+ fn default() -> Self {
+ Self::new()
+ }
+ }
+
+ /// Convert a `ruvector_graph::Node` into the crate-public `Entity` type.
+ fn node_to_entity(node: &ruvector_graph::Node) -> Entity {
+ let label = node
+ .labels
+ .first()
+ .map_or_else(String::new, |l| l.name.clone());
+
+ let name = match node.get_property("name") {
+ Some(PropertyValue::String(s)) => s.clone(),
+ _ => String::new(),
+ };
+
+ let mut properties = HashMap::new();
+ for (k, v) in &node.properties {
+ if k == "name" {
+ continue;
+ }
+ let v_str = match v {
+ PropertyValue::String(s) => s.clone(),
+ PropertyValue::Integer(i) => i.to_string(),
+ PropertyValue::Float(f) => f.to_string(),
+ PropertyValue::Boolean(b) => b.to_string(),
+ _ => format!("{:?}", v),
+ };
+ properties.insert(k.clone(), v_str);
+ }
+
+ Entity {
+ id: node.id.clone(),
+ label,
+ name,
+ properties,
+ }
+ }
+}
+
+// ---------------------------------------------------------------------------
+// WASM fallback (lightweight in-memory stub)
+// ---------------------------------------------------------------------------
+
+#[cfg(target_arch = "wasm32")]
+mod inner {
+ use super::*;
+
+ struct StoredNode {
+ id: String,
+ label: String,
+ name: String,
+ properties: HashMap,
+ }
+
+ struct StoredEdge {
+ _id: String,
+ from: String,
+ to: String,
+ _rel_type: String,
+ }
+
+ /// A knowledge graph backed by simple `Vec` storage for WASM targets.
+ pub struct KnowledgeGraph {
+ nodes: Vec,
+ edges: Vec,
+ next_id: u64,
+ }
+
+ impl KnowledgeGraph {
+ pub fn new() -> Self {
+ Self {
+ nodes: Vec::new(),
+ edges: Vec::new(),
+ next_id: 0,
+ }
+ }
+
+ pub fn add_entity(
+ &mut self,
+ label: &str,
+ name: &str,
+ properties: HashMap,
+ ) -> Result {
+ let id = format!("wasm-{}", self.next_id);
+ self.next_id += 1;
+ self.nodes.push(StoredNode {
+ id: id.clone(),
+ label: label.to_string(),
+ name: name.to_string(),
+ properties,
+ });
+ Ok(id)
+ }
+
+ pub fn add_relationship(
+ &mut self,
+ from_id: &str,
+ to_id: &str,
+ rel_type: &str,
+ ) -> Result {
+ let id = format!("wasm-e-{}", self.next_id);
+ self.next_id += 1;
+ self.edges.push(StoredEdge {
+ _id: id.clone(),
+ from: from_id.to_string(),
+ to: to_id.to_string(),
+ _rel_type: rel_type.to_string(),
+ });
+ Ok(id)
+ }
+
+ pub fn find_by_label(&self, label: &str) -> Vec {
+ self.nodes
+ .iter()
+ .filter(|n| n.label == label)
+ .map(|n| Entity {
+ id: n.id.clone(),
+ label: n.label.clone(),
+ name: n.name.clone(),
+ properties: n.properties.clone(),
+ })
+ .collect()
+ }
+
+ pub fn neighbors(&self, entity_id: &str) -> Vec {
+ let mut ids = std::collections::HashSet::new();
+ for e in &self.edges {
+ if e.from == entity_id {
+ ids.insert(e.to.clone());
+ }
+ if e.to == entity_id {
+ ids.insert(e.from.clone());
+ }
+ }
+ self.nodes
+ .iter()
+ .filter(|n| ids.contains(&n.id))
+ .map(|n| Entity {
+ id: n.id.clone(),
+ label: n.label.clone(),
+ name: n.name.clone(),
+ properties: n.properties.clone(),
+ })
+ .collect()
+ }
+
+ pub fn extract_entities(text: &str) -> Vec<(String, String)> {
+ entity_extractor::extract_entities(text)
+ }
+
+ pub fn ingest_frame_entities(
+ &mut self,
+ frame_id: &str,
+ text: &str,
+ ) -> Result> {
+ // Ensure frame node.
+ let frame_exists = self.nodes.iter().any(|n| n.id == frame_id);
+ let frame_node_id = if frame_exists {
+ frame_id.to_string()
+ } else {
+ let id = frame_id.to_string();
+ self.nodes.push(StoredNode {
+ id: id.clone(),
+ label: "Frame".to_string(),
+ name: frame_id.to_string(),
+ properties: HashMap::new(),
+ });
+ id
+ };
+
+ let extracted = entity_extractor::extract_entities(text);
+ let mut entity_ids = Vec::with_capacity(extracted.len());
+ for (label, name) in &extracted {
+ let eid = self.add_entity(label, name, HashMap::new())?;
+ self.add_relationship(&frame_node_id, &eid, "CONTAINS")?;
+ entity_ids.push(eid);
+ }
+ Ok(entity_ids)
+ }
+ }
+
+ impl Default for KnowledgeGraph {
+ fn default() -> Self {
+ Self::new()
+ }
+ }
+}
+
+// Re-export the platform-appropriate implementation.
+pub use inner::KnowledgeGraph;
diff --git a/examples/OSpipe/src/learning/mod.rs b/examples/OSpipe/src/learning/mod.rs
new file mode 100644
index 000000000..d1ab7e198
--- /dev/null
+++ b/examples/OSpipe/src/learning/mod.rs
@@ -0,0 +1,329 @@
+//! Continual learning for search improvement.
+//!
+//! This module integrates `ruvector-gnn` to provide:
+//!
+//! - **[`SearchLearner`]** -- records user relevance feedback and uses Elastic
+//! Weight Consolidation (EWC) to prevent catastrophic forgetting when the
+//! embedding model is fine-tuned over time.
+//! - **[`EmbeddingQuantizer`]** -- compresses stored embeddings based on their
+//! age, trading precision for storage savings on cold data.
+//!
+//! Both structs compile to no-op stubs on `wasm32` targets where the native
+//! `ruvector-gnn` crate is unavailable.
+
+// ---------------------------------------------------------------------------
+// Native implementation (non-WASM)
+// ---------------------------------------------------------------------------
+
+#[cfg(not(target_arch = "wasm32"))]
+mod native {
+ use ruvector_gnn::compress::TensorCompress;
+ use ruvector_gnn::ewc::ElasticWeightConsolidation;
+ use ruvector_gnn::replay::ReplayBuffer;
+
+ /// Minimum number of feedback entries before learning data is considered
+ /// sufficient for a consolidation step.
+ const MIN_FEEDBACK_ENTRIES: usize = 32;
+
+ /// Records search relevance feedback and manages continual-learning state.
+ ///
+ /// Internally the learner maintains:
+ /// - A [`ReplayBuffer`] that stores (query, result, relevance) triples via
+ /// reservoir sampling so old feedback is not forgotten.
+ /// - An [`ElasticWeightConsolidation`] instance whose Fisher diagonal and
+ /// anchor weights track which embedding dimensions are important.
+ /// - A simple parameter vector (`weights`) that represents a learned
+ /// relevance projection (one weight per embedding dimension).
+ pub struct SearchLearner {
+ replay_buffer: ReplayBuffer,
+ ewc: ElasticWeightConsolidation,
+ /// Learned relevance-projection weights (one per embedding dimension).
+ weights: Vec,
+ }
+
+ impl SearchLearner {
+ /// Create a new learner.
+ ///
+ /// # Arguments
+ /// * `embedding_dim` - Dimensionality of the embedding vectors.
+ /// * `replay_capacity` - Maximum number of feedback entries retained.
+ pub fn new(embedding_dim: usize, replay_capacity: usize) -> Self {
+ Self {
+ replay_buffer: ReplayBuffer::new(replay_capacity),
+ ewc: ElasticWeightConsolidation::new(100.0),
+ weights: vec![1.0; embedding_dim],
+ }
+ }
+
+ /// Record a single piece of user feedback.
+ ///
+ /// The query and result embeddings are concatenated and stored in the
+ /// replay buffer. Positive feedback entries use `positive_ids = [1]`,
+ /// negative ones use `positive_ids = [0]`, which allows downstream
+ /// training loops to distinguish them.
+ ///
+ /// # Arguments
+ /// * `query_embedding` - Embedding of the search query.
+ /// * `result_embedding` - Embedding of the search result.
+ /// * `relevant` - Whether the user considered the result relevant.
+ pub fn record_feedback(
+ &mut self,
+ query_embedding: Vec,
+ result_embedding: Vec,
+ relevant: bool,
+ ) {
+ let mut combined = query_embedding;
+ combined.extend_from_slice(&result_embedding);
+ let positive_id: usize = if relevant { 1 } else { 0 };
+ self.replay_buffer.add(&combined, &[positive_id]);
+ }
+
+ /// Return the current size of the replay buffer.
+ pub fn replay_buffer_len(&self) -> usize {
+ self.replay_buffer.len()
+ }
+
+ /// Returns `true` when the buffer contains enough data for a
+ /// meaningful consolidation step (>= 32 entries).
+ pub fn has_sufficient_data(&self) -> bool {
+ self.replay_buffer.len() >= MIN_FEEDBACK_ENTRIES
+ }
+
+ /// Lock the current parameter state with EWC.
+ ///
+ /// This computes the Fisher information diagonal from sampled replay
+ /// entries and saves the current weights as the EWC anchor. Future
+ /// EWC penalties will discourage large deviations from these weights.
+ pub fn consolidate(&mut self) {
+ if self.replay_buffer.is_empty() {
+ return;
+ }
+
+ // Sample gradients -- we approximate them as the difference between
+ // query and result portions of each stored entry.
+ let samples = self.replay_buffer.sample(
+ self.replay_buffer.len().min(64),
+ );
+
+ let dim = self.weights.len();
+ let gradients: Vec> = samples
+ .iter()
+ .filter_map(|entry| {
+ // Each entry stores [query || result]; extract gradient proxy.
+ if entry.query.len() >= dim * 2 {
+ let query_part = &entry.query[..dim];
+ let result_part = &entry.query[dim..dim * 2];
+ let grad: Vec = query_part
+ .iter()
+ .zip(result_part.iter())
+ .map(|(q, r)| q - r)
+ .collect();
+ Some(grad)
+ } else {
+ None
+ }
+ })
+ .collect();
+
+ if gradients.is_empty() {
+ return;
+ }
+
+ let grad_refs: Vec<&[f32]> = gradients.iter().map(|g| g.as_slice()).collect();
+ let sample_count = grad_refs.len();
+
+ self.ewc.compute_fisher(&grad_refs, sample_count);
+ self.ewc.consolidate(&self.weights);
+ }
+
+ /// Return the current EWC penalty for the learned weights.
+ ///
+ /// Returns `0.0` if [`consolidate`](Self::consolidate) has not been
+ /// called yet.
+ pub fn ewc_penalty(&self) -> f32 {
+ self.ewc.penalty(&self.weights)
+ }
+ }
+
+ // -----------------------------------------------------------------------
+ // EmbeddingQuantizer
+ // -----------------------------------------------------------------------
+
+ /// Age-aware embedding quantizer backed by [`TensorCompress`].
+ ///
+ /// Older embeddings are compressed more aggressively:
+ ///
+ /// | Age | Compression |
+ /// |----------------|----------------------|
+ /// | < 1 hour | Full precision |
+ /// | 1 h -- 24 h | Half precision (FP16)|
+ /// | 1 d -- 7 d | PQ8 |
+ /// | > 7 d | Binary |
+ pub struct EmbeddingQuantizer {
+ compressor: TensorCompress,
+ }
+
+ impl Default for EmbeddingQuantizer {
+ fn default() -> Self {
+ Self::new()
+ }
+ }
+
+ impl EmbeddingQuantizer {
+ /// Create a new quantizer instance.
+ pub fn new() -> Self {
+ Self {
+ compressor: TensorCompress::new(),
+ }
+ }
+
+ /// Compress an embedding based on its age.
+ ///
+ /// The age determines the access-frequency proxy passed to the
+ /// underlying `TensorCompress`:
+ /// - `< 1 h` -> freq `1.0` (no compression)
+ /// - `1-24 h` -> freq `0.5` (half precision)
+ /// - `1-7 d` -> freq `0.2` (PQ8)
+ /// - `> 7 d` -> freq `0.005` (binary)
+ ///
+ /// # Arguments
+ /// * `embedding` - The raw embedding vector.
+ /// * `age_hours` - Age of the embedding in hours.
+ ///
+ /// # Returns
+ /// Serialised compressed bytes. Use [`dequantize`](Self::dequantize)
+ /// to recover the original (lossy) vector.
+ pub fn quantize_by_age(&self, embedding: &[f32], age_hours: u64) -> Vec {
+ let access_freq = Self::age_to_freq(age_hours);
+ match self.compressor.compress(embedding, access_freq) {
+ Ok(compressed) => {
+ serde_json::to_vec(&compressed).unwrap_or_else(|_| {
+ // Fallback: store raw f32 bytes.
+ embedding.iter().flat_map(|f| f.to_le_bytes()).collect()
+ })
+ }
+ Err(_) => {
+ // Fallback: store raw f32 bytes.
+ embedding.iter().flat_map(|f| f.to_le_bytes()).collect()
+ }
+ }
+ }
+
+ /// Decompress bytes produced by [`quantize_by_age`](Self::quantize_by_age).
+ ///
+ /// # Arguments
+ /// * `data` - Compressed byte representation.
+ /// * `original_dim` - Expected dimensionality of the output vector.
+ ///
+ /// # Returns
+ /// The decompressed embedding (lossy). If decompression fails, a
+ /// zero-vector of `original_dim` length is returned.
+ pub fn dequantize(&self, data: &[u8], original_dim: usize) -> Vec {
+ if let Ok(compressed) =
+ serde_json::from_slice::(data)
+ {
+ if let Ok(decompressed) = self.compressor.decompress(&compressed) {
+ if decompressed.len() == original_dim {
+ return decompressed;
+ }
+ }
+ }
+
+ // Fallback: try interpreting as raw f32 bytes.
+ if data.len() == original_dim * 4 {
+ return data
+ .chunks_exact(4)
+ .map(|chunk| f32::from_le_bytes([chunk[0], chunk[1], chunk[2], chunk[3]]))
+ .collect();
+ }
+
+ vec![0.0; original_dim]
+ }
+
+ /// Map an age in hours to an access-frequency proxy in [0, 1].
+ fn age_to_freq(age_hours: u64) -> f32 {
+ match age_hours {
+ 0 => 1.0, // Fresh -- full precision
+ 1..=24 => 0.5, // Warm -- half precision
+ 25..=168 => 0.2, // Cool -- PQ8
+ _ => 0.005, // Cold -- binary
+ }
+ }
+ }
+}
+
+// ---------------------------------------------------------------------------
+// WASM stub implementation
+// ---------------------------------------------------------------------------
+
+#[cfg(target_arch = "wasm32")]
+mod wasm_stub {
+ /// No-op search learner for WASM targets.
+ pub struct SearchLearner {
+ buffer_len: usize,
+ }
+
+ impl SearchLearner {
+ pub fn new(_embedding_dim: usize, _replay_capacity: usize) -> Self {
+ Self { buffer_len: 0 }
+ }
+
+ pub fn record_feedback(
+ &mut self,
+ _query_embedding: Vec,
+ _result_embedding: Vec,
+ _relevant: bool,
+ ) {
+ self.buffer_len += 1;
+ }
+
+ pub fn replay_buffer_len(&self) -> usize {
+ self.buffer_len
+ }
+
+ pub fn has_sufficient_data(&self) -> bool {
+ self.buffer_len >= 32
+ }
+
+ pub fn consolidate(&mut self) {}
+
+ pub fn ewc_penalty(&self) -> f32 {
+ 0.0
+ }
+ }
+
+ /// No-op embedding quantizer for WASM targets.
+ ///
+ /// Returns the original embedding bytes without compression.
+ pub struct EmbeddingQuantizer;
+
+ impl EmbeddingQuantizer {
+ pub fn new() -> Self {
+ Self
+ }
+
+ pub fn quantize_by_age(&self, embedding: &[f32], _age_hours: u64) -> Vec {
+ embedding.iter().flat_map(|f| f.to_le_bytes()).collect()
+ }
+
+ pub fn dequantize(&self, data: &[u8], original_dim: usize) -> Vec {
+ if data.len() == original_dim * 4 {
+ data.chunks_exact(4)
+ .map(|c| f32::from_le_bytes([c[0], c[1], c[2], c[3]]))
+ .collect()
+ } else {
+ vec![0.0; original_dim]
+ }
+ }
+ }
+}
+
+// ---------------------------------------------------------------------------
+// Re-exports
+// ---------------------------------------------------------------------------
+
+#[cfg(not(target_arch = "wasm32"))]
+pub use native::{EmbeddingQuantizer, SearchLearner};
+
+#[cfg(target_arch = "wasm32")]
+pub use wasm_stub::{EmbeddingQuantizer, SearchLearner};
diff --git a/examples/OSpipe/src/lib.rs b/examples/OSpipe/src/lib.rs
new file mode 100644
index 000000000..dc301301e
--- /dev/null
+++ b/examples/OSpipe/src/lib.rs
@@ -0,0 +1,43 @@
+//! # OSpipe
+//!
+//! RuVector-enhanced personal AI memory system integrating with Screenpipe.
+//!
+//! OSpipe captures screen content, audio transcriptions, and UI events,
+//! processes them through a safety-aware ingestion pipeline, and stores
+//! them as searchable vector embeddings for personal AI memory recall.
+//!
+//! ## Architecture
+//!
+//! ```text
+//! Screenpipe -> Capture -> Safety Gate -> Dedup -> Embed -> VectorStore
+//! |
+//! Search Router <--------+
+//! (Semantic / Keyword / Hybrid)
+//! ```
+//!
+//! ## Modules
+//!
+//! - [`capture`] - Captured frame data structures (OCR, transcription, UI events)
+//! - [`storage`] - HNSW-backed vector storage and embedding engine
+//! - [`search`] - Query routing and hybrid search (semantic + keyword)
+//! - [`pipeline`] - Ingestion pipeline with deduplication
+//! - [`safety`] - PII detection and content redaction
+//! - [`config`] - Configuration for all subsystems
+//! - [`error`] - Unified error types
+
+pub mod capture;
+pub mod config;
+pub mod error;
+pub mod graph;
+pub mod learning;
+#[cfg(not(target_arch = "wasm32"))]
+pub mod persistence;
+pub mod pipeline;
+pub mod quantum;
+pub mod safety;
+pub mod search;
+#[cfg(not(target_arch = "wasm32"))]
+pub mod server;
+pub mod storage;
+
+pub mod wasm;
diff --git a/examples/OSpipe/src/persistence.rs b/examples/OSpipe/src/persistence.rs
new file mode 100644
index 000000000..a461bfdc4
--- /dev/null
+++ b/examples/OSpipe/src/persistence.rs
@@ -0,0 +1,319 @@
+//! JSON-file persistence layer for OSpipe data.
+//!
+//! Provides durable storage of frames, configuration, and embedding data
+//! using the local filesystem. All data is serialized to JSON (frames and
+//! config) or raw bytes (embeddings) inside a configurable data directory.
+//!
+//! This module is gated behind `cfg(not(target_arch = "wasm32"))` because
+//! WASM targets do not have filesystem access.
+
+use crate::capture::CapturedFrame;
+use crate::config::OsPipeConfig;
+use crate::error::{OsPipeError, Result};
+use serde::{Deserialize, Serialize};
+use std::path::PathBuf;
+
+/// A serializable wrapper around [`CapturedFrame`] for disk persistence.
+///
+/// This mirrors all fields of `CapturedFrame` but is kept as a distinct
+/// type so the persistence format can evolve independently of the
+/// in-memory representation.
+#[derive(Debug, Clone, Serialize, Deserialize)]
+pub struct StoredFrame {
+ /// The captured frame data.
+ pub frame: CapturedFrame,
+ /// Optional text that was stored after safety-gate processing.
+ /// If `None`, the original frame text was used unchanged.
+ pub safe_text: Option,
+}
+
+/// Filesystem-backed persistence for OSpipe data.
+///
+/// All files are written inside `data_dir`:
+/// - `frames.json` - serialized vector of [`StoredFrame`]
+/// - `config.json` - serialized [`OsPipeConfig`]
+/// - `embeddings.bin` - raw bytes (e.g. HNSW index serialization)
+pub struct PersistenceLayer {
+ data_dir: PathBuf,
+}
+
+impl PersistenceLayer {
+ /// Create a new persistence layer rooted at `data_dir`.
+ ///
+ /// The directory (and any missing parents) will be created if they
+ /// do not already exist.
+ pub fn new(data_dir: PathBuf) -> Result {
+ std::fs::create_dir_all(&data_dir).map_err(|e| {
+ OsPipeError::Storage(format!(
+ "Failed to create data directory {}: {}",
+ data_dir.display(),
+ e
+ ))
+ })?;
+ Ok(Self { data_dir })
+ }
+
+ /// Return the path to a named file inside the data directory.
+ fn file_path(&self, name: &str) -> PathBuf {
+ self.data_dir.join(name)
+ }
+
+ // ---- Frames ----
+
+ /// Persist a slice of stored frames to `frames.json`.
+ pub fn save_frames(&self, frames: &[StoredFrame]) -> Result<()> {
+ let path = self.file_path("frames.json");
+ let json = serde_json::to_string_pretty(frames)?;
+ std::fs::write(&path, json).map_err(|e| {
+ OsPipeError::Storage(format!(
+ "Failed to write frames to {}: {}",
+ path.display(),
+ e
+ ))
+ })
+ }
+
+ /// Load stored frames from `frames.json`.
+ ///
+ /// Returns an empty vector if the file does not exist.
+ pub fn load_frames(&self) -> Result> {
+ let path = self.file_path("frames.json");
+ if !path.exists() {
+ return Ok(Vec::new());
+ }
+ let data = std::fs::read_to_string(&path).map_err(|e| {
+ OsPipeError::Storage(format!(
+ "Failed to read frames from {}: {}",
+ path.display(),
+ e
+ ))
+ })?;
+ let frames: Vec = serde_json::from_str(&data)?;
+ Ok(frames)
+ }
+
+ // ---- Config ----
+
+ /// Persist the pipeline configuration to `config.json`.
+ pub fn save_config(&self, config: &OsPipeConfig) -> Result<()> {
+ let path = self.file_path("config.json");
+ let json = serde_json::to_string_pretty(config)?;
+ std::fs::write(&path, json).map_err(|e| {
+ OsPipeError::Storage(format!(
+ "Failed to write config to {}: {}",
+ path.display(),
+ e
+ ))
+ })
+ }
+
+ /// Load the pipeline configuration from `config.json`.
+ ///
+ /// Returns `None` if the file does not exist.
+ pub fn load_config(&self) -> Result