Skip to content

Memory Operations

Memory operations provide the primary interface for storing and retrieving contextual information. The system maintains dual storage: FalkorDB serves as the source of truth for graph data, while Qdrant provides semantic search capabilities.

All operations except /health require authentication via AUTOMEM_API_TOKEN. Authentication tokens can be passed via:

  1. Authorization: Bearer <token> header (recommended)
  2. X-API-Key: <token> header
  3. ?api_key=<token> query parameter
EndpointMethodPurposeAuthentication
/memoryPOSTCreate new memoryAPI Token
/recallGETSearch/retrieve memoriesAPI Token
/memory/<id>PATCHUpdate existing memoryAPI Token
/memory/<id>DELETERemove memoryAPI Token
/memory/by-tagGETFilter by tagsAPI Token

Creates a new memory node in FalkorDB and optionally stores its embedding in Qdrant. The operation executes synchronously for the primary write but queues background enrichment and embedding generation tasks.

Required Fields:

  • content (string): Memory content, minimum 1 character

Optional Fields:

FieldTypeDescription
typestringOne of Decision, Pattern, Preference, Style, Habit, Insight, Context (default: auto-classified)
confidencefloat0.0–1.0, classification confidence (default: 0.9 if type provided)
tagsarrayCategorization tags, supports hierarchical syntax with : or / delimiters
importancefloat0.0–1.0, importance score (default: 0.5)
metadataobjectArbitrary JSON metadata
timestampstringISO 8601 timestamp (default: current UTC time)
embeddingarray768-dimensional vector (auto-generated if omitted)
idstringCustom UUID (auto-generated if omitted)
t_valid, t_invalidstringTemporal validity bounds
updated_at, last_accessedstringTracking timestamps

Memory Data Model:

graph LR
    subgraph "Request Schema"
        Content["content<br/>string (required)<br/>Memory text"]
        Type["type<br/>string (optional)<br/>Decision/Pattern/etc"]
        Tags["tags<br/>string[] (optional)<br/>Categorization"]
        Importance["importance<br/>float (0-1)<br/>Priority score"]
        Metadata["metadata<br/>object (optional)<br/>Custom fields"]
        Embedding["embedding<br/>float[] (optional)<br/>Pre-computed vector"]
        Timestamp["timestamp<br/>ISO8601 (optional)<br/>Defaults to now"]
    end

    subgraph "Stored Properties"
        ID["id<br/>UUID<br/>Auto-generated"]
        TagPrefixes["tag_prefixes<br/>string[]<br/>Auto-computed"]
        Confidence["confidence<br/>float (0-1)<br/>Type confidence"]
        Enriched["enriched<br/>boolean<br/>Processing status"]
        LastAccessed["last_accessed<br/>ISO8601<br/>Access tracking"]
        UpdatedAt["updated_at<br/>ISO8601<br/>Modification time"]
    end

    Content --> ID
    Type --> Confidence
    Tags --> TagPrefixes
    Timestamp --> UpdatedAt
    Embedding --> ID
Terminal window
curl -X POST https://your-automem-instance/memory \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"content": "Chose PostgreSQL over MongoDB. Need ACID guarantees for transactions. Impact: ensures data consistency.",
"type": "Decision",
"tags": ["project-alpha", "database", "architecture"],
"importance": 0.9,
"metadata": {
"files_modified": ["db/config.py"],
"alternatives": ["MongoDB", "MySQL"]
}
}'

The system uses MemoryClassifier to automatically determine memory type when not explicitly provided:

Classification Strategy:

  1. Explicit Type: If type parameter provided, use directly with confidence=0.9
  2. Regex Patterns: Match content against predefined patterns for each memory type (fast, free)
  3. LLM Classification: Use OpenAI GPT-4o-mini as fallback for complex content
  4. Default: Assign Context type with low confidence (0.3) if all methods fail

Memory Type Reference:

