The Problem
After each conversation, EverOS extracts an Episode, a summary of a conversation segment. The same topic ends up split across several Episodes, each a point-in-time snapshot written with whatever was known at that moment:“Andrew has no pets yet” (Aug) → “Andrew adopted Toby” (Sep) → “Andrew also adopted Buddy” (Oct)Three Episodes, each correct on its own, none complete, and one is now stale. Ask “how many pets does Andrew have?” and retrieval surfaces all three fragmented, overlapping, partly-contradictory pieces. Traditional approaches either keep everything (noise) or let new memories overwrite old ones (broken timeline, lost history). Reflection takes a third path: like a person reviewing periodically, it consolidates the cluster into one accurate, coherent narrative.
How It Works
Reflection runs offline, separate from the live conversation path. The online path keeps extracting Episodes and clustering them; Reflection later consumes those clusters; it never sits between a user and a response.Select
Pick clusters worth consolidating: not yet consolidated and holding ≥ 2 members, or already consolidated and since joined by new members. At most 10 clusters per run, largest first.
Merge
Hand the cluster’s Episodes to the LLM in chronological order and merge them into one narrative: preserve facts, resolve contradictions by keeping the latest state, restore the timeline, drop duplicates, end on the current state. A previously consolidated cluster is updated incrementally: only the new fragments are folded in.
Re-extract
The merged narrative is written to Markdown and triggers re-extraction of atomic facts, keeping derived data consistent.
parent_type: cluster, transparent to retrieval, with no search-pipeline changes. Default search excludes any memory carrying deprecated_by, so a query like “how many pets does Andrew have” hits only the one complete narrative:
“Andrew initially had no pets. He later adopted a dog named Toby, then another named Buddy. He currently has two dogs.”
Quick Start
Examples assume EverOS is running on the default port
8000. <root> is the EverOS memory root.<root>/ome.toml, one line:
cron:
enabled = false stops the next run; a run already in progress finishes normally.
Where the result lands
Each run appends one merged narrative to the relevant user’s Episode log and marks the fragments it replaces as archived. Markdown is the source of truth, so just open the user’s Episode log:parent_type: cluster (Episodes from ordinary conversation are parent_type: memcell):
Triggering a run on demand
The normal mode is the scheduled run. For testing or debugging, trigger one immediately:force: true runs even when enabled = false. status is "ok" (finished) or "timeout" (didn’t finish in time); an unknown strategy name returns 404.
Originals Are Retired, Not Deleted
This is the essential difference from crude overwriting, and it’s what makes consolidation safe to trust. Replaced Episodes are never deleted; they are soft-archived:- They no longer appear in default search (anything with
deprecated_byis excluded), so they don’t pollute the current conversation. - Their Markdown frontmatter records the archive mapping (
deprecated_entries), pointing at the narrative that replaced them. - Because Markdown is the source of truth, every consolidation stays traceable to its original content, and the indexes can always be rebuilt from it.
reflection_report audit record (cluster_id, mode = init/update, source_count, merged_entry_id, created_at), so consolidation history is fully inspectable.
Prerequisites
Reflection’s merge step calls an LLM, and re-clustering the merged narrative calls an embedding model. Configure both as you would for the rest of EverOS: an OpenAI-compatible[llm] and [embedding] block in <root>/everos.toml, or the matching EVEROS_LLM__* / EVEROS_EMBEDDING__* environment variables. If a provider is unavailable, the affected clusters are skipped and logged rather than failing the run.
Configuration
Two files, two scopes: you write only the keys you want to override, and everything else falls back to shipped defaults.| Setting | File | Default | Description |
|---|---|---|---|
reflect_episodes.enabled | ome.toml | false | Set true to enable (the only setting needed) |
reflect_episodes.cron | ome.toml | 0 2 * * 1 | Run time as a cron expression (Mondays 02:00); optional |
clustering.threshold | everos.toml | 0.65 | Clustering similarity threshold |
clustering.time_window_days | everos.toml | 7.0 | Clustering time window (days) |
End-to-End Example
Enable Reflection, trigger a run by hand (in production it runs on schedule), then confirm that searching the topic returns the single merged narrative instead of the scattered fragments:session_id is null (the aggregation-product marker), and episode holds the full consolidated text.
Design Notes
Why Reflection is shaped this way:- Offline and scheduled: merging is a heavy, lossy LLM operation, so it runs off the request path (conversations stay fast), and a weekly cadence lets enough new fragments accumulate to be worth re-merging.
- Soft-archive, never delete: originals stay in Markdown, so every consolidation is traceable and the indexes are always rebuildable.
- A merged narrative is just an Episode: reusing the Episode type means search and every downstream consumer keep working unchanged, so Reflection introduces no new retrieval path.

