Every device owns a complete reading library.
The cloud is an optional collaborator, not the database of record. Reading, saved content, search, and knowledge begin on the device.
Sync operations and field clocks
Devices exchange durable intent and user state. They do not copy SQLite files, article bodies, indexes, or model caches.
Follow the merge path ↓Connectors declare what they need
A versioned descriptor, normalized entry model, and constrained network context keep ingestion separate from storage.
Inspect the contract ↓One UI, replaceable data adapters
React depends on platform capabilities and a reader repository rather than OS branches or a specific database transport.
See the adapter stack ↓The desktop/web path currently uses the local Node API. Mobile SQLite adapters compile, but the complete reading-path cut-over and real-device verification are not finished.
Present in current source and covered by the existing build or tests.
OptionalOff by default or only used after you configure it.
Early foundationUseful today, but deliberately narrower than the eventual system.
Not releasedShared implementation exists; packaging, signing, stores, or device validation remain.
A reader that recedes when the article begins.
ImplementedRinwa organizes subscriptions around reading rather than notification pressure. Unread items are expressed through type weight and color, while controls stay quiet until they are needed.
Original content, preserved structure
The reader keeps headings, paragraphs, lists, quotations, code, tables, images, and media in their original order. Full-text extraction runs asynchronously; cached or feed content remains readable if a refresh fails.
Today, Unread, Starred, and each feed
Smart views sit beside per-feed and per-group reading. A feed can be excluded from aggregate views without being removed, and item counts remain local.
Health, history, and settings
Feed management exposes the last attempt and success, HTTP status, consecutive failures, item and new-item counts, grouping, target languages, and automatic AI preferences.
OPML in and out
Import includes preview, selection, duplicate handling, and group preservation. Export keeps an ordinary OPML exit route that other readers can understand.
Favicons with a quiet fallback
Site icons appear where available. If a favicon fails, Rinwa falls back to a simple source initial rather than leaving a broken image.
Navigation and actions by keyboard
Open smart views, groups, feeds, and saved searches; add or manage feeds; mark items read or starred; open the original; or mark the current list read. Search terms include English and Chinese aliases.
RSS, Atom, JSON Feed, and built-in connectors become one normalized item model.
The feed copy is stored first; extraction may improve it without deleting the previous successful body.
Smart feeds and source views share the same reader, keyboard, touch, and trackpad behavior.
The source never waits for the translation.
Optional · consent-gatedThe original article paints first. Translation arrives asynchronously beneath the matching source block, preserving the article as evidence rather than turning it into a replacement-language page.
Structure, media, links, and executable code remain the author’s.
Aligned below its source; a failure never hides the original.
Skip rules
Rinwa does not translate Chinese text, code or preformatted blocks, URL-only content, dates, numbers, punctuation-only lines, or other text without natural-language value.
Per-feed language
Each feed keeps its own target language. Automatic translation is opt-in per feed and runs only after full text is cached.
Provider choice
Choose environment configuration, DeepL, OpenAI-compatible translation, or a custom endpoint. Provider settings and model choice stay separate from the reading surface.
Without a configured translation provider, Rinwa remains a complete local reader. The deterministic development fallback is not presented as human-quality translation.
Full-text certainty, semantic recall.
Embeddings opt-inRinwa always keeps a deterministic SQLite full-text path. When local embeddings are enabled and already ready, a second semantic lane runs beside it. Reciprocal Rank Fusion combines the two without making vector search a single point of failure.
ONNX Runtime supports loading models from local buffers or URLs and resolving execution-provider fallback. Rinwa currently uses the Node-side runtime supplied by Transformers.js; the product does not claim a universal WebGPU path across every client.
Evidence first, provider second.
BYOK · consent-gatedAI assistance starts by assembling bounded evidence. A short article can use the whole text; a long article or library question retrieves passages. Paragraph offsets and knowledge records become citation IDs before the provider receives the request.
Summary, article, article + knowledge, or library
The scope is explicit. Short articles may fit whole; long articles and library questions retrieve passages within a fixed input budget.
Paragraph, highlight, and library citations
Article paragraphs use [P], saved highlights use [H], and other library sources use [S]. Citation IDs not present in the supplied context are removed before display.
Recent turns plus bounded rolling memory
The latest messages remain verbatim within per-message limits. Earlier user questions are compacted into a small reminder and previous assistant answers are never treated as evidence.
Concise, balanced, or deep
Choose answer language, response style, context scope, citations, temperature, token limit, and supported reasoning effort.
OpenAI, OpenRouter, Ollama, or custom
Rinwa discovers models through an OpenAI-compatible /models endpoint and passes supported reasoning effort without binding the UI to one vendor.
Reading remains local and usable
Rinwa keeps deterministic local fallbacks for development and non-AI paths. No configured provider means no external answer—not a broken library.
Per-feed automatic translation and summary are off by default, require current data-sharing consent, and include a background token-cost hint. AI may suggest note text, but it cannot modify notes without confirmation.
A question can become a lasting reading stream.
ImplementedSaved searches turn a structured local query into an always-current virtual feed. They appear in the sidebar beside smart feeds, carry their own unread count, and open the ordinary article list and reader.
Explainable filters
V1 uses an AND-filter, not an opaque AI rule: keyword, feed IDs, groups, author, domain, read state, starred state, 24-hour / 7-day / 30-day windows, and tags.
Portable identity
Queries store stable feed global IDs rather than one device’s database row IDs. Saved views can therefore travel through the operation log.
Shared foundation
Evaluation happens on the API side through one resolver, so the sidebar, unread counts, mark-all-read, backup, sync, and future automation can share the same meaning.
Prefer an unanchored highlight to a wrong one.
ImplementedRinwa stores the selected quote with bounded prefix and suffix context. When extraction changes the article HTML, it relocates exact normalized text conservatively across block and inline-element boundaries.
Piecewise inline marks
A quote may span multiple text nodes or inline elements. Rinwa renders one logical highlight as accessible pieces without flattening the article.
Context disambiguation
Repeated quotes are scored against their saved prefix and suffix. Weak or absent evidence produces an unanchored state instead of choosing the earliest match.
Jump to source
Selecting a saved highlight closes the knowledge sheet, centers the matching source mark, and respects reduced-motion preferences.
Read-only popover
Activating the mark shows its saved note, or a quiet no-note state. Editing and single-highlight removal are intentionally not offered in this v1 surface.
Your reading can leave the app.
ImplementedStarred articles can carry an editable summary, personal note, tags, highlights, translated excerpts, and external references. These are user data, not disposable AI output.
Bidirectional Obsidian
Rinwa writes only clearly marked managed sections. User-authored Markdown around them is preserved, and changes made in the Vault can return to Rinwa through the local sync worker.
Safe removal
Removing a knowledge item clears the bookmark and its managed record. The exported Vault file is kept by default and deleted only when the user explicitly chooses that option.
Local MCP over stdio
A standalone local server exposes feeds, items, search, knowledge, tags, statistics, health, and OPML to AI agents. Safe writes require a local token; destructive actions and Rinwa’s external AI calls are not exposed.
The MCP process calls Rinwa’s local HTTP API rather than opening SQLite directly. It is intended for desktop and local development environments, not as an on-device mobile service.
A plugin boundary begins with less authority.
P0/P1 foundationSourceConnector separates source-specific discovery and pulling from Rinwa's database. RSS and public YouTube are registered through the same factory and implement the same interface that a future connector would: probe, discover, resolveSubscription, and pullEntries.
fetch(); no database or filesystem handle
Capabilities describe behavior
The v1 contract recognizes discovery, URL resolution, incremental pulling, authentication, inline content, and media assets. Unknown capabilities fail descriptor validation instead of silently expanding authority.
Network and pacing are explicit
The descriptor carries allowed hosts, minimum request interval, maximum concurrency, and an optional preferred page size. The current host uses the declared network hosts when it creates the fetch context.
The SDK does not import the app
Descriptors, subscription intents, entries, media assets, requests, responses, and the JSON message ABI live in packages/connector-sdk. Storage remains a host concern.
These tiers are a permission vocabulary, not a claim that article access is already exposed. Both built-ins declare only query and source-id; the current ConnectorContext supplies no article-body API at all.
Validate every hop
Redirects are followed manually. Every destination is checked again for protocol, declared host policy, and public addressing before the next request.
Deny private networks
Loopback, private, link-local, carrier-grade NAT, cloud metadata, and equivalent IPv6 ranges are rejected so a connector cannot be a convenient path into the user's LAN.
Limit the response
The direct context caps redirects at five, response bodies at 8 MiB, and requests at 15 seconds. Sensitive headers are stripped when a redirect crosses origins.
Normalize before storage
Connector output enters the same ingestion service used by RSS, where stable IDs, content hashes, media, extraction policy, and later indexing have one meaning.
RSS and YouTube prove that the interface is used, not merely proposed. But connectors are still built into the API process: there is no third-party package loader or security sandbox for arbitrary code. DNS rebinding also remains a documented time-of-check/time-of-use limit until the resolved address can be pinned to the socket.
An exit route that can also bring you back.
ImplementedBackup is separate from sync. It can preserve only subscriptions in a readable file, or create a full encrypted snapshot of user-owned reading and knowledge data.
Readable export
Subscriptions, groups, aggregate settings, languages, and automatic AI preferences are exported without encryption.
AES-256-GCM
A passphrase is strengthened with scrypt; a random salt, nonce, and authenticated encryption protect the full backup.
Merge or replace
Merge preserves local records where appropriate. Replace runs transactionally and is designed to avoid partial destructive restores.
Desktop folders
Daily or weekly backups can write to a chosen local folder, keep a configured number of recent files, and use OS secure storage for the passphrase.
Web development mode supports manual download and upload. Mobile background scheduling is not part of the current backup implementation.
Sync operations, not database files.
Optional serverEach device remains independently useful. A local change is recorded before upload as an operation with a stable ID, entity, action, JSON payload, device sequence, timestamp, and HLC ordering key. The server relays the log; clients materialize and merge it into their own SQLite database.
Record
deviceId:sequence, entity, action, payload, timestamp, and HLC are persisted locally before upload.
Relay
The server validates bounded batches. Duplicate operation IDs become harmless CouchDB conflicts.
Merge by field
sync_field_clocks stores one HLC per entity field. shouldApplyField advances only the field whose incoming clock is newer.
Delete with memory
A deleted field clock survives the row. An older upsert cannot recreate it; a genuinely newer re-add can.
Current protocol entities
connector_subscriptionfeedhighlight
item_stateitem_summaryknowledge
preferencesread_later_capturereading_position
rulesaved_search
createHlc()
epochMillis:sequence:deviceId
Thirteen-digit epoch milliseconds provide the broad chronological order.
A per-device sequence orders multiple operations even when they share the same millisecond.
The device ID makes equal time and sequence values compare consistently on every client.
A wall clock alone can produce equal timestamps, and devices can disagree about time. Rinwa's current HLC-shaped key guarantees deterministic lexical ordering, but it does not eliminate clock skew: a badly wrong device clock can still influence which same-field write is considered newer.
isRead = trueadvances the isRead clockisStarred = trueadvances the isStarred clockNaive last-writer-wins at row level would replace the entire item-state row and lose one edit. Rinwa compares fields independently. If both devices edit the same field, the newer HLC wins.
Move subscriptions and URLs, not fetched bodies
A connector subscription carries source identity and settings. A read-later capture carries its URL and capture time. Each receiving device fetches and stores the resulting content locally, reducing replicated private content and bandwidth.
Values that must agree share one clock
Reading position uses one anchor clock for item ID plus sort key. Read later uses one capture clock for URL plus capture time, so paired values cannot be assembled from different writes.
The log records intent; services do the work
A newly imported feed is scheduled for local fetching. Read-later capture is queued outside the apply loop, so network work does not make operation application destructive or blocking.
Tombstones arbitrate delete versus re-add
Feed, knowledge, connector, saved-search, reading-position, rule, highlight, and read-later deletion paths advance deleted, preventing stale snapshots from resurrecting removed records.
Feed and connector intent · item state and summaries · knowledge and highlights · reading preferences and positions · rules · saved searches · read-later captures
Article bodies · extracted HTML · media · translations · model files · embeddings · full-text and vector indexes
kappain develops Rinwa as an open-source reader. Managed Rinwa Sync is the planned commercial service; local reading remains independent, and self-hosting stays within the protocol boundary.
The server can provision Qdrant, but the protocol advertises semanticSearch: false. Current semantic retrieval is local; a configured collection is not a shipped remote-search feature.
App versions and content versions are separate.
Core invariantSQLite is the primary store on each device. A visual update, new setting, or gesture fix does not invalidate article data. Extraction, translation, generated summaries, and embeddings each own a compatibility version.
Translation, summary, and chat content is not sent until the current data-sharing consent is accepted. Consent can be withdrawn.
Packaged desktop clients use OS secure storage for provider keys and sync tokens. Legacy plaintext fields are migration paths, not the design to copy.
Article bodies, prompts, API keys, sync tokens, and Vault contents must not be logged.
Existing databases are migrated in place. Development does not delete or recreate a user’s library.
Notes, tags, highlights, references, and manually edited summaries are never treated as disposable generated cache.
OPML, Obsidian, and backup keep a practical route out of the application.
One interface, two replaceable seams.
Mobile not releasedReact and Vite provide the shared reading surface. Tauri 2 packages it for desktop and mobile. Storage transport is hidden behind ReaderRepository; runtime abilities are hidden behind PlatformAdapter. Components should ask what the runtime can do, not which operating system name it has.
listFeeds · getItems · writestauri-plugin-sqlThe repository chooses at runtime
getReaderRepository() selects SQLite only when the shell reports native API transport and a local SQL capability. Every other environment receives the HTTP implementation.
The interface is deliberately narrow
Its current reading-path core covers feed listing, item queries, read/star state, feed settings, and feed deletion. AI, knowledge, OPML, and sync remain remote operations outside this interface.
The cut-over is not complete
Main feed reads and feed-setting writes use the repository. Scattered item-state calls and real iOS/Android device verification remain, and the mobile database still needs a population path.
The browser adapter returns false or null where that is an honest answer and throws PlatformCapabilityError for unavailable secure storage or in-app browsing. The native shell can override its capability map instead of pretending every platform has finished support.
The shared UI and desktop shell exist, including native windows, file selection, SQLite bridge, secure-storage foundation, and in-app web windows. A signed, notarized release is not available yet.
The shared UI can be packaged, but local SQLite cut-over, Keystore, background refresh, real-device validation, signing, and store distribution remain.
They reuse the same React/Tauri architecture. Native build, database population, signing, device validation, and distribution workflows are unfinished.
The details below are generated from the product repository.
Build-checkedThese pages follow selected Markdown documents in feedsuite. A site build regenerates them, validates local links, and packages the result; product documentation does not need to be copied into two repositories by hand.
This page remains intentionally editorial. The reference pages carry implementation detail and link back to the exact source document on GitHub.
Implemented is not the same as released.
Reading and feed management, OPML, original-first translation, multi-provider AI, local hybrid retrieval, saved searches, stable highlight anchors, knowledge and Obsidian, local MCP, P0/P1 connectors with YouTube, encrypted backup, operation-log sync, command palette, and one shared responsive UI.
Local embeddings are opt-in; AI and sync require configuration; connectors are a P0/P1 built-in foundation rather than a marketplace; Android is a development preview.
Native mobile background refresh, complete Android Keystore validation, full mobile SQLite cut-over and population, signed/notarized macOS packages, iOS and Windows release packages, store submission, and a third-party connector marketplace.
Need implementation-level detail?
Read the source on GitHub ↗