diff --git a/docs/api-reference/memory/add-memories.mdx b/docs/api-reference/memory/add-memories.mdx
index ae95f1c20..70bae11fe 100644
--- a/docs/api-reference/memory/add-memories.mdx
+++ b/docs/api-reference/memory/add-memories.mdx
@@ -3,10 +3,96 @@ title: 'Add Memories'
openapi: post /v1/memories/
---
-## Graph Memory
+Add new facts, messages, or metadata to a user’s memory store. The Add Memories endpoint accepts either raw text or conversational turns and commits them asynchronously so the memory is ready for later search, retrieval, and graph queries.
-To enable graph-based memory relationships, pass the `enable_graph=True` parameter. This creates relationships between entities in your memories for more contextual retrieval.
+## Endpoint
-
-Learn more in the [Graph Memory documentation](/platform/features/graph-memory).
-
\ No newline at end of file
+- **Method**: `POST`
+- **URL**: `/v1/memories/`
+- **Content-Type**: `application/json`
+
+Memories are processed asynchronously by default. The response contains queued events you can track while the platform finalizes enrichment.
+
+## Required headers
+
+| Header | Required | Description |
+| --- | --- | --- |
+| `Authorization: Bearer ` | Yes | API key scoped to your workspace. |
+| `Accept: application/json` | Yes | Ensures a JSON response. |
+
+## Request body
+
+Provide at least one message or direct memory string. Most callers supply `messages` so Mem0 can infer structured memories as part of ingestion.
+
+
+```json Basic request
+{
+ "user_id": "alice",
+ "messages": [
+ { "role": "user", "content": "I moved to Austin last month." }
+ ],
+ "metadata": {
+ "source": "onboarding_form"
+ }
+}
+```
+
+
+### Common fields
+
+| Field | Type | Required | Description |
+| --- | --- | --- | --- |
+| `user_id` | string | No* | Associates the memory with a user. Provide when you want the memory scoped to a specific identity. |
+| `messages` | array | No* | Conversation turns for Mem0 to infer memories from. Each object should include `role` and `content`. |
+| `memory` | string | No* | Direct memory text when you do not need inference. |
+| `metadata` | object | Optional | Custom key/value metadata (e.g., `{"topic": "preferences"}`). |
+| `infer` | boolean (default `true`) | Optional | Set to `false` to skip inference and store the provided text as-is. |
+| `async_mode` | boolean (default `true`) | Optional | Controls asynchronous processing. Most clients leave this enabled. |
+| `output_format` | string (default `v1.1`) | Optional | Response format. `v1.1` wraps results in a `results` array. |
+
+> \* Provide either `messages` or `memory` to describe what you are storing. For scoped memories, include `user_id`. You can also attach `agent_id`, `app_id`, `run_id`, `project_id`, or `org_id` to refine ownership.
+
+## Response
+
+Successful requests return an array of events queued for processing. Each event includes the generated memory text and an identifier you can persist for auditing.
+
+
+```json 200 response
+[
+ {
+ "id": "mem_01JF8ZS4Y0R0SPM13R5R6H32CJ",
+ "event": "ADD",
+ "data": {
+ "memory": "The user moved to Austin in 2025."
+ }
+ }
+]
+```
+
+```json 400 response
+{
+ "error": "400 Bad Request",
+ "details": {
+ "message": "Invalid input data. Please refer to the memory creation documentation at https://docs.mem0.ai/platform/quickstart#4-1-create-memories for correct formatting and required fields."
+ }
+}
+```
+
+
+## Graph relationships
+
+Add Memories can enrich the knowledge graph on write. Set `enable_graph: true` to create entity nodes and relationships for the stored memory. Use this when you want downstream `get_all` or search calls to traverse connected entities.
+
+
+```json Graph-aware request
+{
+ "user_id": "alice",
+ "messages": [
+ { "role": "user", "content": "I met with Dr. Lee at General Hospital." }
+ ],
+ "enable_graph": true
+}
+```
+
+
+The response follows the same format, and related entities become available in [Graph Memory](/platform/features/graph-memory) queries.
diff --git a/docs/cookbooks/essentials/building-ai-companion.mdx b/docs/cookbooks/essentials/building-ai-companion.mdx
index 6cbaf0e12..bcaaada17 100644
--- a/docs/cookbooks/essentials/building-ai-companion.mdx
+++ b/docs/cookbooks/essentials/building-ai-companion.mdx
@@ -164,7 +164,7 @@ Ray can plan workouts that avoid aggravating Max's knee, without pulling in race
Run the basic loop for a week and check what's stored:
```python
-memories = mem0_client.get_all(user_id="max")
+memories = mem0_client.get_all(filters={"AND": [{"user_id": "max"}]})
print([m["memory"] for m in memories["results"]])
# Output: ["Max wants to run marathon under 4 hours", "hey", "lol ok", "cool thanks", "gtg bye"]
@@ -202,7 +202,7 @@ Now chat again:
chat("hey how's it going", user_id="max")
chat("I prefer trail running over roads", user_id="max")
-memories = mem0_client.get_all(user_id="max")
+memories = mem0_client.get_all(filters={"AND": [{"user_id": "max"}]})
print([m["memory"] for m in memories["results"]])
# Output: ["Max wants to run marathon under 4 hours", "Max prefers trail running over roads"]
@@ -411,7 +411,7 @@ Max changes his goal from sub-4 to sub-3:45:
```python
# Find the old memory
-memories = mem0_client.get_all(user_id="max")
+memories = mem0_client.get_all(filters={"AND": [{"user_id": "max"}]})
goal_memory = [m for m in memories["results"] if "sub-4" in m["memory"]][0]
# Update it
diff --git a/docs/cookbooks/integrations/agents-sdk-tool.mdx b/docs/cookbooks/integrations/agents-sdk-tool.mdx
index 91c8f210b..29b8c5db8 100644
--- a/docs/cookbooks/integrations/agents-sdk-tool.mdx
+++ b/docs/cookbooks/integrations/agents-sdk-tool.mdx
@@ -126,7 +126,7 @@ async def get_all_memory(
) -> str:
"""Retrieve all memories from Mem0"""
user_id = context.context.user_id or "default_user"
- memories = await client.get_all(user_id=user_id)
+ memories = await client.get_all(filters={"AND": [{"user_id": user_id}]})
results = '\n'.join([result["memory"] for result in memories["results"]])
return str(results)
```
diff --git a/docs/platform/features/async-client.mdx b/docs/platform/features/async-client.mdx
index cd5fbdc6a..14f34dfeb 100644
--- a/docs/platform/features/async-client.mdx
+++ b/docs/platform/features/async-client.mdx
@@ -75,14 +75,18 @@ await client.search("What is Alice's favorite sport?", { user_id: "alice" });
Retrieve all memories for a user asynchronously.
+
+`get_all()` now requires filters to be specified.
+
+
```python Python
-await client.get_all(user_id="alice")
+await client.get_all(filters={"AND": [{"user_id": "alice"}]})
```
```javascript JavaScript
-await client.getAll({ user_id: "alice" });
+await client.getAll({ filters: {"AND": [{"user_id": "alice"}]} });
```
diff --git a/docs/platform/features/async-mode-default-change.mdx b/docs/platform/features/async-mode-default-change.mdx
index 28a7dc490..d7a7da93e 100644
--- a/docs/platform/features/async-mode-default-change.mdx
+++ b/docs/platform/features/async-mode-default-change.mdx
@@ -161,12 +161,14 @@ You can also retrieve all processed memories at any time:
```python Python
# Retrieve all memories for a user
-memories = client.get_all(user_id="user-123")
+# Note: get_all now requires filters
+memories = client.get_all(filters={"AND": [{"user_id": "user-123"}]})
```
```javascript JavaScript
// Retrieve all memories for a user
-const memories = await client.getAll({ user_id: "user-123" });
+// Note: getAll now requires filters
+const memories = await client.getAll({ filters: {"AND": [{"user_id": "user-123"}]} });
```
diff --git a/docs/platform/features/custom-instructions.mdx b/docs/platform/features/custom-instructions.mdx
index 3c80ac8cf..6d6bae3c5 100644
--- a/docs/platform/features/custom-instructions.mdx
+++ b/docs/platform/features/custom-instructions.mdx
@@ -302,7 +302,7 @@ messages = [
# Add the messages and check extracted memories
result = client.add(messages, user_id="test_user")
-memories = client.get_all(user_id="test_user")
+memories = client.get_all(filters={"AND": [{"user_id": "test_user"}]})
# Review if the right information was extracted
for memory in memories:
diff --git a/docs/platform/features/direct-import.mdx b/docs/platform/features/direct-import.mdx
index 5217b473f..0e1cb5391 100644
--- a/docs/platform/features/direct-import.mdx
+++ b/docs/platform/features/direct-import.mdx
@@ -67,10 +67,14 @@ client.search("What is Alice's favorite sport?", user_id="alice")
You can retrieve all memories using the `get_all` method.
+
+`get_all()` now requires filters to be specified.
+
+
```python Python
-client.get_all(query="What is Alice's favorite sport?", user_id="alice")
+client.get_all(filters={"AND": [{"user_id": "alice"}]})
```
```json Output
diff --git a/docs/platform/features/graph-memory.mdx b/docs/platform/features/graph-memory.mdx
index 64579df9f..4a7e4dcc6 100644
--- a/docs/platform/features/graph-memory.mdx
+++ b/docs/platform/features/graph-memory.mdx
@@ -187,12 +187,16 @@ console.log(results);
When retrieving all memories, Graph Memory provides additional relationship context:
+
+`get_all()` now requires filters to be specified.
+
+
```python Python
# Get all memories with graph context
memories = client.get_all(
- user_id="joseph",
+ filters={"AND": [{"user_id": "joseph"}]},
enable_graph=True
)
@@ -202,7 +206,7 @@ print(memories)
```javascript JavaScript
// Get all memories with graph context
const memories = await client.getAll({
- user_id: "joseph",
+ filters: {"AND": [{"user_id": "joseph"}]},
enable_graph: true
});
diff --git a/docs/platform/features/v2-memory-filters.mdx b/docs/platform/features/v2-memory-filters.mdx
index d4fc204eb..b74757adf 100644
--- a/docs/platform/features/v2-memory-filters.mdx
+++ b/docs/platform/features/v2-memory-filters.mdx
@@ -1,515 +1,416 @@
---
-title: Memory Filters v2
-description: This guide covers the filtering system for retrieving and searching memories. You can filter by user sessions, agents, applications, content categories, and time ranges.
+title: Memory Filters
+description: Query and retrieve memories with powerful filtering capabilities. Filter by users, agents, content, time ranges, and more.
---
-## Quick Start
+> Memory filters provide a flexible way to query and retrieve specific memories from your memory store. You can filter by users, agents, content categories, time ranges, and combine multiple conditions using logical operators.
-### Memories for a specific user
+## When to use filters
-```json
+When working with large-scale memory stores, you need precise control over which memories to retrieve. Filters help you:
+
+* **Isolate user data**: Retrieve memories for specific users while maintaining privacy
+* **Debug and audit**: Export specific memory subsets for analysis
+* **Target content**: Find memories with specific categories or metadata
+* **Time-based queries**: Retrieve memories within specific date ranges
+* **Performance optimization**: Reduce query complexity by pre-filtering
+
+
+Filters were introduced in v1.0.0 to provide precise control over memory retrieval.
+
+
+## Filter structure
+
+Filters use a nested JSON structure with logical operators at the root:
+
+```python
+# Basic structure
{
- "AND": [
- { "user_id": "u1" }
- ]
+ "AND": [ # or "OR", "NOT"
+ { "field": "value" },
+ { "field": { "operator": "value" } }
+ ]
}
```
-### User memories across all runs
-
-```json
-{
- "AND": [
- { "user_id": "u1" },
- { "run_id": "*" }
- ]
-}
-```
-
-
-Excludes null run_id values
-
-
-
----
-
-## Filter Structure
-
-* Root must be **`AND`** or **`OR`** (or **`NOT`**) containing an **array** of conditions.
-* A **condition** is either a simple equality `{ "user_id": "u1" }` or an operator clause `{ "created_at": { "gte": "..." } }`.
-
-```json
-{
- "AND": [
- { "user_id": "u1" },
- { "run_id": "*" },
- { "created_at": { "lt": "2025-06-01T00:00:00Z" } },
- { "categories": { "in": ["finance", "health"] } }
- ]
-}
-```
-
-**Accepted shapes**
-
-```json
-{ "AND": [ /* conditions... */ ] }
-{ "OR": [ /* conditions... */ ] }
-{ "NOT": [ /* conditions... */ ] }
-```
-
----
-
-## Available Fields
-
-Use these to scope memories to primary entities:
-
-| Field | Meaning |
-| ---------- | ----------------------- |
-| `user_id` | Filter by user/consumer |
-| `agent_id` | Filter by AI agent |
-| `app_id` | Filter by application |
-| `run_id` | Filter by session/run |
-
----
-
-## Wildcards
-
-Wildcards (`"*"`) match **any non-null** value of that field. This means if a field is null, it won't be included in the results.
-
-
-Asterisks (`*`) exclude null values - only non-null fields will be matched
-
-
-```json
-{ "AND": [ { "user_id": "*" } ] } // any record with a user_id
-{ "AND": [ { "user_id": "*" }, { "run_id": "*" } ] } // require both non-null
-{ "OR": [ { "user_id": "*" }, { "run_id": "*" } ] } // either non-null
-```
-
----
-
-## Operators and Fields
-
-**Available Fields**
-
-* **Entities**: `user_id`, `agent_id`, `app_id`, `run_id`
-* **Time**: `created_at`, `updated_at`, `timestamp`
-* **Content**: `categories`, `metadata`, `keywords`
-* **Special**: `memory_ids` (array of IDs)
-
-**Operators**
-
-* `in`: Matches any of the values specified
-* `gte`: Greater than or equal to
-* `lte`: Less than or equal to
-* `gt`: Greater than
-* `lt`: Less than
-* `ne`: Not equal to
-* `contains`: Case-sensitive containment check
-* `icontains`: Case-insensitive containment check
-* `*`: Wildcard character that matches everything
-
-**Field Structures**
-
-```json
-// Entity fields
-{ "user_id": "u1" }
-{ "agent_id": "a1" }
-{ "app_id": "app1" }
-{ "run_id": "run1" }
-
-// Time fields
-{ "created_at": { "gte": "2025-01-01T00:00:00Z" } }
-{ "updated_at": { "lt": "2025-02-01T00:00:00Z" } }
-
-// Categories (exact matching)
-{ "categories": { "in": ["personal_information", "finance"] } }
-// Categories (partial matching)
-{ "categories": { "contains": "finance" } }
-
-// Metadata (exact key-value match)
-{ "metadata": { "key": "value" } }
-
-// Keywords (text search)
-{ "keywords": { "icontains": "budget" } }
-
-// Memory IDs
-{ "memory_ids": ["m1", "m2", "m3"] }
-```
-
-**Notes**
-
-* `eq` is implied: `{ "user_id": "u1" }` ≡ `{ "user_id": { "eq": "u1" } }`
-* `ne` includes **NULLs**: results where the field is either **not equal** or **missing**
-* For `categories`, use `contains` for partial matching or `in` for exact matching
-
----
-
-## Examples
-
-### User and Agent Filters
-
-**All memories for a specific user**
-
-```json
-{ "AND": [ { "user_id": "u1" } ] }
-```
-
-**All memories across all users (no agent/app/run)**
-
-```json
-{ "AND": [ { "user_id": "*" } ] }
-```
-
-
-Excludes null user_id values
-
-
-**User memories across all runs**
-
-```json
-{ "AND": [ { "user_id": "u1" }, { "run_id": "*" } ] }
-```
-
-
-Excludes null run_id values
-
-
-**All memories for a specific agent**
-
-```json
-{ "AND": [ { "agent_id": "a1" } ] }
-```
-
-**Agent memories across all runs**
-
-```json
-{ "AND": [ { "agent_id": "a1" }, { "run_id": "*" } ] }
-```
-
-
-Excludes null run_id values
-
-
-### Content and Text Filters
-
-**Search for text in user's memory content (case-insensitive)**
-
-```json
-{ "AND": [
- { "user_id": "u1" },
- { "keywords": { "icontains": "pizza" } }
-] }
-```
-
-**Search for text in user's memory content (case-sensitive)**
-
-```json
-{ "AND": [
- { "user_id": "u1" },
- { "keywords": { "contains": "BudgetQ1" } }
-] }
-```
-
-**User memories with specific categories**
-
-```json
-{ "AND": [
- { "user_id": "u1" },
- { "categories": { "in": ["finance", "health"] } }
-] }
-```
-
-**User memories with specific metadata**
-
-```json
-{ "AND": [
- { "user_id": "u1" },
- { "metadata": { "foo": "bar" } }
-] }
-```
-
-### Time-based Filters
-
-**Memories created after a specific date**
-
-```json
-{ "AND": [
- { "user_id": "u1" },
- { "created_at": { "gt": "2025-01-01T00:00:00Z" } }
-] }
-```
-
-**User memories within a date range**
-
-```json
-{ "AND": [
- { "user_id": "u1" },
- { "created_at": { "gte": "2025-01-01T00:00:00Z" } },
- { "created_at": { "lt": "2025-02-01T00:00:00Z" } }
-] }
-```
-
-**Memories updated within a time window**
-
-```json
-{ "AND": [
- { "user_id": "u1" },
- { "updated_at": { "gte": "2025-05-01T00:00:00Z" } },
- { "updated_at": { "lte": "2025-05-31T23:59:59Z" } }
-] }
-```
-
-### Advanced Filters
-
-**Memories from multiple users**
-
-```json
-{ "AND": [ { "user_id": { "in": ["u1", "u2", "u3"] } } ] }
-```
-
-
-**Memories from either user or run**
-
-```json
-{ "OR": [ { "user_id": "u1" }, { "run_id": "run1" } ] }
-```
-
-**Memories that have both user and run (non-null)**
-
-```json
-{ "AND": [ { "user_id": "*" }, { "run_id": "*" } ] }
-```
-
-
-Excludes null user_id and run_id values
-
-
-**User memories excluding specific categories**
-
-```json
-{ "AND": [
- { "user_id": "u1" },
- { "NOT": { "categories": { "in": ["spam", "test"] } } }
-] }
-```
-
-**User memories by specific IDs**
-
-```json
-{ "AND": [
- { "user_id": "u1" },
- { "memory_ids": ["m1", "m2", "m3"] }
-] }
-```
-
-**Complex filter: text + category + time**
-
-```json
-{ "AND": [
- { "user_id": "u1" },
- { "keywords": { "icontains": "invoice" } },
- { "categories": { "in": ["finance"] } },
- { "created_at": { "gte": "2025-03-01T00:00:00Z" } }
-] }
-```
-
-### Comprehensive Filters
-
-**All memories with non-null entities**
-
-```json
-{ "AND": [
- { "user_id": "*" },
- { "agent_id": "*" },
- { "run_id": "*" },
- { "app_id": "*" }
-] }
-```
-
-
-Excludes null values for all entity fields
-
-
-**All memories (including null entities)**
-
-```json
-{ "OR": [
- { "user_id": "*" },
- { "agent_id": "*" },
- { "run_id": "*" },
- { "app_id": "*" }
-] }
-```
-
----
-
-## Common Patterns
-
-**Single user memories**
-
-```json
-{ "AND": [ { "user_id": "u1" } ] }
-```
-
-**User memories across all runs**
-
-```json
-{ "AND": [ { "user_id": "u1" }, { "run_id": "*" } ] }
-```
-
-
-Excludes null run_id values
-
-
-**All user memories (no agent/app/run)**
-
-```json
-{ "AND": [ { "user_id": "*" } ] }
-```
-
-
-Excludes null user_id values
-
-
-**Agent with specific users**
-
-```json
-{ "AND": [ { "agent_id": "a1" }, { "user_id": { "in": ["u1", "u2"] } } ] }
-```
-
-**Search user's memory content (case-insensitive)**
-
-```json
-{ "AND": [
- { "user_id": "u1" },
- { "keywords": { "icontains": "budget" } }
-] }
-```
-
-**Memories within date range**
-
-```json
-{ "AND": [
- { "user_id": "u1" },
- { "created_at": { "gte": "" } },
- { "created_at": { "lt": "" } }
-] }
-```
-
-**Exclude specific categories**
-
-```json
-{ "AND": [
- { "user_id": "u1" },
- { "NOT": { "categories": { "in": ["spam", "test"] } } }
-] }
-```
-
-**Get user's specific memories by ID**
-
-```json
-{ "AND": [
- { "user_id": "u1" },
- { "memory_ids": ["id1", "id2"] }
-] }
-```
-
----
+## Available fields and operators
+
+### Entity fields
+| Field | Operators | Example |
+|-------|-----------|---------|
+| `user_id` | `=`, `!=`, `in`, `*` | `{"user_id": "user_123"}` |
+| `agent_id` | `=`, `!=`, `in`, `*` | `{"agent_id": "*"}` |
+| `app_id` | `=`, `!=`, `in`, `*` | `{"app_id": {"in": ["app1", "app2"]}}` |
+| `run_id` | `=`, `!=`, `in`, `*` | `{"run_id": "*"}` |
+
+### Time fields
+| Field | Operators | Example |
+|-------|-----------|---------|
+| `created_at` | `>`, `>=`, `<`, `<=`, `=`, `!=` | `{"created_at": {"gte": "2024-01-01"}}` |
+| `updated_at` | `>`, `>=`, `<`, `<=`, `=`, `!=` | `{"updated_at": {"lt": "2024-12-31"}}` |
+| `timestamp` | `>`, `>=`, `<`, `<=`, `=`, `!=` | `{"timestamp": {"gt": "2024-01-01"}}` |
+
+### Content fields
+| Field | Operators | Example |
+|-------|-----------|---------|
+| `categories` | `=`, `!=`, `in`, `contains` | `{"categories": {"in": ["finance"]}}` |
+| `metadata` | `=`, `!=` | `{"metadata": {"key": "value"}}` |
+| `keywords` | `contains`, `icontains` | `{"keywords": {"icontains": "invoice"}}` |
+
+### Special fields
+| Field | Operators | Example |
+|-------|-----------|---------|
+| `memory_ids` | `in` | `{"memory_ids": ["id1", "id2"]}` |
+
+
+The `*` wildcard matches any non-null value. Records with null values for that field are excluded.
+
+
+## Common filter patterns
+
+Use these ready-made filters to target typical retrieval scenarios without rebuilding logic from scratch.
+
+
+
+ ```python
+ # Narrow to one user's memories
+ filters = {"AND": [{"user_id": "user_123"}]}
+ memories = client.get_all(filters=filters)
+ ```
+
+
+
+ ```python
+ # Wildcard skips null user_id entries
+ filters = {"AND": [{"user_id": "*"}]}
+ memories = client.get_all(filters=filters)
+ ```
+
+
+
+ ```python
+ # Pair a user filter with a run wildcard
+ filters = {
+ "AND": [
+ {"user_id": "user_123"},
+ {"run_id": "*"}
+ ]
+ }
+ memories = client.get_all(filters=filters)
+ ```
+
+
+
+### Content search
+
+Find memories containing specific text, categories, or metadata values.
+
+
+
+ ```python
+ # Case-insensitive match
+ filters = {
+ "AND": [
+ {"user_id": "user_123"},
+ {"keywords": {"icontains": "pizza"}}
+ ]
+ }
+
+ # Case-sensitive match
+ filters = {
+ "AND": [
+ {"user_id": "user_123"},
+ {"keywords": {"contains": "Invoice_2024"}}
+ ]
+ }
+ ```
+
+
+
+ ```python
+ # Match against category list
+ filters = {
+ "AND": [
+ {"user_id": "user_123"},
+ {"categories": {"in": ["finance", "health"]}}
+ ]
+ }
+
+ # Partial category match
+ filters = {
+ "AND": [
+ {"user_id": "user_123"},
+ {"categories": {"contains": "finance"}}
+ ]
+ }
+ ```
+
+
+
+ ```python
+ # Pin to a metadata attribute
+ filters = {
+ "AND": [
+ {"user_id": "user_123"},
+ {"metadata": {"source": "email"}}
+ ]
+ }
+ ```
+
+
+
+### Time-based filtering
+
+Retrieve memories within specific date ranges using time operators.
+
+
+
+ ```python
+ # Created in January 2024
+ filters = {
+ "AND": [
+ {"user_id": "user_123"},
+ {"created_at": {"gte": "2024-01-01T00:00:00Z"}},
+ {"created_at": {"lt": "2024-02-01T00:00:00Z"}}
+ ]
+ }
+
+ # Updated recently
+ filters = {
+ "AND": [
+ {"user_id": "user_123"},
+ {"updated_at": {"gte": "2024-12-01T00:00:00Z"}}
+ ]
+ }
+ ```
+
+
+
+### Multiple criteria
+
+Combine various filters for complex queries across different dimensions.
+
+
+
+ ```python
+ # Expand scope to a short user list
+ filters = {
+ "AND": [
+ {"user_id": {"in": ["user_1", "user_2", "user_3"]}}
+ ]
+ }
+ ```
+
+
+
+ ```python
+ # Return matches on either condition
+ filters = {
+ "OR": [
+ {"user_id": "user_123"},
+ {"run_id": "run_456"}
+ ]
+ }
+ ```
+
+
+
+ ```python
+ # Wrap negative logic with NOT
+ filters = {
+ "AND": [
+ {"user_id": "user_123"},
+ {"NOT": {
+ "categories": {"in": ["spam", "test"]}
+ }}
+ ]
+ }
+ ```
+
+
+
+ ```python
+ # Fetch a fixed set of memory IDs
+ filters = {
+ "AND": [
+ {"user_id": "user_123"},
+ {"memory_ids": ["mem_1", "mem_2", "mem_3"]}
+ ]
+ }
+ ```
+
+
+
+ ```python
+ # Require every entity field to be non-null
+ filters = {
+ "AND": [
+ {"user_id": "*"},
+ {"agent_id": "*"},
+ {"run_id": "*"},
+ {"app_id": "*"}
+ ]
+ }
+ ```
+
+
+
+## Advanced examples
+
+Level up foundational patterns with compound filters that coordinate entity scope, tighten time windows, and weave in exclusion rules for high-precision retrievals.
+
+
+
+ ```python
+ # Invoice memories in Q1 2024
+ filters = {
+ "AND": [
+ {"user_id": "user_123"},
+ {"keywords": {"icontains": "invoice"}},
+ {"categories": {"in": ["finance"]}},
+ {"created_at": {"gte": "2024-01-01T00:00:00Z"}},
+ {"created_at": {"lt": "2024-04-01T00:00:00Z"}}
+ ]
+ }
+ ```
+
+
+
+ ```python
+ # From specific agent, all users
+ filters = {
+ "AND": [
+ {"agent_id": "finance_bot"},
+ {"user_id": "*"}
+ ]
+ }
+
+ # Any entity populated
+ filters = {
+ "OR": [
+ {"user_id": "*"},
+ {"agent_id": "*"},
+ {"run_id": "*"},
+ {"app_id": "*"}
+ ]
+ }
+ ```
+
+
+
+ ```python
+ # User memories from 2024, excluding spam and test
+ filters = {
+ "AND": [
+ {"user_id": "user_123"},
+ {"created_at": {"gte": "2024-01-01T00:00:00Z"}},
+ {"NOT": {
+ "OR": [
+ {"categories": {"in": ["spam"]}},
+ {"categories": {"in": ["test"]}}
+ ]
+ }}
+ ]
+ }
+ ```
+
+
+
+## Best practices
+
+
+The root must be `AND`, `OR`, or `NOT` with an array of conditions.
+
+
+
+Use `"*"` to match any non-null value for a field.
+
+
+
+When you specify `user_id` only, other entity fields default to null. Use wildcards to include them.
+
## Troubleshooting
-### "I filtered by `user_id`, but I don't see items that have an `agent_id`."
+
+
+ **Problem**: Filtered by `user_id` but don't see agent memories.
-This is the **implicit null-scoping** rule. When you write only `{ "user_id": "u1" }`, the system also enforces `agent_id = NULL`, `run_id = NULL`, `app_id = NULL`. If you want any agent, add `{ "agent_id": "*" }`.
+ **Solution**: Add a wildcard for `agent_id` so non-null entries return:
+ ```python
+ {"AND": [{"user_id": "user_123"}, {"agent_id": "*"}]}
+ ```
+
-```json
-{ "AND": [ { "user_id": "u1" }, { "agent_id": "*" } ] }
-```
+
+ **Problem**: `ne` comparison pulls in records with null values.
-### "My `ne` seems to return more than I expect."
+ **Solution**: Pair `ne` with a wildcard guard:
+ ```python
+ {"AND": [{"agent_id": "*"}, {"agent_id": {"ne": "old_agent"}}]}
+ ```
+
-`ne` returns rows where the field is **not equal OR NULL**. If you need "not equal and **definitely present**", combine with a wildcard.
+
+ **Solution**: Swap to `icontains` to normalize casing.
+
-```json
-{ "AND": [ { "agent_id": "*" }, { "agent_id": { "ne": "a1" } } ] }
-```
+
+ **Solution**: Use `gte` for the start and `lt` for the end boundary:
+ ```python
+ {"AND": [
+ {"created_at": {"gte": "2024-01-01"}},
+ {"created_at": {"lt": "2024-02-01"}}
+ ]}
+ ```
+
-### "Case-insensitive search?"
-
-Use `icontains`.
-
-```json
-{ "AND": [ { "keywords": { "icontains": "receipt" } } ] }
-```
-
-### "Between two dates?"
-
-Use `gte` and `lt` (or `lte`) together.
-
-```json
-{ "AND": [
- { "user_id": "u1" },
- { "created_at": { "gte": "2025-01-01T00:00:00Z" } },
- { "created_at": { "lt": "2025-02-01T00:00:00Z" } }
-] }
-```
-
-### "Complex logic with NOT"
-
-`NOT` can wrap a single condition or an array. Example: user `u1` but not category `spam` or `test`.
-
-```json
-{ "AND": [
- { "user_id": "u1" },
- { "NOT": { "categories": { "in": ["spam", "test"] } } }
-] }
-```
-
-### "Metadata matching isn't working."
-
-Ensure you match the **exact JSON shape** at the top level.
-
-```json
-{ "AND": [ { "metadata": { "foo": "bar" } } ] }
-```
-
-### "I want all users, all agents, all runs."
-
-Be explicit with wildcards for **each** entity dimension.
-
-```json
-{ "AND": [ { "user_id": "*" }, { "agent_id": "*" }, { "run_id": "*" } ] }
-```
-
----
+
+ **Solution**: Match top-level metadata keys exactly:
+ ```python
+ {"metadata": {"source": "email"}}
+ ```
+
+
## FAQ
-**Q: Do I have to wrap my filter in `AND` or `OR`?**
+
+
+ Yes. The root must be a logical operator with an array.
+
-Yes. The root must be one of `AND`, `OR`, or `NOT`.
+
+ Any non-null value. Nulls are excluded.
+
-**Q: What does the wildcard `"*"` match?**
+
+ Unspecified fields default to NULL. Use `"*"` to include non-null values.
+
-Any **non-null** value for that field.
+
+ No. Equality is the default: `{"user_id": "u1"}` works.
+
-**Q: Why are results "missing" unless I add wildcards?**
+
+ Only top-level keys are supported.
+
-Because unspecified entity fields default to **`NULL`** due to restrictive scoping.
+
+ Use `keywords` with `contains` (case-sensitive) or `icontains` (case-insensitive).
+
-**Q: Is `eq` required?**
-
-No—equality is the default. `{ "user_id": "u1" }` is enough.
-
-**Q: Does `ne` include NULLs?**
-
-Yes. Use `{ "field": "*" }` together with `ne` if you need "present and not equal".
-
-**Q: How do I search the memory text?**
-
-Use `keywords` with `contains` or `icontains`.
-
-**Q: Can I filter nested metadata keys?**
-
-Currently target **top-level** keys as shown: `{ "metadata": { "foo": "bar" } }`.
\ No newline at end of file
+
+ ```python
+ {
+ "AND": [
+ {"user_id": "user_123"},
+ {"OR": [
+ {"categories": "finance"},
+ {"categories": "health"}
+ ]}
+ ]
+ }
+ ```
+
+
diff --git a/docs/templates/feature_guide_template.mdx b/docs/templates/feature_guide_template.mdx
index 9ed0a147d..a1644ef66 100644
--- a/docs/templates/feature_guide_template.mdx
+++ b/docs/templates/feature_guide_template.mdx
@@ -119,7 +119,7 @@ Walk through a real request/response. Include sample payloads and highlight nota
## Best practices
- Keep criteria minimal—overfiltering hurts recall.
-- Pair with Memory Filters v2 for hybrid scoring.
+- Pair with Memory Filters for hybrid scoring.
{/* DEBUG: verify CTA targets */}