Install any skill in seconds. Free to start, no credit card required.
Get Started Free →Use when writing a mem0 memory retrieval call with the Python SDK (search / get_all): emit mem0's own filter grammar — bare AND/OR/NOT logical keys, bare in/gte/lte/gt/lt/contains/icontains/ne operators (no MongoDB $ prefixes), snake_case user_id/agent_id/app_id/run_id scopes, the "*" any-non-null wildcard, and top_k/threshold search args — which cheaper models replace with MongoDB syntax by default.
.claude/skills/mem0-filter-syntax/SKILL.md| Model | Eval pass | Runs |
|---|---|---|
| gemini-3.6-flash | 50% | 2 |
| Model | Lift | Δ tokens | Δ turns | Cases | Verified |
|---|---|---|---|---|---|
| gemini-3.6-flashbest | +55% | +109% | 0% | 22 | 54d ago |
| gemini-3.5-flash | pending re-run | — | |||
| Test case | Without → With | Effect | Δ tokens | Δ turns |
|---|---|---|---|---|
| case-18 | ✗→✓ | ▲ Improved | — | — |
| case-12 | ✗→✓ | ▲ Improved | — | — |
| case-07 | ✗→✓ | ▲ Improved | — | — |
| case-05 | ✗→✓ | ▲ Improved | — | — |
| case-06 | ✗→✓ | ▲ Improved | — | — |
When you call the mem0 Python SDK (MemoryClient / Memory) to search or get_all memories, emit mem0's OWN filter grammar — never MongoDB / Mongoose syntax. Apply whenever you build a filters= object or pick the search arguments.
client.search(query, filters=..., top_k=..., threshold=..., rerank=...).query — the natural-language semantic query string.filters — the filter object (see rule 3+).top_k — max results (NOT limit, k, n, max_results, count, or size).threshold — minimum semantic score, a float (default 0.1); pass 0.0 to disable scorefiltering. NOT min_score, min_relevance, score, or cutoff.
rerank — a boolean; turns on the managed reranker. NOT use_rerank, reorder, rerankers.client.get_all(filters=...) (NOT list, all,get_memories).
user_id, agent_id, app_id, run_id — snake_case, never camelCase (userId, agentId) and never id / application_id / session_id. Every filter must carry at least one entity id. A bare {"user_id": "alice"} is equality shorthand.
$. Combine conditions with AND, OR,NOT (never $and / $or / $not, never lowercase and / or).
AND — value is a JSON array of condition objects (all must match).OR — value is a JSON array of condition objects (any match).NOT — value is a single condition object (must not match).AND array may contain an OR object and vice-versa.$. Nest an operator object on a field:in — membership in a list: {"categories": {"in": ["finance", "health"]}} (NOT $in).gte / lte / gt / lt — numeric/date range (NOT $gte etc.).contains — case-SENSITIVE substring.icontains — case-INSENSITIVE substring (this is the ONLY case-insensitive form — NOT$regex, regex, like, ilike).
ne — not-equal (NOT $ne, neq, !=)."*". e.g. {"run_id": "*"} matchesrecords where run_id is present. NEVER $exists, {"ne": null}, or a boolean-exists form.
{"metadata": {"type": "decision"}} — never a dotted "metadata.type" key. Metadata does NOT support range operators (gte/lte) — only bare equality, contains, and ne.
created_at / updated_at with gte/lte/gt/lt, e.g.{"created_at": {"gte": "2024-01-01T00:00:00Z"}}.
Simple scoped search — base reaches for a flat call + limit:
# BEFORE (base default) # AFTER (mem0)
m.search("payment retries", m.search("payment retries",
user_id="u_42", limit=5) filters={"user_id": "u_42"}, top_k=5)Compound AND with metadata — base reaches for MongoDB $and + dotted key:
# BEFORE filters={"$and": [{"user_id": "u_42"}, {"metadata.kind": "note"}]}
# AFTER filters={"AND": [{"user_id": "u_42"}, {"metadata": {"kind": "note"}}]}Case-insensitive substring — base reaches for $regex:
# BEFORE {"summary": {"$regex": "timeout", "$options": "i"}}
# AFTER {"summary": {"icontains": "timeout"}}Membership + wildcard + date — base reaches for $in / $exists / $gte:
# BEFORE {"$and": [{"labels": {"$in": ["a","b"]}}, {"run_id": {"$exists": true}},
# {"created_at": {"$gte": "2025-01-01T00:00:00Z"}}]}
# AFTER {"AND": [{"labels": {"in": ["a","b"]}}, {"run_id": "*"},
# {"created_at": {"gte": "2025-01-01T00:00:00Z"}}]}Negation — base reaches for $not / $ne:
# BEFORE {"$and": [{"user_id": "u_42"}, {"tier": {"$ne": "trial"}}]}
# AFTER {"AND": [{"user_id": "u_42"}, {"NOT": {"tier": "trial"}}]}user_id / agent_id / app_id / run_id scope.
value to a top-level field or filter it after retrieval.
get_all paginates with page / page_size; search caps with top_k. Don't put top_kon get_all or page on search.
threshold=0.0 returns everything above score 0 (filtering effectively off), not "top 0".AND / OR / NOT. DON'T use $and / $or / $not.in / gte / icontains / ne. DON'T prefix operators with $.icontains for case-insensitive match. DON'T use $regex / like."*" for any-non-null. DON'T use $exists / {"ne": null}.top_k and threshold. DON'T use limit / k / min_score.{"metadata": {...}}. DON'T use dotted "metadata.key".$and, $or, $gte, $lte, $in, $ne, $regex, $exists, $options.limit= / k= / n= instead of top_k=; min_score= instead of threshold=.userId / agentId / appId (camelCase) in the Python SDK."metadata.type") instead of the {"metadata": {...}} sub-object.contains when case-insensitivity is required (that needs icontains).{"run_id": {"$exists": true}} instead of {"run_id": "*"}.AND / OR / NOT (arrays for AND/OR, object for NOT).$-prefixed operator anywhere.in / gte / lte / gt / lt / contains / icontains / ne.user_id / agent_id / app_id / run_id)."*"; metadata is a sub-object (eq/contains/ne only); dates are ISO-8601.top_k; min score is threshold; reranker is rerank.| Case | Status | Duration (ms) | Turns | Tokens | Tool calls | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| Without | With | Δ | Without | With | Δ | Without | With | Δ | Without | With | Δ | ||
case-18 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-12 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-15 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-07 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-08 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-01 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-17 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-05 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-19 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-06 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-11 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-22 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-10 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-21 | pass→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-16 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-02 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-14 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-04 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-20 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-03 | fail→fail | — | — | — | — | — | — | — | — | — | — | — | — |
case-09 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
case-13 | fail→pass | — | — | — | — | — | — | — | — | — | — | — | — |
DecimalAI ran this skill against gemini-3.6-flash twice over the same eval suite — once with the skill loaded and once without — and compared the two runs case by case. 22 cases were attempted. The headline lift of +55 percentage points is the difference between those two pass rates over the 22 comparable cases.
The per-case answers from this run were removed by the retention sweep, so the case table below shows the verdicts without the text either arm produced. The counts above were recorded at the time and are unaffected. Answers are now kept for 180 days.
| Model | Method | Date | Lift |
|---|---|---|---|
| gemini-3.5-flash | verified | 7/9/2026 | +96% |
Other measured skills in the registry, with their headline benchmark lift.