Rinwa technical architecture#
Updated 2026-07-31. The application and protocol still use the internal
Lumaname in several identifiers while the public product moves to Rinwa.
This document explains the current implementation boundaries behind local search, AI-assisted reading, synchronization, persistence, and cross-platform delivery. It describes working source code, and calls out transitional pieces instead of presenting plans as shipped capabilities.
System shape#
Rinwa is local-first. A device owns its reading library and can continue to read, search, annotate, and organize saved content without a server.
Shared React reading surface
│
Platform and Repository boundary
│
Per-device SQLite ─── extraction / translation / embedding queues
│
├── optional AI provider, after explicit consent
├── optional Obsidian Vault
└── optional Rinwa Sync operation log
The React interface is shared by the web development surface and Tauri 2
clients. Platform-specific capabilities stay behind apps/web/src/platform.
The local database migration is in progress: the desktop/web production path
still uses the local Node API, while the mobile SQLite adapter has not yet
completed real-device verification or the full App.tsx cut-over.
Architecture thesis#
Embeddings are the memory layer for reading, not the reading experience itself.
Rinwa uses a common semantic representation to reconnect article passages, highlights, notes, references, and questions. That layer is local by default, versioned independently, and safe to delete and rebuild. Original content and user-authored knowledge remain authoritative.
This is an embedding-first architecture, not an embedding-dependent one:
- SQLite FTS, metadata filters, source boundaries, and explicit user rules remain deterministic paths;
- semantic and sparse retrieval are fused instead of asking vectors to solve exact names, dates, code, and URLs;
- every semantic result must preserve a path back to its source passage;
- reading, annotation, and exact search remain usable before the model is downloaded, while it is indexing, or when it is disabled;
- generated answers receive only a small, cited evidence set and still require the user's chosen provider and consent.
Local hybrid search#
Search always has a deterministic sparse path and can add a local semantic path when embeddings are enabled and ready.
Indexing#
- Extracted article text is preferred; feed content is used when extraction is unavailable.
- The tokenizer splits structure-aware chunks with a target of 360 tokens, a maximum of 480, a hard limit of 512, and a 48-token overlap.
onnx-community/embeddinggemma-300m-ONNXis pinned to a specific model revision and loaded lazily through@huggingface/transformers.- The model runs locally through ONNX Runtime using a quantized
q4runtime. - Documents use
title: none | text:and queries usetask: search result | query:as recommended by the model contract. - The model's 768-dimensional
sentence_embeddingoutput is truncated to 256 Matryoshka dimensions and L2-normalized before persistence. - Vectors are stored in SQLite as little-endian float32 BLOBs alongside source hashes, offsets, heading paths, model identity, and an index signature.
The model cache lives beside the device database. Model loading, download progress, indexing progress, pause, retry, and rebuild are exposed as states rather than hidden blocking work.
Retrieval#
The sparse lane uses SQLite full-text passage candidates. The dense lane embeds the query only when the local model is already ready, then calculates cosine similarity in a worker thread. The current library-wide dense scan is bounded to 5,000 indexed chunks and the hybrid request uses a short deadline.
Reciprocal Rank Fusion combines sparse and dense ranks with k = 60.
If embeddings are disabled, still loading, over budget, timed out, or invalid,
the result quietly falls back to the sparse ranking.
This search path is also used to assemble evidence for article and library chat. Stable paragraph offsets map retrieved chunks back to citation IDs.
Semantic story aggregation#
The same local embedding space can reduce duplicate news coverage without calling a generative model for classification.
Semantic membership is decided by embedding cosine similarity. A recent time window bounds the candidate set so two genuinely similar events from different periods are not treated as one story. Metadata still determines eligibility, presentation, source attribution, and chronology; it does not replace the embedding similarity decision.
Clusters are derived, local data. The normal feed can collapse a cluster into one expandable row, while a most-reported view sorts the same clusters by source coverage. Every member remains readable as an individual article. Users can inspect why articles were grouped and split a wrong cluster; that correction is durable user data and syncs even though cluster membership and vectors do not.
When embeddings are disabled or unavailable, the ordinary chronological feed continues unchanged. Story clustering is an enhancement to the feed, not a requirement for ingestion or reading.
Original-first translation#
Translation is an asynchronous layer over the reading surface rather than a replacement document.
The reader renders cached source content first, preserves block identity, and attaches translated text to the matching source block as results arrive. The translation selector excludes Chinese text, code and preformatted blocks, URL-only text, dates, numbers, and punctuation-only lines. A user may translate the article or only a selected sentence.
Structure, block identity, and independent cache versions allow translation to be retried or replaced without invalidating extracted content. Provider calls remain optional and consent-gated; a failure leaves the original and the previous successful translation readable.
AI runtime#
AI-assisted reading is a provider boundary, not a requirement for the reader.
- Chat supports environment configuration, OpenAI, OpenRouter, Ollama, and custom OpenAI-compatible endpoints.
- Translation supports DeepL, OpenAI, custom endpoints, and environment configuration.
- Short articles can use whole-article context; long articles use passage retrieval within a token budget.
- Article paragraphs, knowledge excerpts, and library results receive distinct citation IDs. Unknown citation IDs are removed before display.
- Streaming chat includes timeouts, bounded retry for transient network, rate-limit, and server failures, plus cancellation.
- Usage records distinguish prompt, completion, cached, and reasoning tokens when providers return them; otherwise estimates remain visibly separate.
- Packaged clients hold provider keys in OS secure storage and pass a session-scoped key to the local service.
External article or note content is not sent until the current data-sharing consent version has been accepted. AI output may propose a note change, but does not write to notes without explicit confirmation.
Synchronization#
Rinwa Sync does not replicate SQLite files.
Each device records an immutable operation containing a stable operation ID, workspace ID, device ID, device sequence, entity/action, payload, creation time, and a Hybrid Logical Clock value. The device also stores a clock for each field affected by an operation.
Device A SQLite ── push immutable operations ──┐
├── CouchDB operation log
Device B SQLite ── pull from opaque cursor ───┘
│
└── apply only fields with a newer HLC
The server validates bounded batches and stores each operation as an
idempotent CouchDB document. Duplicate pushes are accepted as conflicts rather
than duplicated. Clients pull through CouchDB's opaque _changes cursor and
own all merge semantics.
Per-field clocks allow unrelated changes to merge. Deletions use tombstones so an older upsert cannot resurrect a removed feed, knowledge card, saved search, connector subscription, or highlight. Network failure leaves operations queued locally and never blocks reading or local writes.
Covered data includes subscriptions, selected item state, reading preferences, saved searches, connector subscriptions, summaries, knowledge cards, tags, references, and highlights. Article bodies, media, translations, embeddings, and search indexes remain per-device caches.
The sync server can provision a Qdrant collection, but the protocol currently
advertises semanticSearch: false. Remote semantic search is not a shipped
capability.
Cache and data ownership#
Application releases do not invalidate content. Extraction, translation, generated summaries, and embeddings have independent compatibility versions. Only the affected version changes when persisted output becomes incompatible.
A failed refresh keeps the previous successful article and its derived data. User notes, tags, highlights, references, and manually edited summaries are user data, not disposable caches.
Knowledge surfaces#
Obsidian is bidirectional. Rinwa writes only clearly managed sections and preserves user-authored Markdown around them. Changes made in the Vault return to Rinwa.
The local MCP surface exposes read operations by default. Mutations such as adding a subscription, changing reading state, saving a note, or exporting to Obsidian require an explicit local write token.
Platform boundary and current status#
The shared React interface is packaged through Tauri 2 for macOS, Windows, iOS/iPadOS, and Android. UI is not reimplemented per platform.
- macOS is the primary quality target.
- The Android preview uses the shared interface, but local SQLite, Keystore, background refresh, and store distribution still require device validation.
- iOS/iPadOS and Windows need their native build, signing, and distribution workflows completed.
- Mobile local SQLite adapters compile, but must not be described as finished until the reading path and store population are verified on devices.
Source map#
apps/api/src/services/embedding-service.ts: local model lifecycle and vector encoding.apps/api/src/services/embedding-index-policy.ts: pinned model, chunk and vector compatibility contract.apps/api/src/services/hybrid-retrieval.ts: sparse/dense retrieval and RRF.apps/api/src/services/ai-service.ts: provider calls, streaming, retries, and response metadata.apps/api/src/services/chat-service.ts: context construction and citation validation.apps/api/src/services/sync-service.ts: operations, HLC field clocks, and client merge behavior.apps/sync-server/src/index.ts: CouchDB operation relay and capabilities.docs/CACHE_POLICY.md: independent cache versions.docs/PRIVACY.md: consent and data boundaries.docs/multiplatform-architecture.md: shared UI and native repository plan.