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
| Surface | Call |
|---|---|
| REST | POST /v1/memory/append |
| MCP | add_memory |
| Node / Python | memory.add(content, {...}) / memory.add(content, ...) |
| .NET | AppendAsync |
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
| Field | Required | Description |
|---|---|---|
workspaceId | yes | Target workspace. A value other than your key's workspace returns 404. |
runId | yes | Task/session ID. Use the same value for every write in the same task. |
layer | in practice, yes | Workspace is durable. Session writes only to the run layer (until consolidation). If omitted, it defaults to Working and the memory is not persisted. |
type | yes | decision, correction, violation, approved_pattern, artifact_ref, preference, raw. |
content | yes | The information itself. A single, self-contained statement improves search. |
applicationId | no | Application-specific memory. If omitted, it is written to the workspace's shared pool. |
tags | no | Free-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. |
summary | no | Short summary. |
userId | no | The end user the memory is about. Requires the act for users permission. |
visibility | no | workspace (default), private, agent, user, tenant. tenant requires the promote permission. |
classification | no | public, internal (default), confidential, restricted. Stored and returned; not currently used in access decisions. |
sourceKind | no | Where the information came from: agent (default), user, document, import. system and derived are reserved for the platform. |
sourceRef | no | Free text pointing to the source (PR number, document path, ticket ID). Not validated. |
createdAt | no | Event time (default: now). For backdated imports. The recency score is computed from it. |
observedAt, validFrom, validTo | no | When 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
| Field | Meaning |
|---|---|
id | ID of the live memory. If a merge happened, this is the ID of the existing memory. |
merged | No new memory was created; it was merged into an existing one. |
contentReplaced | During the merge, the content was replaced with the new text (if the new information is more current). |
operationId | Ingestion 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
releaseorrejectit withPOST /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
piitag. 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:
- Write the lines with
layer: "Session",type: "raw"under the samerunId. - Call
POST /v1/memory/consolidate; optionally steer what gets extracted withextractionInstructions.
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.
Recommended writing habits
- 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
supersedesin 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 withvisibility: "private".