MemorySyncMemorySync
Core Concepts

Memory Fundamentals

A memory in MemorySync is a single durable record of one piece of knowledge — a preference, a fact, an event, a decision, an insight — that the API can recall by meaning later. This page is the mental model: what a memory is, how it gets created, and what scopes own it.

A one-line definition you can quote

A memory is a row in the memories table that pairs an encrypted text payload with an embedding vector, a set of scope keys (tenant, project, user, environment), a set of scoring signals, and a lifecycle state.

Why "encrypted"
Each user has a per-user encryption key. The text column stores authenticated-encryption ciphertext, not plain text. Only the API process can decrypt it during retrieval.

The two ways memories come into existence

PathTriggerWhat you supply
Direct writePOST /memory/addA text string (or its alias content) plus optional metadata.
ExtractionIntegration sync, web crawl, or chat captureRaw external content. The extraction pipeline produces one or more MemoryCandidate rows that are promoted into Memory rows after validation.

Both paths end the same way: a row in memories with an embedding, a tier, and a retention status.

The five scope keys every memory carries

KeySourceWhy it exists
user_idServer-resolved (JWT user, or end-user mapped from X-End-User-ID).Hard owner of the memory. Body user_id is ignored.
tenant_idRead off the user's row, never trusted from input.Outer isolation boundary — every read must filter on it.
project_idX-Project-ID header, or pinned on the API key.Sub-scope inside a tenant. Nullable for org-wide memories.
environmentStamped from request context — defaults to production.Must be one of development, staging, production.
end_user_id (optional)X-End-User-ID header on service-auth calls.Lets one API key represent many real users without collision.

What you write vs what you read back

The request shape is small. The response shape is large because the platform enriches the record on the way in.

StageField set
Request bodytext (or content), optional metadata, tags, source, event_type, importance, ttl_minutes, deduplicate, user_id, project_id.
Server overridesuser_id, project_id, environment are always taken from request context, never from the body.
Computed at writevector, vector_id, embedding model and version, semantic tags, tier, retention_status, importance_score, quality_score, confidence_score, freshness_score.
ResponseMemoryResponse with the stored fields plus the semantic enrichment.

When a memory becomes recallable

  1. 1The row is committed with retention_status = "active".
  2. 2The text is embedded into the configured embedding model.
  3. 3The vector and its scope metadata land in the per-user vector namespace.
  4. 4POST /memory/query returns the row only if retention_status = "active" AND the requested scope keys match.

What a memory is not

  • Not a chat message — see Sessions & Threads for conversation modeling.
  • Not a file or attachment — only text content is stored. Integrations extract memories from files; the file itself is not a memory.
  • Not a log line — auditable lifecycle events live in memory_events, not in the memory row.
  • Not bound to a session — memories are scoped to (tenant, project, user), never to a single conversation.

Quick reference card

QuestionAnswer
What identifies a memory uniquely?id (integer primary key) plus vector_id (string) for the vector store side.
What text is actually embedded?Semantic-enriched text produced by the extraction or preprocessing step — not the raw input string.
Can two memories carry the same content?Yes, but writes use source_input_hash to detect duplicates; with deduplicate=true (default) the API may skip the insert.
Does a memory ever update?Lifecycle fields update (tier, retention_status, usage_count, decay_score). The text payload itself is immutable.