Memory
Two ways to remember, pick one: the built-in local memory or OpenViking semantic memory. When a service is unavailable it says so, and the two never stand in for each other.
Design principles
- Two ways, pick one. Choose under Settings → Advanced → Memory → Memory mode. The setting is
memory.backend(openvikingorembedded); new configurations default toopenviking. - Never a silent fallback. When the OpenViking service is offline, memory operations return
503with a clear message instead of switching to local records and pretending to hit; each way keeps its own memory with no migration, and switching back restores what was there. - Isolated per project. Each project's directory is
viking://resources/projects/<projectId>, managed automatically. Retrieval results are filtered by project scope once more. - Memory is not capability. A memory write only adds a retrievable record; changes in behaviour go through gene-tree evolution.
- Session logs, drafts and project configuration are not in the memory index.
The two ways
| OpenViking semantic memory | Local memory (built in) | |
|---|---|---|
| Needs | Docker, the OpenViking service, an embedding model and a text model | Nothing |
| Search | By meaning: found even when worded differently or in another language | By keyword: finds only content using the same words |
| Conversation memory | Distilled into long-term memory by a model | Each conversation segment saved as written, no model call |
| Data location | The OpenViking service's data volume | <state>.rna/memory/embedded.sqlite next to the state file (mode 0600) |
| When a conversation is deleted | Distilled project memory is kept | What was saved from that conversation is deleted with it |
Local memory searches by SQLite FTS5 keywords: English and numbers by word, CJK text by adjacent character pairs, and a hit returns the passage of the file where the query words are densest. It does not understand synonyms or rephrasing, does not cross languages, and does not distil conclusions from conversation. Replayed over a real state (112 turns, 100 searches), an earlier turn of the same conversation ranked first 90% of the time and within the top five 98%; the sample is only 6 conversations, so this says “ranking is usable”, not a precise recall rate.
With either way, auto-recall, the memory tools, the memory browser, the sync queue, conversation deletion and rollback run the same code. The local memory database is backed up and restored with restore points. It needs Node's node:sqlite, which the runtime bundled with the desktop app includes. For deploying OpenViking see docs/openviking-local.md in the repository; for local memory details see docs/embedded-memory.md.
Auto-recall
In a real-model session with memory, JEV first judges at the start of a turn whether this turn needs memory; if so, a budgeted set of candidate excerpts is attached, and openviking_search and openviking_read expand overviews or originals on demand (the tool names are the same for both ways). What was attached is recorded in that turn's reference context and does not change the system prompt's cache prefix.
Common options in Settings → Memory:
- the Recall project memory automatically switch;
- the auto-save switch for project memory;
- Auto-recall budget (estimated tokens), 2048 by default;
- under Search options, how many candidates one search returns at most.
OpenViking's address and credentials sit in the collapsed “Advanced connection settings”, checked with “Test saved connection”; local memory is checked with “Check local memory”.
Three levels
| Level | What it reads |
|---|---|
| L0 | Directory abstract |
| L1 | Directory overview |
| L2 | Full file text, 200 lines by default, at most 500 |
--level is an index filter and cannot turn an abstract into full text.
Auto-save
Finished real turns are registered in a durable sync queue. With OpenViking they are then written to the service, committed and polled: a task_id only means the extraction task was accepted, not that learning has finished, and a commit with an unclear outcome is not blindly repeated. With local memory the committed conversation segment becomes one record as written, titled with your first line. Neither way back-fills the whole history in bulk.
The sync state is visible under “Memory sync” in settings: what is still being checked, what did not sync, and failed items that can be re-extracted (re-extraction costs money and asks you to confirm once more).
Rollback takes memory with it
When you edit or delete a message or roll back a turn, the memories OpenViking distilled from the removed turns are withdrawn too: only entries that exactly match the archive record are removed, and the rest stay and are reported to you. Deleting a whole conversation keeps the distilled project memory. There is no entry for deleting a single memory directly.
Delivered project documents are no longer withdrawn by mistake: only a real deletion or a privacy boundary withdraws them (switching model or opening a new conversation used to drift the project scope), and ones wrongly withdrawn earlier are re-indexed automatically.
CLI
./rna memory-config --backend embedded # or --backend openviking
./rna memory-config --endpoint http://127.0.0.1:1933 --api-key-env OPENVIKING_API_KEY --auto-recall true --context-budget 2048
./rna memory PROJECT_ID health
./rna memory PROJECT_ID initialize
./rna memory PROJECT_ID search "release conventions" --level L1
./rna memory PROJECT_ID read viking://resources/projects/PROJECT_ID/note.md --level L2
./rna memory PROJECT_ID write --file /path/to/note.md --title "Release conventions"
./rna doctor PROJECT_IDdoctor reports the background service, the model configuration, the memory connection's health and the last 7 days of use and evolution; it exits non-zero when the memory health check fails.