TypeTypical ImportanceUse Cases
Decision0.9–1.0Architecture choices, library selections, pattern decisions
Pattern0.7–0.9Code patterns, architectural patterns, reusable solutions
Insight0.7–0.9Root cause discoveries, realizations, aha moments
Preference0.6–0.9Style choices, tool preferences, workflow preferences
Style0.6–0.8Coding conventions, formatting rules
Habit0.5–0.7Development workflows, testing practices
Context0.5–0.7Feature descriptions, project context, miscellaneous (default)
sequenceDiagram
    participant Client
    participant POST_memory as "/memory endpoint"
    participant Classifier as "MemoryClassifier"
    participant Graph as "state.memory_graph<br/>(FalkorDB)"
    participant EnrichQ as "state.enrichment_queue"
    participant EmbedQ as "state.embedding_queue"
    participant Qdrant as "state.qdrant<br/>(QdrantClient)"

    Client->>POST_memory: POST /memory<br/>{content, type?, tags, importance}

    alt Type Not Provided
        POST_memory->>Classifier: classify(content)
        Classifier-->>POST_memory: (type, confidence)
    end

    POST_memory->>POST_memory: _normalize_tag_list(tags)
    POST_memory->>POST_memory: _compute_tag_prefixes(tags)
    POST_memory->>POST_memory: _normalize_timestamp(timestamp)

    POST_memory->>Graph: MERGE Memory node<br/>(id, content, type, tags, importance,<br/>timestamp, metadata, confidence)
    Graph-->>POST_memory: Node created

    POST_memory->>EnrichQ: enqueue_enrichment(memory_id)

    alt Embedding Provided
        POST_memory->>Qdrant: upsert(id, embedding, payload)
        Qdrant-->>POST_memory: Stored
    else No Embedding
        POST_memory->>EmbedQ: Queue for generation
    end

    POST_memory-->>Client: 201 Created<br/>{memory_id, type, confidence,<br/>enrichment: "queued"}

Processing Steps:

  1. Validation: Extract and validate required fields, normalize tags and timestamps
  2. Classification: Determine memory type if not provided (regex → LLM → default)
  3. Tag Processing: Compute hierarchical tag prefixes for efficient filtering
  4. Graph Write: Execute MERGE operation in FalkorDB (immediate, blocking)
  5. Enrichment Queue: Add to background queue for entity extraction and relationship building
  6. Embedding Handling: Store provided embedding or queue for generation
  7. Response: Return immediately with memory ID and enrichment status

Tags support hierarchical structure using : or / delimiters. The system computes all prefixes for efficient filtering. For example, a tag of slack:channel:general generates prefixes: slack, slack:channel, and slack:channel:general.

This enables prefix matching queries like tags=slack to match slack:channel:general, slack:user:U123, etc.

Implementation functions:

  • _normalize_tag_list(): Parse comma-separated or array tags
  • _expand_tag_prefixes(): Split on : or / and generate cumulative prefixes
  • _compute_tag_prefixes(): Deduplicate and lowercase all prefixes

Tagging Conventions (from platform templates):

Memory TypeTag PatternExample
Project Decision[project, platform, date, decision]["ecommerce", "cursor", "2025-01", "decision"]
Bug Fix[project, platform, date, bug-fix, component]["api-gateway", "codex", "2025-01", "bug-fix", "auth"]
Code Pattern[project, platform, date, pattern, component]["frontend", "cursor", "2025-01", "pattern", "react"]
User Preference[preference, platform, date, domain]["preference", "cursor", "2025-01", "code-style"]
Personal Note[personal, date, category]["personal", "2025-01", "health"]

The MCP store_memory tool enforces a two-tier content size system:

Limit TypeThresholdBehavior
Target150–300 charsIdeal size for semantic search quality
Soft Limit500 charsWarning issued; backend may auto-summarize
Hard Limit2000 charsRejected immediately with error

When content exceeds the soft limit, the backend AutoMem service may automatically summarize it using an LLM. The response then includes:

  • summarized: true — Flag indicating summarization occurred
  • original_length: number — Original content length
  • summarized_length: number — Post-summarization length
RangeCategoryExamples
0.9–1.0CriticalUser preferences, major architecture decisions, breaking changes, corrections to AI outputs
0.7–0.9ImportantPatterns discovered, bug fixes with root cause, significant features
0.5–0.7StandardMinor decisions, helpful context, tool selections, configuration notes
0.3–0.5MinorSmall fixes, temporary workarounds, low-impact notes
0.0–0.3LowTrivial changes (avoid storing these)
{
"memory_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"type": "Decision",
"confidence": 0.9,
"enrichment": "queued",
"embedding": "queued"
}

When using AutoMem via MCP, the store_memory tool corresponds to POST /memory:

Required Parameters:

  • content (string): The memory content. Must be under 2000 characters (hard limit).

Optional Parameters:

ParameterTypeDefaultDescription
tagsstring[][]Tags for categorization and filtering
importancenumber (0.0–1.0)0.5Importance score affecting recall ranking
embeddingnumber[]auto-generated768-dimensional vector for semantic search
metadataobject{}Structured metadata (files modified, error signatures, etc.)
timestampstring (ISO 8601)now()When the memory was created

MCP example:

{
"content": "Login failing on special characters. Root: missing input sanitization. Added validator. Files: auth/login.ts",
"tags": ["auth", "bug-fix", "2025-01"],
"importance": 0.8,
"metadata": {
"files_modified": ["auth/login.ts", "auth/validator.ts"],
"error_signature": "ValidationError: special_chars",
"solution_pattern": "input-sanitization"
}
}

Best practices for content:

✅ "Chose PostgreSQL over MongoDB. Need ACID guarantees for transactions. Impact: ensures data consistency."
✅ "Login failing on special characters. Root: missing input sanitization. Added validator. Files: auth/login.ts"
✅ "Using early returns for validation. Reduces nesting, improves readability. Applied in all API routes."
❌ "Fixed typo" (too trivial, no context)
❌ "Changed config" (what config? why?)
❌ "[DECISION] Chose PostgreSQL..." (type prefix redundant, use type field instead)
❌ "[3000 character essay...]" (exceeds hard limit)

When to store:

  • User corrections to AI outputs (importance: 0.9)
  • Architectural decisions with rationale (importance: 0.9)
  • Bug fixes with root cause (importance: 0.7–0.8)
  • Patterns discovered during work (importance: 0.7–0.9)

Never store:

  • Trivial edits (typos, formatting, simple renames)
  • Already well-documented information
  • Temporary file contents or debug output
  • Sensitive credentials or API keys

Client retry logic:

  • Network errors: Retried up to 3 times (500ms, 1s, 2s delays)
  • 5xx server errors: Retried up to 3 times
  • 4xx client errors: Not retried (auth/validation issues)
  • Timeout: 25 seconds (to fit within Claude Desktop’s 30s MCP timeout)

Updates an existing memory node in FalkorDB and synchronizes changes to Qdrant. Content changes trigger automatic re-embedding.

Updatable Fields:

FieldNotes
contentTriggers re-embedding if changed
tagsRecomputes tag_prefixes automatically
importance, confidence, typeUpdate directly
metadataMerged with existing metadata (not replaced)
t_valid, t_invalidUpdate temporal bounds

Non-updatable Fields:

FieldReason
idImmutable identifier
timestampPreserved original creation time
updated_atAuto-set to current UTC time
sequenceDiagram
    participant Client
    participant PATCH_endpoint as "PATCH /memory/:id"
    participant Graph as "state.memory_graph"
    participant EmbedQ as "state.embedding_queue"
    participant Qdrant as "state.qdrant"

    Client->>PATCH_endpoint: PATCH /memory/:id<br/>{content?, tags?, importance?}

    PATCH_endpoint->>Graph: MATCH (m:Memory {id: $id})<br/>RETURN m
    Graph-->>PATCH_endpoint: Existing node or null

    alt Memory Not Found
        PATCH_endpoint-->>Client: 404 Not Found
    end

    PATCH_endpoint->>PATCH_endpoint: Validate update fields
    PATCH_endpoint->>PATCH_endpoint: _compute_tag_prefixes(tags)

    PATCH_endpoint->>Graph: MATCH (m:Memory {id: $id})<br/>SET m.content = $content,<br/>m.tags = $tags,<br/>m.tag_prefixes = $prefixes,<br/>m.updated_at = $now
    Graph-->>PATCH_endpoint: Updated

    alt Content Changed
        PATCH_endpoint->>EmbedQ: Queue re-embedding
    end

    alt Qdrant Available
        PATCH_endpoint->>Qdrant: set_payload(id, updated_fields)
        Qdrant-->>PATCH_endpoint: Payload updated
    end

    PATCH_endpoint->>Graph: MATCH (m:Memory {id: $id})<br/>RETURN m
    Graph-->>PATCH_endpoint: Refreshed node

    PATCH_endpoint-->>Client: 200 OK<br/>{status: "success", memory: {...}}

Update process:

  1. Validation: Verify memory exists (404 if not found)
  2. Field Processing: Normalize tags, compute prefixes, validate types
  3. Graph Update: Execute Cypher SET operation with changed fields
  4. Re-embedding: Queue if content changed
  5. Qdrant Sync: Update payload fields (non-blocking failure)
  6. Refresh: Fetch updated node and return to client

The metadata field uses merge semantics, not replacement. Given existing metadata {"key1": "val1"} and an update with {"key2": "val2"}, the result is {"key1": "val1", "key2": "val2"}.

To remove a metadata field, explicitly set it to null.

Terminal window
curl -X PATCH https://your-automem-instance/memory/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
-H "Authorization: Bearer YOUR_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"importance": 0.95,
"tags": ["project-alpha", "database", "architecture", "reviewed"],
"metadata": {
"reviewed_at": "2025-02-01T10:00:00Z"
}
}'
{
"status": "success",
"memory": {
"id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"content": "Chose PostgreSQL over MongoDB...",
"type": "Decision",
"tags": ["project-alpha", "database", "architecture", "reviewed"],
"importance": 0.95,
"updated_at": "2025-02-01T10:00:00Z"
}
}

The update_memory MCP tool corresponds to PATCH /memory/:id.

Input Schema:

