Skip to content

STARE: five dimensions of significance

A vector store asks one question about a memory: does it look like the query? That is not enough to decide what an agent should remember. A passing remark and a standing decision can look equally similar to a question. A fact that was true last quarter can look as relevant as one that is true now.

Meaning Memory asks five questions about every memory. Their initials are STARE.

Dimension The question it answers
S Significance How much does this matter?
T Temporal When was this true, and is it still?
A Asymmetry Whose perspective does this memory serve?
R Relational What does it connect to, and does it agree with what it connects to?
E Episodic What ongoing story is it part of?

The five dimensions come from research on how people decide what is worth remembering. They are not equally mature in the engine, and the engine says so: the readiness report below is generated from the code, not written by hand.

Every memory has a significance value between 0 and 1. It is the main ranking signal:

  • Search ranks results by significance and age. By default a memory’s weight halves for every 90 days since it was written; MM_S1_HALF_LIFE_DAYS changes the period.
  • When the compiled memory file has to fit its budget, the least significant memories are dropped first. Pinned memories and memories with significance 0.90 or above are protected: they go only if the protected memories alone overflow the budget.
  • People and agents change significance with feedback: mm_feedback with important, demote, pin or unpin. Each change is recorded with its reason; see Provenance.

mm_remember stores a new memory at 0.80 unless the call passes significance.

Temporal answers when. Two search arguments use it:

  • as_of returns the memories that were valid at a past moment (an ISO 8601 timestamp).
  • currently_valid: true returns only memories still in effect; false returns the ones that have expired.

A memory with no validity window is treated as valid at any time. Temporal also covers decay curves, which make a memory count for less in the compiled file as it ages. Decay curves are off by default; Decay and recency covers turning them on and the presets. Decay changes the compiled file only; the stored significance stays as it was.

Asymmetry is about perspective: who a memory is for, and how clearly it says where a claim came from. It is built but switched off. In testing, a source that wrote confidently was marked as strongly as a source that was right, so the engine does not use Asymmetry for ranking until it can tell the two apart.

Relational links memories to each other and to the people, customers and projects they mention. On Postgres:

  • related_to restricts a search to the memories directly connected to one memory.
  • min_r returns only memories with at least that many connections.

Divergence detection, which flags when two agents’ memories disagree, is built but off. Multi-hop traversal, following links several steps out, is opt-in and meant for tracing where something came from, not for finding things: in testing it did not find more than plain semantic search.

Episodic is the difference between a fact and an account of what happened. Today it ships as Open Threads: during a full consolidation run, related events across sessions are grouped, and the compiled memory file gets a section listing the threads still in progress. It is in pilot and off by default. Recalling a whole story across many sessions on request is in preview and not yet reliable.

You can still store and find events today: write them with memory_type: "episodic". See The four memory types.

Besides the single significance value, a memory can carry a score from 0 to 1 for each of the five dimensions. Scores get onto a memory in three ways:

  1. The writer supplies them. mm_remember accepts stare_scores:

    mm_remember({"source": "agent", "text": "Zephyr Logistics renews its support contract every March; the renewal decides next year's budget.",
    "category": "fact", "stare_scores": {"s": 0.9, "t": 0.4}})
  2. Bulk writes score automatically. mm_bulk_remember and meaning-memory seed run a small scorer bundled with the engine. Dimensions and categories the scorer is not calibrated for are left empty by default; MM_STARE_AUTO_SKIP_DIMS and MM_STARE_AUTO_SKIP_CATEGORIES change that list.

  3. Consolidation’s extraction can attach scores to the facts it extracts, when you have configured an extraction model.

A dimension with no score is left empty, never filled with a guess.

By default the dimension scores do not change ranking. They are for filtering and for showing at a glance why a memory is there. Filter a search with min_s_score, min_t_score, min_a_score, min_r_score or min_e_score; a memory with no score on that dimension is left out:

mm_search({"query": "Zephyr", "min_s_score": 0.8})
| # | mem_id | Sig | Eligible | Category | Date | Text |
|---|--------|-----|----------|----------|------|------|
| 1 | `83f33219d7033862` | 0.80 | - | fact | 2026-10-03 | Zephyr Logistics renews its support contract every March; the renewal decides ne... |

The same search without the filter returns all three Zephyr memories in that workspace.

In the compiled memory file, each memory is prefixed with one mark per dimension, in S, T, A, R, E order: ● for a score of 0.6 or more, ○ for less, — for no score. The memory above shows as:

- ●○——— Zephyr Logistics renews its support contract every March; the renewal decides next year's budget.

MM_STARE_DISPLAY_MODE=verbose prints the numbers instead, and off removes the marks.

mm_stare_readiness reports each capability on three axes: whether it is built, whether it is switched on, and what evidence backs it. The engine will not report evidence beyond a failing check.

mm_stare_readiness({})
| Dim | Capability | implementation | deployment | evidence | verdict |
|---|---|---|---|---|---|
| **S (Significance)** | `core` | `GA` | `customer-default` | `gated-eval` | `pass` |
| **T (Temporal)** | `core` | `GA` | `customer-default` | `gated-eval` | `pass` |
| **A (Asymmetry)** | `encoding` | `beta` | `off` | `none` | `fail` |
| **R (Relational)** | `divergence` | `beta` | `off` | `synthetic` | `pending` |
| **R (Relational)** | `traversal` | `beta` | `opt-in` | `synthetic` | `stale` |
| **E (Episodic)** | `anchor` | `beta` | `pilot` | `gated-eval` | `pass` |
| **E (Episodic)** | `saga` | `preview` | `off` | `none` | `pending` |

The full report (shortened here) also lists each open check and what it blocks. In short: build on Significance and Temporal; treat the rest as features to switch on deliberately and measure in your own setting.