Data model · Fields

Every field keeps its full history.

Fields are the fine-grained state on a topic. When a value changes, MemState never silently overwrites it — the previous value is preserved with its timestamp and source, so retrieval can tell the current truth from what used to be true.

Value history (formal view)

Fix a semantic unit ui (a topic) and a field name f. MemState stores an ordered sequence of revisions; write each revision as a tuple (value, time, provenance) matching the wire shape value, valid_from, provenance, with optional rationale fields why_changed and impact_expected. That sequence is the empirical trace of how the field evolved — what the agent and tools asserted, when, and from which surface.

Query soundness (default). Unless the caller enables temporal expansion, retrieval treats the newest revision as current truth and does not mix older values into the default bundle. When explain or temporal stages are on, the same ordered trace is exposed so the model can answer “how did we get here?” without contradicting the append-only discipline on disk. See also the GEM state overview for how Dt and St relate.

Why history and not overwrite

Overwriting a value loses information the agent may need later: when did this change, who changed it, what was the old value? It also breaks any form of audit, rollback, or "what did we believe before" reasoning.

MemState treats every field as a stack of revisions, newest first. Writes append. Reads return the newest revision by default. Callers that explicitly ask for history get the full timeline.

Field: owner current value = "Aya" 2026-04-22 · provenance: ui value = "Priya" 2026-03-10 · provenance: llm value = "unassigned" 2026-02-01 · provenance: api Reads (default) → return current revision "Aya" Reads with history → return full stack [current + older] Writes → append new revision

Each field is a time-ordered stack of revisions. Writes append. Reads default to the newest one; history is opt-in.

What a revision contains

Every entry in a field's history carries enough metadata to explain the change.

AttributeDescription
idUnique revision id (UUID).
valueThe value at this point in time.
valid_fromTimestamp the revision was recorded.
provenanceWhere the change came from: api, ui, llm, mcp, or an internal revision event.
why_changedOptional reason, usually written by the agent or the caller.
impact_expectedOptional forward-looking note about consequences of the change.

Field record

{
  "owner": {
    "field_type": "string",
    "ref_topic_id": null,
    "salience": 1.2,
    "history": [
      {
        "id": "6f3...",
        "valid_from": "2026-04-22T12:00:00+00:00",
        "value": "Aya",
        "provenance": "ui",
        "why_changed": "handoff from Priya"
      },
      {
        "id": "2a1...",
        "valid_from": "2026-03-10T09:10:00+00:00",
        "value": "Priya",
        "provenance": "llm"
      }
    ]
  }
}

Supported types

Type Typical value Notes
stringFree textDefault type when none is specified.
intInteger numberStored as JSON number in history.
floatDecimal numberStored as JSON number in history.
booltrue / false 
dateDate stringConvention-based; not strictly parsed.
datetimeDate-time stringConvention-based; not strictly parsed.
listJSON arrayNested content allowed.
jsonAny JSON shapeOpaque to MemState; size affects latency.

The write path

  1. An observation reaches MemState. Typically via /v1/ingest, a UI tool, or a chat-driven tool call that forwards what the agent noticed.
  2. MemState builds a new revision. It assigns a UUID, stamps the time, records the provenance, and carries any reason the caller provided.
  3. The revision is prepended. It becomes the new current value; previous revisions remain in the stack.
  4. Limits are enforced. If the stack exceeds the configured history cap, the oldest revisions are trimmed.
  5. Topic salience is refreshed. The topic's importance score is recomputed from its fields so retrieval stays in sync.

Field-level salience

  • Each field carries its own salience score between 0 and 10.
  • Retrieval bumps salience on read; forgetting consults it when deciding what to attenuate.
  • The topic's overall salience tracks the average of its field saliences, so the node-level signal is always consistent with its parts.

Limits

  • History length is capped at 500 revisions per field by default (max_field_history). Oldest revisions are trimmed beyond the cap.
  • Field salience is clamped to the range [0, 10].
  • JSON payload size is not enforced by MemState but affects retrieval and API response latency.

Code map

  • memstate.datamodel.fields.TopicField — field shape, type coercion, salience clamp.
  • memstate.datamodel.fields.FieldHistoryEntry — revision payload.
  • memstate.store.GraphStore.append_field_history — write path and trimming.
  • memstate.core.Executor._field_bundle — read path for current-only and history expansions.