feat(mem0-plugin): v0.2.5 — fix identity scoping, skill param bugs, add checklists (#5247)

This commit is contained in:
Kartik
2026-05-25 19:21:10 +05:30
committed by GitHub
parent 0da3359a1a
commit f9c52baf21
43 changed files with 970 additions and 439 deletions
+4 -6
View File
@@ -22,12 +22,10 @@ Pre-fetches relevant memories to prime context before working on a task.
| Query angle | Filter | Purpose |
|---|---|---|
| Feature/module name | `{"metadata": {"type": "decision"}}` | Architecture decisions |
| File paths mentioned | `{"metadata": {"type": "convention"}}` | Coding patterns |
| Error keywords (if any) | `{"metadata": {"type": "anti_pattern"}}` | Known pitfalls |
| Broad project context | no metadata filter | Catch-all |
All calls must include `user_id` and `app_id` filters.
| Feature/module name | `{"AND": [{"user_id": "<id>"}, {"app_id": "<pid>"}, {"metadata": {"type": "decision"}}]}` | Architecture decisions |
| File paths mentioned | `{"AND": [{"user_id": "<id>"}, {"app_id": "<pid>"}, {"metadata": {"type": "convention"}}]}` | Coding patterns |
| Error keywords (if any) | `{"AND": [{"user_id": "<id>"}, {"app_id": "<pid>"}, {"metadata": {"type": "anti_pattern"}}]}` | Known pitfalls |
| Broad project context | `{"AND": [{"user_id": "<id>"}, {"app_id": "<pid>"}]}` | Catch-all |
3. **Deduplicate** results by memory ID across all search responses.
+17 -9
View File
@@ -10,7 +10,7 @@ identifies near-duplicates, flags contradictions, and prunes stale entries based
configured retention policies. All proposed changes are shown as a diff for user
approval before anything is modified.
---
**IMPORTANT: Execute steps strictly in order (1 → 2 → 3 → 4 → 5 → 6). Each step depends on the previous one. Do NOT run steps in parallel or skip ahead.**
## Step 1: Load Retention Policies
@@ -99,7 +99,7 @@ confidence.
---
## Step 4: Print Diff Report (item 15)
## Step 4: Print Diff Report
Print a structured diff to the terminal before making any changes. Use exactly
this format:
@@ -159,7 +159,7 @@ For each approved merge pair:
1. `delete_memory(<id1>)`
2. `delete_memory(<id2>)`
3. `add_memory` with:
- `messages=[{"role": "user", "content": "<merged content>"}]`
- `text="<merged content>"`
- `user_id=<active_user_id>`
- `app_id=<active_project_id>` (top-level, not in metadata)
- `metadata={"type": "<original type>", "branch": "<active_branch>", "confidence": <higher of the two original scores>, "source": "mem0-dream"}`
@@ -168,10 +168,7 @@ For each approved merge pair:
#### Contradictions (resolved)
For each resolved conflict where the user chose A or B:
- Identify the loser (the non-chosen memory).
- First call `get_memory(<loser_id>)` to read its current text content.
- Then call `update_memory(<loser_id>, text=<original_text_content>)` to preserve the text while updating it.
- **Important:** `update_memory` requires the `text` parameter. A metadata-only call may error or wipe the content. Always read first, then update with the original text.
- Delete the loser (the non-chosen memory): `delete_memory(memory_id=<loser_id>)`
Contradictions where the user chose `skip` are left untouched.
@@ -200,6 +197,14 @@ When invoked with `--auto` (e.g., `/mem0:dream --auto`), run non-interactively:
- **Prunes**: applied automatically (age/confidence-based, no ambiguity).
- **Contradictions**: skipped — they require human judgment.
### Concurrency guard
Before doing any work, check for a lock file at `/tmp/mem0_dream_auto.lock`:
- If the lock file exists and is less than 10 minutes old, print `[mem0-dream --auto] Another run in progress — skipping.` and stop.
- Otherwise, create the lock file (write the current timestamp). Delete it when done (in all exit paths).
### Execution
In auto mode:
1. Load policies and fetch memories (Steps 1–3) as normal.
2. Apply merges and prunes silently without printing the diff or prompting.
@@ -207,10 +212,13 @@ In auto mode:
```
[mem0-dream --auto] project=<id> merged=<N> pruned=<N> conflicts_skipped=<N>
```
4. If contradictions were detected but skipped, store a reminder memory:
4. If contradictions were detected but skipped, check if a `mem0-dream-auto` reminder already exists before storing one:
- Search for existing reminders: `search_memories(query="mem0-dream contradictions manual review", filters={"AND": [{"user_id": "<active_user_id>"}, {"app_id": "<active_project_id>"}, {"metadata": {"source": "mem0-dream-auto"}}]}, top_k=1)`
- If a result exists with similarity > 0.9, skip storing the reminder (one already exists).
- If no match, store the reminder:
```python
add_memory(
messages=[{"role": "user", "content": "mem0-dream detected <N> contradiction(s) requiring manual review. Run /mem0:dream to resolve them interactively."}],
text="mem0-dream detected <N> contradiction(s) requiring manual review. Run /mem0:dream to resolve them interactively.",
user_id="<active_user_id>",
app_id="<active_project_id>",
metadata={"type": "task_learning", "source": "mem0-dream-auto", "branch": "<active_branch>"},
+1 -2
View File
@@ -18,8 +18,7 @@ Determine the active identity:
### Step 2: Fetch all memories
Call `get_memories` with:
- `user_id=<active_user_id>`
- `app_id=<active_project_id>`
- `filters={"AND": [{"user_id": "<active_user_id>"}, {"app_id": "<active_project_id>"}]}`
- `page_size=200`
If the response is paginated (i.e. the result contains a `next` cursor or the count equals `page_size`), continue fetching pages until all memories are retrieved.
+30 -13
View File
@@ -14,26 +14,38 @@ Run ALL checks, then display a single summary. Do not stop on the first failure.
### Check 1: API key
```bash
echo "${MEM0_API_KEY:-${CLAUDE_PLUGIN_OPTION_MEM0_API_KEY:-NOT_SET}}"
_KEY="${MEM0_API_KEY:-${CLAUDE_PLUGIN_OPTION_MEM0_API_KEY:-}}"
[ -n "$_KEY" ] && echo "${_KEY:0:6}..." || echo "NOT_SET"
```
- If `NOT_SET`: FAIL — "No API key configured"
- If set: PASS — show first 6 chars + `...` (never print the full key)
- If set: PASS — the command already prints only the first 6 chars
### Check 2: Identity resolution
Read the active identity from the SessionStart banner or resolve manually:
- `user_id`: from `MEM0_RESOLVED_USER_ID` or `$USER`
- `project_id`: from `MEM0_PROJECT_ID` or current directory name
- `branch`: from `MEM0_BRANCH` or `git rev-parse --abbrev-ref HEAD`
Resolve identity using the plugin's own resolver scripts to match what hooks use:
```bash
SCRIPT_DIR="${CLAUDE_PLUGIN_ROOT:-${CODEX_PLUGIN_ROOT:-${CURSOR_PLUGIN_ROOT:-}}}/scripts"
source "$SCRIPT_DIR/_identity.sh" 2>/dev/null
echo "user_id=${MEM0_RESOLVED_USER_ID:-}"
echo "project_id=${MEM0_PROJECT_ID:-}"
echo "branch=${MEM0_BRANCH:-}"
```
If `CLAUDE_PLUGIN_ROOT` is not available, fall back to:
- `user_id`: from `MEM0_USER_ID` or `$USER`
- `project_id`: from `MEM0_PROJECT_ID` or check `~/.mem0/project_map.json` for `$PWD`
- `branch`: from `git branch --show-current`
PASS if all three are non-empty. WARN if any falls back to defaults.
### Check 3: MCP server connectivity
Call `search_memories` with:
- `query="health check"`, `user_id=<id>`, `limit=1`
- `filters={"AND": [{"user_id": "<id>"}, {"app_id": "<project_id>"}]}`
- `query="health check"`
- `filters={"AND": [{"user_id": "<active_user_id>"}, {"app_id": "<active_project_id>"}]}`
- `top_k=1`
- If returns successfully (even empty): PASS
- If errors: FAIL — show the error message
@@ -41,12 +53,17 @@ Call `search_memories` with:
### Check 4: Memory write capability
Call `add_memory` with:
- `messages=[{"role": "user", "content": "Health check probe — safe to delete."}]`
- `user_id=<id>`, `app_id=<project_id>`
- `text="Health check probe — safe to delete."`
- `user_id=<active_user_id>`
- `app_id=<active_project_id>`
- `metadata={"type": "health_check", "probe": true}`
- `infer=False`
If it returns a memory ID: PASS — then immediately call `delete_memory` with that ID to clean up.
If it errors: FAIL — show the error.
The response returns `event_id` (v3 writes are async). Call `get_event_status(event_id=<event_id>)` to check processing.
- If status is `SUCCEEDED`: PASS — extract the memory ID from the event result, then call `delete_memory` with that ID to clean up.
- If status is `PENDING` after 5 seconds: PASS (write accepted, processing delayed)
- If errors: FAIL — show the error.
### Check 5: Session stats tracker
@@ -85,7 +102,7 @@ When invoked with `--deep` (e.g., `/mem0:health --deep`), run the standard 5 che
### Quality Check 1: Duplicates
Call `get_memories` with `user_id`, `app_id`, `page_size=200`. Compare all pairs within the same `metadata.type` group for high textual overlap (shared nouns/keywords > 60%). Report:
Call `get_memories` with `filters={"AND": [{"user_id": "<active_user_id>"}, {"app_id": "<active_project_id>"}]}`, `page_size=200`. Compare all pairs within the same `metadata.type` group for high textual overlap (shared nouns/keywords > 60%). Report:
```
Potential duplicates: <N> pairs
+2 -2
View File
@@ -63,7 +63,7 @@ Determine the active identity:
For each record in the parsed JSON array, call `add_memory` with:
- `messages=[{"role": "user", "content": "<record.content>"}]`
- `text="<record.content>"`
- `user_id=<active_user_id>`
- `app_id=<active_project_id>`
- `metadata={`
@@ -156,7 +156,7 @@ detects native auto-memory and the user chooses to import:
2. Split by non-empty lines. Each line becomes one memory.
3. Skip lines shorter than 20 characters or lines that are just headers (`#`).
4. For each line, call `add_memory` with:
- `messages=[{"role": "user", "content": "<line>"}]`
- `text="<line>"`
- `user_id=<active_user_id>`
- `app_id=<active_project_id>`
- `metadata={"type": "task_learning", "source": "memory-md-import", "confidence": 0.8}`
+1 -1
View File
@@ -16,7 +16,7 @@ Audits memory quality for the active project. Finds duplicates, contradictions,
## Steps
1. **Fetch all memories** for active project via `get_memories` with `user_id` and `app_id`. Paginate if needed — cap at 200 memories.
1. **Fetch all memories** for active project via `get_memories` with `filters={"AND": [{"user_id": "<active_user_id>"}, {"app_id": "<active_project_id>"}]}`, `page_size=200`. Paginate if needed — cap at 200 memories.
2. **Group by `metadata.type`**. Common types: `decision`, `convention`, `anti_pattern`, `task_learning`, `project_profile`, `user_preference`, `session_state`.
+65 -28
View File
@@ -7,6 +7,8 @@ description: Sets up mem0 for a new project including API key configuration, MCP
Run this wizard to set up the mem0 plugin for the current project. Complete in ~60 seconds.
**IMPORTANT: Execute steps strictly in order (0 → 1 → 2 → 3 → 4 → 5 → 6). Each step depends on the previous one. Do NOT run steps in parallel or skip ahead. Complete one step fully before starting the next.**
## Step 0: Ensure mem0ai SDK is installed
The plugin installs the `mem0ai` Python SDK automatically on session start via a venv in `${CLAUDE_PLUGIN_DATA}/venv`. If Step 5 (categories) fails with an import error, run:
@@ -22,10 +24,12 @@ This is silent and idempotent — safe to run anytime.
Check if `MEM0_API_KEY` is already set by running:
```bash
echo $MEM0_API_KEY
[ -n "$MEM0_API_KEY" ] && echo "SET" || echo "NOT_SET"
```
### If API key IS set (non-empty output)
IMPORTANT: Never run `echo $MEM0_API_KEY` — that prints the secret in plaintext to the conversation log.
### If API key IS set (output is "SET")
Print: `- API key found.` and proceed to Step 2.
@@ -46,15 +50,18 @@ Step 1: Setting up API key.
source ~/.zshrc
3. Verify:
echo $MEM0_API_KEY
# Should print your key
[ -n "$MEM0_API_KEY" ] && echo "SET" || echo "NOT_SET"
```
After the user confirms they've set the key, verify it by running `echo $MEM0_API_KEY`. If still empty, repeat the instructions. If set, proceed to Step 2.
After the user confirms they've set the key, verify it by running `[ -n "$MEM0_API_KEY" ] && echo "SET" || echo "NOT_SET"`. If NOT_SET, repeat the instructions. If SET, proceed to Step 2.
## Step 2: MCP OAuth login
## Step 2: MCP server connection
Now authenticate the MCP server connection. Tell the user:
First, check if MCP tools are already available using ToolSearch with query `"mem0 search_memories"`. The exact tool name varies by install method (may be `mcp__mem0__search_memories` or `mcp__plugin_mem0_mem0__search_memories`).
**If MCP tools ARE found:** Print `- MCP already connected.` and proceed to Step 3.
**If MCP tools are NOT found:** Guide the user through OAuth:
```
Step 2: MCP OAuth login.
@@ -65,7 +72,7 @@ Step 2: MCP OAuth login.
4. Return here after authenticating in your browser
```
After the user completes OAuth, verify MCP tools are available using ToolSearch with query `"mem0 search_memories"`. The exact tool name varies by install method (may be `mcp__mem0__search_memories` or `mcp__plugin_mem0_mem0__search_memories`).
After the user completes OAuth, verify MCP tools again using ToolSearch.
- If MCP tools found: Print `- MCP connected.` and proceed to Step 3.
- If NOT found: Troubleshoot before giving up:
@@ -77,7 +84,7 @@ After the user completes OAuth, verify MCP tools are available using ToolSearch
## Step 3: Verify connectivity and show identity
Call `search_memories` with `query="project setup"`, `user_id=<active_user_id>`, `filters={"AND": [{"user_id": "<active_user_id>"}, {"app_id": "<active_project_id>"}]}`, `limit=1` to verify connectivity.
Call `search_memories` with `query="project setup"`, `filters={"AND": [{"user_id": "<active_user_id>"}, {"app_id": "<active_project_id>"}]}`, `top_k=1` to verify connectivity.
Print:
```
@@ -89,29 +96,54 @@ Print:
If the search fails, troubleshoot the API key and MCP connection.
## Step 4: Detect and import project files
## Step 4: Import project files
Check for these files in the project root:
1. `CLAUDE.md`
2. `AGENTS.md`
3. `.cursorrules`
4. `.windsurfrules`
5. `mem0.md`
Project files (CLAUDE.md, AGENTS.md, etc.) are automatically imported into mem0 when a session starts. This step verifies import status and triggers a re-import if needed.
For each file found, ask the user: "Found `<filename>` (<size> bytes). Import into mem0? [Y/n]"
### 4a: Detect project files
If user says yes (or default):
- Read the file content
- Call `add_memory` with:
- `messages=[{"role": "user", "content": "## Project Profile: <filename>\n\nProject: <project_id>\n\n<file_content>"}]`
- `user_id=<active_user_id>`
- `app_id=<active_project_id>`
- `metadata={"type": "project_profile", "file": "<filename>", "source": "onboard", "branch": "<active_branch>"}`
- `infer=False`
- The response contains `event_id` (writes are async). Do not block on each — continue importing. The summary reflects files submitted, not confirmed processed.
```bash
for f in CLAUDE.md AGENTS.md .cursorrules .windsurfrules mem0.md; do
[ -f "$f" ] && echo "FOUND: $f ($(wc -c < "$f") bytes)"
done || true
```
If no files found, print `- No project files found. Skipping import.` and proceed to Step 5.
### 4b: Check and import
Run auto_import in foreground to check status and import if needed:
```bash
MEM0_DEBUG=1 MEM0_CWD="$PWD" python3 "${CLAUDE_PLUGIN_ROOT}/scripts/auto_import.py"
```
### 4c: Report to user
Parse the auto_import output and print a user-friendly summary:
- If output contains `Imported` lines:
```
- Importing project files into mem0... done.
<N> file(s) imported (<M> chunks). These are stored verbatim for future context.
```
- If output contains only `skipping` lines:
```
- Project files already in mem0 (imported during session start). Verified server-side.
```
- If output contains `re-importing`:
```
- Project files were missing from mem0. Re-imported successfully.
```
- If output contains errors or no files were processed:
```
- Project file import failed. Check API key and retry with: /mem0:onboard
```
## Step 5: Install coding categories
The setup script is idempotent — it compares existing categories against the proposed set and skips the API call if they already match (tolerates order differences and extra API fields). Safe to re-run.
Ask: "Install coding categories optimized for development workflows? [Y/n]"
If yes, run the setup script using the plugin's venv python:
@@ -125,6 +157,11 @@ else
fi
```
Parse the output:
- `"Categories already match -- skipping update."` → Print: `- Coding categories already installed. Skipped.`
- `"Done."` → Print: `- Coding categories installed (<N> categories).`
- Error → Print the error and suggest re-running `/mem0:onboard`.
If the script fails with "mem0ai SDK not found", run the dependency installer first:
```bash
"${CLAUDE_PLUGIN_ROOT}/scripts/ensure_deps.sh"
@@ -138,8 +175,8 @@ Print a summary:
- Onboarding complete.
user_id: <user_id>
project_id: <project_id> (app_id)
imported: <N> files
categories: <installed or skipped>
files: <N> found, <M> imported
categories: <N installed | already installed | skipped by user>
Memory is now active for this project. Start working — mem0 will
automatically search relevant context and capture learnings.
+14 -13
View File
@@ -29,20 +29,21 @@ Call `get_memory` with the selected memory ID. Store:
### Step 3: Pin it
Call `update_memory` with:
- `memory_id=<selected_id>`
- `text=<original_text>` (preserve existing content)
- `metadata=` merge `original_metadata` with `{"pinned": true}`
The MCP `update_memory` tool only accepts `memory_id`, `text`, and `source` — it
does not accept a `metadata` parameter. To pin, append a pin marker to the text:
```python
updated_meta = {**original_metadata, "pinned": True}
update_memory(memory_id=<selected_id>, text=<original_text>, metadata=updated_meta)
pinned_text = "[PINNED] " + original_text if not original_text.startswith("[PINNED]") else original_text
update_memory(memory_id=<selected_id>, text=pinned_text)
```
**Important:** `update_memory` requires the `text` parameter. Passing only metadata may error or wipe content.
**For new memories** (user wants to pin text that isn't stored yet):
1. Call `add_memory` with the text + `metadata={"pinned": true, "type": "decision", "confidence": 1.0}`
1. Call `add_memory` with:
- `text="[PINNED] <the user's text>"`
- `user_id=<active_user_id>`
- `app_id=<active_project_id>`
- `metadata={"pinned": true, "type": "decision", "confidence": 1.0}`
- `infer=False`
2. The response contains `event_id`. Call `get_event_status(event_id=<event_id>)` once to retrieve the memory ID, then confirm.
### Step 4: Confirm
@@ -57,10 +58,10 @@ Append `...` only if content exceeds 80 characters.
### Unpin
If the user says "unpin":
1. Call `get_memory` to read current content and metadata.
2. Set `metadata.pinned = false`:
1. Call `get_memory` to read current content.
2. Remove the pin marker from the text:
```python
updated_meta = {**original_metadata, "pinned": False}
update_memory(memory_id=<id>, text=<original_text>, metadata=updated_meta)
unpinned_text = original_text.removeprefix("[PINNED] ")
update_memory(memory_id=<id>, text=unpinned_text)
```
3. Print: `Unpinned: "<content>..."`
+1 -1
View File
@@ -32,7 +32,7 @@ Based on the content, pick the best `metadata.type`:
### Step 3: Store
Call `add_memory` with:
- `messages=[{"role": "user", "content": "<the user's text>"}]`
- `text="<the user's text>"`
- `user_id=<active_user_id>`
- `app_id=<active_project_id>`
- `metadata={"type": "<classified_type>", "branch": "<active_branch>", "confidence": 1.0, "source": "remember_command"}`
+6 -7
View File
@@ -26,8 +26,7 @@ If the script returns empty or errors, note "No session data available" and cont
**Lifetime stats:**
Call `get_memories` with:
- `user_id=<active_user_id>`
- `app_id=<active_project_id>`
- `filters={"AND": [{"user_id": "<active_user_id>"}, {"app_id": "<active_project_id>"}]}`
- `page_size=100`
Count the returned memories. Group them by:
@@ -38,14 +37,14 @@ Count the returned memories. Group them by:
**Session stats (API-backed):**
Read the session ID file at `/tmp/mem0_session_id_$USER`. If it exists and contains
a non-empty value, also call `get_memories` with:
- `filters={"AND": [{"user_id": "<id>"}, {"app_id": "<pid>"}, {"run_id": "<session_id>"}]}`
- `filters={"AND": [{"user_id": "<active_user_id>"}, {"app_id": "<active_project_id>"}, {"run_id": "<session_id>"}]}`
- `page_size=100`
This returns only memories written in the current session. Use this count to
cross-check the local stats file. If the API count is higher, use the API count
(the local tracker may have missed operations).
Also run a `search_memories` call with `query="project"`, `top_k=1` to measure round-trip latency (time the call).
Also run a `search_memories` MCP tool call with `query="project"`, `filters={"AND": [{"user_id": "<active_user_id>"}, {"app_id": "<active_project_id>"}]}`, `top_k=1` to measure round-trip latency. Note the time before and after the MCP call — do NOT attempt raw HTTP calls to the API.
### Step 3: Display
@@ -88,9 +87,9 @@ activity digest after the standard stats dashboard:
### W1: Fetch recent memories
Call `search_memories` in parallel with time-scoped queries:
1. `query="decisions made this week"`, `filters={"AND": [{"user_id": "<id>"}, {"app_id": "<pid>"}, {"created_at": {"gte": "<7 days ago YYYY-MM-DD>"}}]}`, `limit=20`
2. `query="bugs errors fixes"`, same time filter, `limit=20`
3. `query="patterns conventions learnings"`, same time filter, `limit=20`
1. `query="decisions made this week"`, `filters={"AND": [{"user_id": "<id>"}, {"app_id": "<pid>"}, {"created_at": {"gte": "<7 days ago YYYY-MM-DD>"}}]}`, `top_k=20`
2. `query="bugs errors fixes"`, same time filter, `top_k=20`
3. `query="patterns conventions learnings"`, same time filter, `top_k=20`
### W2: Analyze
+1 -1
View File
@@ -36,7 +36,7 @@ The user provides a project name as an argument: `/mem0:switch-project <project-
(Replace `<PROJECT_NAME>` with the user's chosen project name.)
3. Verify by searching for existing memories:
- Call `search_memories` with `query="project"`, `filters={"AND": [{"user_id": "<id>"}, {"app_id": "<PROJECT_NAME>"}]}`, `limit=1`
- Call `search_memories` with `query="project"`, `filters={"AND": [{"user_id": "<active_user_id>"}, {"app_id": "<PROJECT_NAME>"}]}`, `top_k=1`
4. Print:
```
+9 -14
View File
@@ -12,9 +12,9 @@ Show the user what mem0 has stored for the current project.
When invoked with `--all-projects` (e.g., `/mem0:tour --all-projects` or
`/mem0:tour --all-projects auth middleware`), search across ALL projects:
1. Call `get_memories` with `user_id=<active_user_id>`, `page_size=200` — **no `app_id` filter**.
1. Call `get_memories` with `filters={"AND": [{"user_id": "<active_user_id>"}]}`, `page_size=200` — **no `app_id` filter**.
2. If a search query was also provided, run `search_memories` with `query=<query>`,
`filters={"AND": [{"user_id": "<id>"}]}`, `limit=20` — again no `app_id`.
`filters={"AND": [{"user_id": "<active_user_id>"}]}`, `top_k=20` — again no `app_id`.
3. Group results by `app_id` first, then by category within each project.
4. Display:
```
@@ -37,8 +37,8 @@ When `/mem0:tour` receives a search query argument (e.g., `/mem0:tour auth middl
WITHOUT `--all-projects`, run in **peek mode** — compact one-liner results:
1. Run 2 parallel `search_memories` calls:
- Broad: `query=<query>`, `filters={"AND": [{"user_id": "<id>"}, {"app_id": "<pid>"}]}`, `limit=10`, `rerank=true`
- Targeted: `query=<query>`, `filters={"AND": [{"user_id": "<id>"}, {"app_id": "<pid>"}, {"metadata": {"type": "decision"}}]}`, `limit=5`, `rerank=true`
- Broad: `query=<query>`, `filters={"AND": [{"user_id": "<id>"}, {"app_id": "<pid>"}]}`, `top_k=10`, `rerank=true`
- Targeted: `query=<query>`, `filters={"AND": [{"user_id": "<id>"}, {"app_id": "<pid>"}, {"metadata": {"type": "decision"}}]}`, `top_k=5`, `rerank=true`
2. Deduplicate by ID, display compact results:
```
## mem0 search: "<query>" (<N> results)
@@ -57,23 +57,18 @@ If no query argument and no `--all-projects` flag, use the full tour flow below.
### Step 1: Fetch ALL memories for this project
Call `get_memories` with:
- `user_id=<active_user_id>`
- `app_id=<active_project_id>`
- `filters={"AND": [{"user_id": "<active_user_id>"}, {"app_id": "<active_project_id>"}]}`
- `page_size=100`
This returns every memory scoped to the project — no semantic filtering, no missed results.
If `get_memories` doesn't support `app_id` as a direct parameter, use:
- `filters={"AND": [{"user_id": "<id>"}, {"app_id": "<pid>"}]}`
Pass `page_size=100` (or the maximum allowed) to get a full picture.
### Step 2: Run supplementary semantic searches
In parallel, run these `search_memories` calls to get relevance-ranked results for key topics:
- `query="architecture decisions design choices"`, `filters={"AND": [{"user_id": "<id>"}, {"app_id": "<pid>"}]}`, `limit=10`, `rerank=true`
- `query="bugs errors failures anti-patterns"`, `filters={"AND": [{"user_id": "<id>"}, {"app_id": "<pid>"}]}`, `limit=10`, `rerank=true`
- `query="project setup tooling conventions preferences"`, `filters={"AND": [{"user_id": "<id>"}, {"app_id": "<pid>"}]}`, `limit=10`, `rerank=true`
- `query="architecture decisions design choices"`, `filters={"AND": [{"user_id": "<id>"}, {"app_id": "<pid>"}]}`, `top_k=10`, `rerank=true`
- `query="bugs errors failures anti-patterns"`, `filters={"AND": [{"user_id": "<id>"}, {"app_id": "<pid>"}]}`, `top_k=10`, `rerank=true`
- `query="project setup tooling conventions preferences"`, `filters={"AND": [{"user_id": "<id>"}, {"app_id": "<pid>"}]}`, `top_k=10`, `rerank=true`
**Do NOT filter by `metadata.type` in these calls.** The platform auto-assigns `categories` — filtering on `metadata.type` misses memories that were auto-categorized but don't have an explicit `metadata.type`.