The Storage Stack
Three embedded pieces, each owning what it is best at. Markdown is the source of truth; the other two are derived and rebuildable.Delete the entire
.index/ directory and no memory is lost — it rebuilds from the .md tree. There is no separate “export”; the markdown is the export. See Operating It to trigger a rebuild.Storage Paths
The default memory root is~/.everos/ (override with EVEROS_MEMORY__ROOT or [memory] root in TOML). Configuration (the .env file) is separate from data (the memory root).
Memory is partitioned by <app_id>/<project_id> before the user-visible directories, so different (app, project) spaces never share a directory or cross in search. The reserved id "default" materialises as default_app / default_project on disk.
How a Memory Is Born
A message does not become memory immediately — it accumulates, a boundary is detected, an LLM extracts a cell, writers persist markdown, and the index catches up asynchronously./addappends messages to a per-(session_id, app_id, project_id)buffer and returnsaccumulated(orextractedif the boundary tripped on this call)./flushforces the boundary now (one extraction LLM call), used at the end of a chat/agent run.- Episode markdown is written synchronously — when
/flushreturnsextracted, the episode file is already on disk. - Everything else (atomic facts, foresight, profile, agent cases/skills) is produced asynchronously by the OME.
- The cascade daemon turns every
.mdwrite into LanceDB rows so the content becomes searchable.
Memory Types & Storage Strategies
Six memory kinds today, each picking one of three on-disk patterns:The Cascade Daemon
The cascade subsystem keeps LanceDB in sync with the markdown tree. It runs in-process with the server (a coroutine started by the app lifespan), not as a separate OS daemon.- A native filesystem watcher (
watchdog: FSEvents on macOS, inotify on Linux) sees a.mdcreate/modify. - The change is enqueued in the
md_change_statetable (SQLite) — durable, so a crash mid-sync replays on restart. - A worker drains the queue at entry-level granularity: it diffs the file, re-embeds only changed entries (keyed by
content_sha256), and upserts the LanceDB rows.
The Offline Memory Engine (OME)
Most memory kinds are not extracted on the request path — they are derived later by the OME, an in-process async strategy engine. When extraction carves a MemCell, it emits an event; OME strategies pick it up and write their markdown when ready:extract_atomic_facts— single-sentence facts from an episodeextract_foresight— anticipatory notesextract_user_profile— the aggregateduser.mdextract_agent_case— a reusable agent trajectoryextract_agent_skill— clusters related cases into a named skillreflect_episodes(cron, default off): consolidates related episodes into one coherent narrative. See Reflection.
ome.toml at the memory root (hot-reloaded within ~2s). Example — disable two strategies:
Consistency Model
A
/search immediately after the /flush that produced a record may miss it. The markdown is durable regardless; index lag never loses data. If you need read-your-write, retry with backoff, or force the queue with everos cascade sync.
Zero External Services
No database server, message broker, or vector service to run. Vector ANN, full-text BM25, and scalar filtering all execute inside the embedded LanceDB engine; SQLite is a local file. The whole stack is a single directory you can copy, back up, or check into git (user-visible parts only).There is no automatic “grep over markdown” search fallback — if the LanceDB index is unavailable, rebuild it from markdown rather than relying on a degraded search path.

