Memory Record
Every piece of information stored in engram is a memory record. Records are stored as vectors in Qdrant and surfaced through the MCP tools. This page documents every field, its serialized JSON name, allowed values, and who sets it.
Field reference
Section titled “Field reference”| Field | JSON key | Type | Set by | Description |
|---|---|---|---|---|
| ID | id |
string (UUID) | server | Unique record identifier, generated on creation |
| Content | content |
string | client | The memory text; also the text that is embedded |
| Scope | scope |
string | client | run:tier:repo identifier, e.g. eval-2026-05:project:selfhosted-cluster |
| Repo | repo |
string | client | Repository name or URL (optional context) |
| Workspace | workspace |
string | client | Workspace identifier (optional context) |
| Worktree path | worktree_path |
string | client | Path to the git worktree (optional context) |
| Base dir | base_dir |
string | client | Base directory for the project (optional context) |
| Source | source |
string | client | How the memory was produced — see Source values |
| Category | category |
string | client | What kind of memory — see Category values |
| Tags | tags |
string[] | client | Free-form labels |
| Summary | summary |
string | client/server | Short human-readable summary; omit or empty for none — see Summary fields |
| Summary Source | summary_source |
string | client/server | How the summary was produced: client (caller-authored), auto (offline-generated), or "" (none) |
| Summary Model | summary_model |
string | server | Name of the model used when summary_source=auto (e.g. gpt-4o-mini); empty when source is client or none |
| Actor | actor |
string | server | Verified caller identity extracted from the OIDC token (email, username, or subject); never client-supplied; empty when auth is disabled |
| Owner | owner |
string | server | Value of the configured owner claim (ENGRAM_OWNER_CLAIM, default email) — the authorization key; never client-supplied; empty string when auth is disabled (anonymous bucket) |
| Visibility | visibility |
string | client/server | "" (private, default) or "shared" — see Visibility |
| Created at | created_at |
string (RFC3339) | server | UTC timestamp of creation |
Source values
Section titled “Source values”The source field describes how the memory was produced. Exactly two values are
accepted by the store:
| Value | Meaning |
|---|---|
user-said |
The user stated this explicitly |
agent-inferred |
The agent derived or inferred this |
Discovery records always have source set to agent-inferred by the server.
Category values
Section titled “Category values”The category field classifies what kind of memory is stored:
| Value | Meaning |
|---|---|
decision |
An architectural or design decision |
preference |
A stated user or team preference |
convention |
A coding or workflow convention |
gotcha |
A known pitfall or non-obvious behaviour |
discovery |
Agent-earned codebase understanding (see Discovery fields) |
The discovery category is set by the server for records created via
store_discovery; client callers use the other four values with store_memory.
Visibility
Section titled “Visibility”The visibility field controls cross-actor reads:
| Value | Meaning |
|---|---|
"" (empty string) |
Private — only the owner can read and write |
"shared" |
Readable by any authenticated caller; writable only by owner |
Toggle visibility with set_visibility or update_memory’s shared argument.
Sharing grants read only — another actor can never write a record they do not
own, even when it is shared.
Summary fields
Section titled “Summary fields”Summaries help agents work with stored memories efficiently. Recall (via
search_memory / list_memory) returns compact summaries by default, keeping
the spine bootstrap small; full content is always accessible via get_memory
(id fetch) or by passing full=true to recall tools.
-
summary: Short human-readable digest of the memory. Optional. -
summary_source: Describes how the summary was produced:"client"— caller-authored and explicit; important for content matching and stable, treat as authoritative"auto"— offline-generated byengram summarize-missing; lossy but useful for orientation; always verify against full content before acting on caveats""(empty string) — no summary present
-
summary_model: Name of the model used whensummary_source=auto(e.g.gpt-4o-mini). Set by the server; empty for client-authored or absent summaries.
Updating with a stale summary: If summary_source=client and you change the
memory’s content, you must address the summary: re-send it unchanged, update
it to reflect the new content, or clear it. Failing to address a stale
caller-authored summary causes the update to be rejected.
Discovery fields
Section titled “Discovery fields”Records in the discovery category carry additional fields that are absent (or
zero-valued) on regular memory records.
| Field | JSON key | Type | Required | Description |
|---|---|---|---|---|
| Kind | kind |
string | yes | map (orientation/structure) or fact (pinned checkable claim) |
| Citations | citations |
Citation[] | yes | At least one source anchor; max 50 |
| Summary | summary |
string | no | Short human-readable summary |
Discovery records live in scopes starting with discovery:, typically
discovery:repo:<repo>. They are recalled on demand via search_discovery and
are never returned by list_memory session bootstrap.
Citation fields
Section titled “Citation fields”Each citation anchors a discovery claim to a verifiable source:
| Field | JSON key | Type | Required | Description |
|---|---|---|---|---|
| Kind | kind |
string | yes | file, commit, url, or repo |
| Ref | ref |
string | yes | Path, repo URL, or doc URL |
| Locator | locator |
string | no | E.g. 200-240 line range |
| Pin | pin |
string | no | Aging anchor: commit SHA, content-hash, @rev, or fetched-at |
| Excerpt | excerpt |
string | no | Cached substance from the source; max 16 KiB, soft cap ~50 lines |
Field name notes
Section titled “Field name notes”The serialized JSON keys match the Go struct tags in internal/store/store.go
exactly:
worktree_path(notworktree) — the struct field isWorktree string \json:“worktree_path”``base_dir(notbaseDir) — snake_case throughoutcreated_at— RFC3339 string in the Qdrant payload; deserialized astime.Time
These match the README’s description (repo/workspace/worktree_path/base_dir).
Isolation and ownership
Section titled “Isolation and ownership”actor and owner are always server-set. The actor is extracted from the
token’s UserID (email, username, or subject claim, in priority order). The
owner is the value of the configured owner claim (ENGRAM_OWNER_CLAIM,
default email); it changes only if the chosen claim is not stable across IdP
profile updates (e.g. email changes when the user renames their account; sub
never changes).
When authentication is disabled (no --oidc-issuer), both actor and owner
are empty strings, and all callers share one anonymous bucket.
Pre-isolation records — those written before per-actor ownership was added —
carry no owner key (distinct from an empty-string owner). They are invisible
to every owner-scoped read. See Auth and Isolation for
migration details.