Loading repository data…
Loading repository data…
wangjiake / repository
Riverse — A personal AI agent designed for your own devices. Persistent memory, offline cognition, grows with every conversation. River Algorithm. Local-first.
Personal memory engine for AI — extracts, ages, and resolves your memories from every conversation. Runs locally. Works with any LLM.
📖 Full documentation: wangjiake.github.io/riverse-docs
Two months ago you mentioned changing jobs. You just said you've been having headaches.
🤖 I'm sorry to hear that. Common causes of headaches: dehydration, screen time, stress...
No connection to your life context.
🤖 You started the new management role about two months ago, and your sleep got worse around the same time — you mentioned staying up past 1am several times. The headaches might be linked. How's the work pressure been?
Causal chain: job change → sleep disruption → headaches. Timeline-aware, personally weighted.
mkdir jkriver && cd jkriver
curl -O https://raw.githubusercontent.com/wangjiake/JKRiver/main/docker/docker-compose.yaml
docker compose pull && docker compose up -d
docker logs jkriver-jkriver-1 2>&1 | grep "Token:"
Open http://localhost:1234, enter the token, set your API key in System. Done.
| Service | URL | What it does |
|---|---|---|
| JKRiver | http://localhost:1234 | Web chat + system config |
| RiverHistory | http://localhost:2345 | Profile viewer |
| API Docs | http://localhost:8400/docs | REST API reference |
Full Docker guide (bots, data import, demo): docker/README.md
JKRiver now supports multiple family members on a single deployment, each with their own isolated chat history, profile, memory, and finance/health data — sharing one Postgres database. Set up via System → 家庭成员:
accounts table maps an internal name (e.g. wife) to a numeric owner_id. Every business row (observations, profile, memory, finance, etc.) is namespaced by this id.access_tokens table stores per-device session tokens (SHA-256 hashed). Each family member can have multiple devices (their phone, your iPad, etc.).family.require_admin_approval in settings.yaml.channel_identities maps Telegram/Discord user_id → owner_id, so messages from your wife's Telegram get routed to her account, not yours.send icon. Stop button still red when a response is streaming.jk_lang cookie), so navigation between pages no longer flashes English text before client-side JS swaps it.<head> script before the first paint.12 SQL migrations under migrations/ cover the multi-owner roll-out: 005_multi_owner.sql adds owner_id columns to 27 business tables (default 1 for existing rows); 006-007 fix UNIQUE constraints; 008 drops the legacy hypotheses table (functionality merged into user_profile.layer); 009 hashes device tokens and adds device metadata; 010-012 cover geoip, admin approval, and clean-up. Migrations are idempotent and run automatically at startup.
After each conversation, Riverse runs an offline consolidation pipeline (Sleep) that builds a structured personal profile:
suspected, get promoted to confirmed then established through multi-turn verificationdecay_days TTL; stale facts expire automatically without manual cleanupend_time and superseded by the new one; the full history is preservedAll data lives in a local PostgreSQL database. Nothing leaves your machine.
The entire pipeline runs atomically inside a single database transaction. If any step fails, everything rolls back.
| Phase | Step | What it does |
|---|---|---|
| Extract | 1. Load initial | Load existing profile and life trajectory |
| 2. Extract sessions | LLM extracts observations, tags, relationships, and events from each unprocessed conversation | |
| Analyze | 3. Analyze behavior | LLM infers behavioral patterns from observations (e.g. "sends messages late at night" → "night owl"); generates clarification strategies |
| 4. Classify & integrate | LLM classifies each observation as support, contradict, evidence_against, or new relative to existing facts; integrates results into the profile | |
| 5. Cross-verify | Suspected facts with stated source + mention count ≥ 2 auto-confirm; remaining suspected facts undergo LLM cross-verification with timeline and conversation history | |
| 6. Resolve disputes | LLM arbitrates contradicting fact pairs (supersede chains) — accept new or reject new | |
| Maintain | 7. Extract edges | Build knowledge graph edges between affected facts |
| 8. Expire facts | Close facts past their expires_at date; generate verification strategies for next conversation | |
| 9. Maturity decay | Adjust decay_days based on fact age and evidence count — long-standing, well-evidenced facts live longer (up to 2 years) | |
| Output | 10. User model | LLM analyzes communication style dimensions from conversations |
| 11. Trajectory | Update life-phase trajectory when significant changes are detected | |
| 12. Consolidate | Deduplicate the profile | |
| 13. Snapshot | Pre-compile a memory snapshot (profile + model + events + relationships + knowledge graph) for fast context injection | |
| 14. Finalize | Mark conversations as processed |
After the transaction, non-critical post-processing runs: vector embedding and memory clustering.
Riverse's memory pipeline is architecturally designed beyond what current general-purpose LLMs can fully deliver. The 14-step Sleep consolidation requires precise structured judgment at each stage — observation extraction, fact classification, cross-verification, contradiction resolution — and cascading errors from imprecise LLM outputs are currently the primary accuracy bottleneck, not the algorithm itself.
No LLM today is purpose-trained for personal memory consolidation. The ideal path would be a dedicated memory LLM optimized for structured profile extraction and multi-fact reasoning. The author has a clear design for what that model should look like, but training it requires compute and data resources beyond what an individual can access.
If your company is building a memory-focused model or working on personal AI and you have a role that fits — I'd love to hear from you: mailwangjk@gmail.com
Until then, the algorithm rides on general-purpose models and improves automatically with each stronger generation, with zero code changes required. The pipeline is also a practical benchmark: if extraction errors are high, the cause is almost always LLM capability, not a bug. Try a stronger model and watch the difference.
Query memory from any external system, agent, or LLM:
| Endpoint | Description |
|---|---|
GET /profile | Current confirmed profile (category, field, value) |
GET /hypotheses | Full profile with confidence levels and status |
POST /chat | Send a message; response uses full memory context |
POST /sleep | Trigger memory consolidation manually |
GET /health | Service health |
Authentication: X-Device-Token: <token> header on every request.
| RAG / Existing AI Memory | Riverse | |
|---|---|---|
| Retrieval | Vector similarity — finds text that "looks similar" | Profile weighting — ranked by relevance to you |
| Timeline | No timeline — 3 years ago and yesterday weigh the same | Temporal evolution — facts have momentum and decay |
| Reasoning | No causal inference — facts stay as isolated fragments | Causal chains — connects related facts automatically |
| Confidence | All facts have equal weight | suspected → confirmed → established |
| Invalidation | No mechanism — old facts persist forever | Facts expire, get superseded, or are rejected |
| Data ownership | Cloud-dependent, platform-owned | Local-first — your device, your data |
The demo includes 20 casual conversations with a fictional character. From raw chat history:
Riverse extracts a structured, evolving profile:
Riverse ships with a personal AI agent that consumes the memory engine: