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:
Authorization: Bearer <token>header (recommended)X-API-Key: <token>header?api_key=<token>query parameter
Available Endpoints
Section titled “Available Endpoints”| Endpoint | Method | Purpose | Authentication |
|---|---|---|---|
/memory | POST | Create new memory | API Token |
/recall | GET | Search/retrieve memories | API Token |
/memory/<id> | PATCH | Update existing memory | API Token |
/memory/<id> | DELETE | Remove memory | API Token |
/memory/by-tag | GET | Filter by tags | API Token |
POST /memory — Creating Memories
Section titled “POST /memory — Creating Memories”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.
Request Format
Section titled “Request Format”Required Fields:
content(string): Memory content, minimum 1 character
Optional Fields:
| Field | Type | Description |
|---|---|---|
type | string | One of Decision, Pattern, Preference, Style, Habit, Insight, Context (default: auto-classified) |
confidence | float | 0.0–1.0, classification confidence (default: 0.9 if type provided) |
tags | array | Categorization tags, supports hierarchical syntax with : or / delimiters |
importance | float | 0.0–1.0, importance score (default: 0.5) |
metadata | object | Arbitrary JSON metadata |
timestamp | string | ISO 8601 timestamp (default: current UTC time) |
embedding | array | 768-dimensional vector (auto-generated if omitted) |
id | string | Custom UUID (auto-generated if omitted) |
t_valid, t_invalid | string | Temporal validity bounds |
updated_at, last_accessed | string | Tracking 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
Example Request
Section titled “Example Request”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"] } }'Memory Type Classification
Section titled “Memory Type Classification”The system uses MemoryClassifier to automatically determine memory type when not explicitly provided:
Classification Strategy:
- Explicit Type: If
typeparameter provided, use directly withconfidence=0.9 - Regex Patterns: Match content against predefined patterns for each memory type (fast, free)
- LLM Classification: Use OpenAI GPT-4o-mini as fallback for complex content
- Default: Assign
Contexttype with low confidence (0.3) if all methods fail
Memory Type Reference:
| Type | Typical Importance | Use Cases |
|---|---|---|
Decision | 0.9–1.0 | Architecture choices, library selections, pattern decisions |
Pattern | 0.7–0.9 | Code patterns, architectural patterns, reusable solutions |
Insight | 0.7–0.9 | Root cause discoveries, realizations, aha moments |
Preference | 0.6–0.9 | Style choices, tool preferences, workflow preferences |
Style | 0.6–0.8 | Coding conventions, formatting rules |
Habit | 0.5–0.7 | Development workflows, testing practices |
Context | 0.5–0.7 | Feature descriptions, project context, miscellaneous (default) |
Data Flow
Section titled “Data Flow”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:
- Validation: Extract and validate required fields, normalize tags and timestamps
- Classification: Determine memory type if not provided (regex → LLM → default)
- Tag Processing: Compute hierarchical tag prefixes for efficient filtering
- Graph Write: Execute
MERGEoperation in FalkorDB (immediate, blocking) - Enrichment Queue: Add to background queue for entity extraction and relationship building
- Embedding Handling: Store provided embedding or queue for generation
- Response: Return immediately with memory ID and enrichment status
Tag Processing
Section titled “Tag Processing”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 Type | Tag Pattern | Example |
|---|---|---|
| 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"] |
Content Size Governance
Section titled “Content Size Governance”The MCP store_memory tool enforces a two-tier content size system:
| Limit Type | Threshold | Behavior |
|---|---|---|
| Target | 150–300 chars | Ideal size for semantic search quality |
| Soft Limit | 500 chars | Warning issued; backend may auto-summarize |
| Hard Limit | 2000 chars | Rejected 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 occurredoriginal_length: number— Original content lengthsummarized_length: number— Post-summarization length
Importance Scoring Guidelines
Section titled “Importance Scoring Guidelines”| Range | Category | Examples |
|---|---|---|
| 0.9–1.0 | Critical | User preferences, major architecture decisions, breaking changes, corrections to AI outputs |
| 0.7–0.9 | Important | Patterns discovered, bug fixes with root cause, significant features |
| 0.5–0.7 | Standard | Minor decisions, helpful context, tool selections, configuration notes |
| 0.3–0.5 | Minor | Small fixes, temporary workarounds, low-impact notes |
| 0.0–0.3 | Low | Trivial changes (avoid storing these) |
Success Response (201 Created)
Section titled “Success Response (201 Created)”{ "memory_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890", "type": "Decision", "confidence": 0.9, "enrichment": "queued", "embedding": "queued"}MCP Tool: store_memory
Section titled “MCP Tool: store_memory”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:
| Parameter | Type | Default | Description |
|---|---|---|---|
tags | string[] | [] | Tags for categorization and filtering |
importance | number (0.0–1.0) | 0.5 | Importance score affecting recall ranking |
embedding | number[] | auto-generated | 768-dimensional vector for semantic search |
metadata | object | {} | Structured metadata (files modified, error signatures, etc.) |
timestamp | string (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)
PATCH /memory/:id — Updating Memories
Section titled “PATCH /memory/:id — Updating Memories”Updates an existing memory node in FalkorDB and synchronizes changes to Qdrant. Content changes trigger automatic re-embedding.
Request Format
Section titled “Request Format”Updatable Fields:
| Field | Notes |
|---|---|
content | Triggers re-embedding if changed |
tags | Recomputes tag_prefixes automatically |
importance, confidence, type | Update directly |
metadata | Merged with existing metadata (not replaced) |
t_valid, t_invalid | Update temporal bounds |
Non-updatable Fields:
| Field | Reason |
|---|---|
id | Immutable identifier |
timestamp | Preserved original creation time |
updated_at | Auto-set to current UTC time |
Update Data Flow
Section titled “Update Data Flow”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:
- Validation: Verify memory exists (404 if not found)
- Field Processing: Normalize tags, compute prefixes, validate types
- Graph Update: Execute Cypher
SEToperation with changed fields - Re-embedding: Queue if
contentchanged - Qdrant Sync: Update payload fields (non-blocking failure)
- Refresh: Fetch updated node and return to client
Metadata Merge Behavior
Section titled “Metadata Merge Behavior”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.
Example Request
Section titled “Example Request”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" } }'Success Response (200 OK)
Section titled “Success Response (200 OK)”{ "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" }}MCP Tool: update_memory
Section titled “MCP Tool: update_memory”The update_memory MCP tool corresponds to PATCH /memory/:id.
Input Schema:
| Parameter | Type | Required | Constraints | Description |
|---|---|---|---|---|
memory_id | string | Yes | — | ID of memory to update |
content | string | No | — | New content (replaces existing) |
tags | array[string] | No | — | New tags (replaces existing) |
importance | number | No | 0–1 | New importance score |
metadata | object | No | — | Metadata (merged with existing) |
timestamp | string | No | ISO format | Override creation timestamp |
updated_at | string | No | ISO format | Explicit update timestamp |
last_accessed | string | No | ISO format | Last access timestamp |
type | string | No | — | Memory type classification |
confidence | number | No | 0–1 | Confidence score |
DELETE /memory/:id — Deleting Memories
Section titled “DELETE /memory/:id — Deleting Memories”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.
Deletion Data Flow
Section titled “Deletion Data Flow”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:
- Graph Deletion: Execute Cypher
DETACH DELETEto remove node and relationships - Vector Deletion: Remove embedding from Qdrant (non-blocking failure)
- Response: Confirm deletion success
The DETACH DELETE clause ensures all incoming and outgoing relationships are automatically removed, preventing orphaned edges.
Example Request
Section titled “Example Request”curl -X DELETE https://your-automem-instance/memory/a1b2c3d4-e5f6-7890-abcd-ef1234567890 \ -H "Authorization: Bearer YOUR_TOKEN"Success Response (200 OK)
Section titled “Success Response (200 OK)”{ "status": "success", "message": "Memory a1b2c3d4-e5f6-7890-abcd-ef1234567890 deleted"}MCP Tool: delete_memory
Section titled “MCP Tool: delete_memory”The delete_memory MCP tool corresponds to DELETE /memory/:id.
| Parameter | Type | Required | Description |
|---|---|---|---|
memory_id | string | Yes | ID of memory to delete |
The tool is annotated destructiveHint: true and idempotentHint: true — calling it multiple times with the same ID is safe.
GET /memory/by-tag — Querying by Tags
Section titled “GET /memory/by-tag — Querying by Tags”Retrieves memories filtered by tags, ordered by importance and recency. More performant than /recall when only tag filtering is needed.
Query Parameters
Section titled “Query Parameters”| Parameter | Type | Description | Default |
|---|---|---|---|
tags | string[] | Tag filters (multiple values supported) | Required |
limit | integer | Max results (1–100) | 50 |
Example Requests
Section titled “Example Requests”# Filter by single tagcurl "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"Implementation
Section titled “Implementation”Query Strategy:
- Vector-First: If Qdrant available, use
scroll()with tag filter - Graph Fallback: Query FalkorDB if Qdrant unavailable or returns no results
- Ordering: Sort by
importance DESC, timestamp DESC - Relations: Fetch connected memories for context
- Format: Return in same format as
/recallfor 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.
Error Responses
Section titled “Error Responses”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 Code | Meaning |
|---|---|
| 400 Bad Request | Invalid or missing required fields |
| 401 Unauthorized | Missing or invalid API token |
| 404 Not Found | Memory ID does not exist |
| 503 Service Unavailable | FalkorDB unavailable |
Performance Considerations
Section titled “Performance Considerations”Embedding Generation
Section titled “Embedding Generation”- 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
Relationship Limits
Section titled “Relationship Limits”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.
Tag Prefix Optimization
Section titled “Tag Prefix Optimization”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.
Post-Storage: Creating Associations
Section titled “Post-Storage: Creating Associations”After storing certain memory types, create associations to build the knowledge graph:
| After Storing | Search For | Association Type |
|---|---|---|
| User correction | What’s being corrected | INVALIDATED_BY |
| Bug fix | Original bug discovery | DERIVED_FROM |
| Decision | Alternatives considered | PREFERS_OVER |
| Evolution | Superseded knowledge | EVOLVED_INTO |
See Relationship Operations for details on creating associations.