Agent Memory

Writing memory

Store decisions, corrections, preferences and other durable facts, with deduplication, idempotent retries and content safety checks.

When information comes up that should persist (a decision, a correction, a violation, an approved solution, an important file, a person's preference), you write it to memory. Agent Memory stores the text as is; it does not reinterpret it with an LLM at write time.

Endpoints

SurfaceCall
RESTPOST /v1/memory/append
MCPadd_memory
Node / Pythonmemory.add(content, {...}) / memory.add(content, ...)
.NETAppendAsync

Example

curl -s -X POST $API/v1/memory/append \
  -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' \
  -H 'Idempotency-Key: billing-decision-7' \
  -d "{
    \"workspaceId\": \"$WS\",
    \"runId\": \"billing-refactor-12\",
    \"layer\": \"Workspace\",
    \"type\": \"decision\",
    \"content\": \"Invoice numbers are generated with a year prefix, sequentially per tenant\",
    \"tags\": {\"facet\": \"billing\"},
    \"sourceKind\": \"agent\",
    \"sourceRef\": \"PR-482\"
  }"
# {"id":"…","merged":false,"contentReplaced":false,"operationId":"…"}

Fields

FieldRequiredDescription
workspaceIdyesTarget workspace. A value other than your key's workspace returns 404.
runIdyesTask/session ID. Use the same value for every write in the same task.
layerin practice, yesWorkspace is durable. Session writes only to the run layer (until consolidation). If omitted, it defaults to Working and the memory is not persisted.
typeyesdecision, correction, violation, approved_pattern, artifact_ref, preference, raw.
contentyesThe information itself. A single, self-contained statement improves search.
applicationIdnoApplication-specific memory. If omitted, it is written to the workspace's shared pool.
tagsnoFree-form key: value pairs. Search can filter on them by exact match. The facet tag has special meaning (see below). Platform-reserved tags (origin_entry_id, episode_id, promoted_from_run, belief) cannot be sent.
summarynoShort summary.
userIdnoThe end user the memory is about. Requires the act for users permission.
visibilitynoworkspace (default), private, agent, user, tenant. tenant requires the promote permission.
classificationnopublic, internal (default), confidential, restricted. Stored and returned; not currently used in access decisions.
sourceKindnoWhere the information came from: agent (default), user, document, import. system and derived are reserved for the platform.
sourceRefnoFree text pointing to the source (PR number, document path, ticket ID). Not validated.
createdAtnoEvent time (default: now). For backdated imports. The recency score is computed from it.
observedAt, validFrom, validTonoWhen the information was observed, and its validity interval. See Time, provenance and explainability.

MCP add_memory accepts most of the same fields (content, type, runId, visibility, userId, facet, sourceKind, sourceRef, observedAt, validFrom, validTo, idempotencyKey) and additionally accepts supersedes: the new memory is written and the given old memory is immediately treated as superseded by it. MCP always writes to the Workspace layer.

Response

FieldMeaning
idID of the live memory. If a merge happened, this is the ID of the existing memory.
mergedNo new memory was created; it was merged into an existing one.
contentReplacedDuring the merge, the content was replaced with the new text (if the new information is more current).
operationIdIngestion receipt. Track it with GET /v1/memory/operations/{operationId}?workspaceId=…. Session layer writes do not produce a receipt.

Duplicates and merging

Every Workspace write is checked for duplicates within the same type and facet:

  • Identical content within the last hour → no new memory is created; the existing memory's "mention" count increases.
  • Semantically very close content, or content with high word overlap → merged into the existing memory; its evidence count and stability increase.
  • Memories with a different visibility, owner, end user or application are never merged.

When every row must stay separate, such as in bulk imports, duplicate checking can be turned off in settings (dedup.enabled, see Configuration).

Safe retries: Idempotency-Key

To safely repeat the same request after a network error, send an Idempotency-Key header (1–128 characters). The same request with the same key within 24 hours returns the original response again (Idempotency-Replayed: true). Using the same key with a different body returns 409 IDEMPOTENCY_CONFLICT. The header also works on update, delete, share and consolidation calls. In MCP, use the idempotencyKey parameter.

Content safety

  • Content that resembles prompt-injection patterns is quarantined: the memory is stored but does not appear in search or in reads by ID. Someone with the review permission (curate) can release or reject it with POST /v1/memory/{id}/review.
  • If personal data is detected (pattern-based: email, delimited phone numbers, Luhn-validated card numbers, mod-97-validated IBANs, Turkish national ID numbers, US SSNs), the memory gets a pii tag. The memory is not rejected and the content is stored; it is not made a tenant-wide rule candidate, and the relevant parts are masked in exports and webhook summaries. This is not model-based DLP; it does not catch personal data outside these patterns.

Turning raw conversation text into memory

No extraction happens at write time. To extract information from conversation lines:

  1. Write the lines with layer: "Session", type: "raw" under the same runId.
  2. Call POST /v1/memory/consolidate; optionally steer what gets extracted with extractionInstructions.
curl -s -X POST $API/v1/memory/append -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' \
  -d "{\"workspaceId\":\"$WS\",\"runId\":\"chat-301\",\"layer\":\"Session\",\"type\":\"raw\",
       \"sourceKind\":\"user\",\"content\":\"user: I want the reports as PDF every Monday, not Excel.\"}"

curl -s -X POST $API/v1/memory/consolidate -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' \
  -d "{\"workspaceId\":\"$WS\",\"runId\":\"chat-301\",
       \"extractionInstructions\":\"Extract only reporting and communication preferences.\"}"
# {"status":"consolidated"}

If no LLM is configured, extraction is rule-based (the text is split into clauses; instructions are ignored). Details: Consolidation, episodes and procedures.

  • One memory = one piece of information. The form "We chose X because Y" works well for both search and contradiction detection.
  • Choose the right type; consolidation, contradiction rules and procedure learning all work by type.
  • If a piece of information replaces an older one, pass supersedes in MCP; don't expect the system to infer it from text similarity.
  • Write person-specific information with userId, and notes that belong only to the agent itself with visibility: "private".

On this page