ParameterTypeRequiredConstraintsDescription
memory_idstringYesID of memory to update
contentstringNoNew content (replaces existing)
tagsarray[string]NoNew tags (replaces existing)
importancenumberNo0–1New importance score
metadataobjectNoMetadata (merged with existing)
timestampstringNoISO formatOverride creation timestamp
updated_atstringNoISO formatExplicit update timestamp
last_accessedstringNoISO formatLast access timestamp
typestringNoMemory type classification
confidencenumberNo0–1Confidence score

Removes a memory from both FalkorDB and Qdrant. The operation deletes the node, all its relationships, and the corresponding vector embedding.

No request body is required.

sequenceDiagram
    participant Client
    participant DELETE_endpoint as "DELETE /memory/:id"
    participant Graph as "state.memory_graph"
    participant Qdrant as "state.qdrant"

    Client->>DELETE_endpoint: DELETE /memory/:id

    DELETE_endpoint->>Graph: MATCH (m:Memory {id: $id})<br/>DETACH DELETE m
    Note over Graph: Deletes node + all relationships
    Graph-->>DELETE_endpoint: Deleted

    alt Qdrant Available
        DELETE_endpoint->>Qdrant: delete(collection_name,<br/>points_selector=PointIdsList(<br/>points=[id]))
        Qdrant-->>DELETE_endpoint: Vector deleted
    else Qdrant Unavailable
        Note over DELETE_endpoint: Continue without error
    end

    DELETE_endpoint-->>Client: 200 OK<br/>{status: "success",<br/>message: "Memory deleted"}

Deletion process:

  1. Graph Deletion: Execute Cypher DETACH DELETE to remove node and relationships
  2. Vector Deletion: Remove embedding from Qdrant (non-blocking failure)
  3. Response: Confirm deletion success

The DETACH DELETE clause ensures all incoming and outgoing relationships are automatically removed, preventing orphaned edges.

Terminal window
curl -X DELETE https://your-automem-instance/memory/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \
-H "Authorization: Bearer YOUR_TOKEN"
{
"status": "success",
"message": "Memory a1b2c3d4-e5f6-7890-abcd-ef1234567890 deleted"
}

The delete_memory MCP tool corresponds to DELETE /memory/:id.

ParameterTypeRequiredDescription
memory_idstringYesID of memory to delete

The tool is annotated destructiveHint: true and idempotentHint: true — calling it multiple times with the same ID is safe.


Retrieves memories filtered by tags, ordered by importance and recency. More performant than /recall when only tag filtering is needed.

ParameterTypeDescriptionDefault
tagsstring[]Tag filters (multiple values supported)Required
limitintegerMax results (1–100)50
Terminal window
# Filter by single tag
curl "https://your-automem-instance/memory/by-tag?tags=project-alpha" \
-H "Authorization: Bearer YOUR_TOKEN"
# Filter by multiple tags (any match)
curl "https://your-automem-instance/memory/by-tag?tags=project-alpha&tags=database&limit=20" \
-H "Authorization: Bearer YOUR_TOKEN"

Query Strategy:

  1. Vector-First: If Qdrant available, use scroll() with tag filter
  2. Graph Fallback: Query FalkorDB if Qdrant unavailable or returns no results
  3. Ordering: Sort by importance DESC, timestamp DESC
  4. Relations: Fetch connected memories for context
  5. Format: Return in same format as /recall for consistency

When using FalkorDB, the query leverages tag arrays with direct index usage on the tags property — no keyword extraction or scoring required, making it more efficient than /recall for tag-only filtering.

The score field in the response reflects the memory’s importance when filtering by tags only.


All endpoints follow consistent error formatting:

{
"error": "Description of what went wrong",
"field": "field_name"
}

Validation errors include specific field names and expected formats to aid debugging.

Status CodeMeaning
400 Bad RequestInvalid or missing required fields
401 UnauthorizedMissing or invalid API token
404 Not FoundMemory ID does not exist
503 Service UnavailableFalkorDB unavailable

  • Batching: Embeddings queue for batch generation (20 items or 2s timeout)
  • Async Processing: POST returns immediately, embedding happens in background
  • Fallback: System generates placeholder vectors if OpenAI unavailable

The RECALL_RELATION_LIMIT constant (default: 5) caps the number of relationships fetched per memory to prevent performance degradation. For memories with many relationships, only the most relevant are returned.

Hierarchical tags precompute all prefixes and store them in tag_prefixes array for O(1) filtering. This enables efficient prefix queries without runtime string operations.


After storing certain memory types, create associations to build the knowledge graph:

After StoringSearch ForAssociation Type
User correctionWhat’s being correctedINVALIDATED_BY
Bug fixOriginal bug discoveryDERIVED_FROM
DecisionAlternatives consideredPREFERS_OVER
EvolutionSuperseded knowledgeEVOLVED_INTO

See Relationship Operations for details on creating associations.