feat(mem0-plugin): onboarding, project scoping, identity banner (#5207)
This commit is contained in:
@@ -16,6 +16,23 @@ You have access to persistent memory via the mem0 MCP tools. Follow this protoco
|
||||
|
||||
Decide whether persistent memory context would improve your response, then act accordingly. Don't search by default — search deliberately.
|
||||
|
||||
## Project scoping
|
||||
|
||||
Every memory operation MUST be scoped to the current project:
|
||||
|
||||
- **On `add_memory`:** Always include `metadata.project_id` (the active project_id from SessionStart).
|
||||
- **On `search_memories`:** Always include `{"metadata": {"project_id": "<your_project_id>"}}` in the AND filter.
|
||||
- **Session-state memories:** Also include `metadata.branch` (the active branch from SessionStart).
|
||||
|
||||
Full filter template:
|
||||
```python
|
||||
filters={"AND": [
|
||||
{"user_id": "<your_user_id>"},
|
||||
{"metadata": {"project_id": "<your_project_id>"}},
|
||||
{"metadata": {"type": "decision"}}
|
||||
]}
|
||||
```
|
||||
|
||||
### Decide: search or skip?
|
||||
|
||||
**Search WHEN** the user:
|
||||
@@ -59,9 +76,9 @@ Combine `user_id` with one metadata clause per call:
|
||||
| `{"metadata": {"type": "user_preference"}}` | tooling, stack, style — always include for code work |
|
||||
| `{"metadata": {"type": "convention"}}` | established patterns in this project |
|
||||
|
||||
Full filter (replace `<your_user_id>` with the active user_id from your runtime):
|
||||
Full filter (replace `<your_user_id>` and `<your_project_id>` with the active values from SessionStart):
|
||||
```python
|
||||
filters={"AND": [{"user_id": "<your_user_id>"}, {"metadata": {"type": "decision"}}]}
|
||||
filters={"AND": [{"user_id": "<your_user_id>"}, {"metadata": {"project_id": "<your_project_id>"}}, {"metadata": {"type": "decision"}}]}
|
||||
```
|
||||
|
||||
### Worked example
|
||||
@@ -74,16 +91,16 @@ search_memories(query="Refactor the auth module to use JWT")
|
||||
# Hits whatever shares words. Misses prior decisions and preferences.
|
||||
```
|
||||
|
||||
Do (parallel — substitute the active `user_id` for `<your_user_id>`):
|
||||
Do (parallel — substitute the active `user_id` and `project_id` for the placeholders):
|
||||
```python
|
||||
search_memories(query="auth module decisions",
|
||||
filters={"AND": [{"user_id": "<your_user_id>"}, {"metadata": {"type": "decision"}}]})
|
||||
filters={"AND": [{"user_id": "<your_user_id>"}, {"metadata": {"project_id": "<your_project_id>"}}, {"metadata": {"type": "decision"}}]})
|
||||
search_memories(query="JWT",
|
||||
filters={"AND": [{"user_id": "<your_user_id>"}]})
|
||||
filters={"AND": [{"user_id": "<your_user_id>"}, {"metadata": {"project_id": "<your_project_id>"}}]})
|
||||
search_memories(query="auth refactor failures",
|
||||
filters={"AND": [{"user_id": "<your_user_id>"}, {"metadata": {"type": "anti_pattern"}}]})
|
||||
filters={"AND": [{"user_id": "<your_user_id>"}, {"metadata": {"project_id": "<your_project_id>"}}, {"metadata": {"type": "anti_pattern"}}]})
|
||||
search_memories(query="auth",
|
||||
filters={"AND": [{"user_id": "<your_user_id>"}, {"metadata": {"type": "user_preference"}}]})
|
||||
filters={"AND": [{"user_id": "<your_user_id>"}, {"metadata": {"project_id": "<your_project_id>"}}, {"metadata": {"type": "user_preference"}}]})
|
||||
```
|
||||
|
||||
## After completing significant work
|
||||
@@ -116,7 +133,7 @@ When the user is asking about *current* state ("where were we", "what's the acti
|
||||
|
||||
```python
|
||||
# Last 90 days only
|
||||
{"AND": [{"user_id": "<id>"}, {"metadata": {"type": "session_state"}}, {"created_at": {"gte": "<90 days ago, YYYY-MM-DD>"}}]}
|
||||
{"AND": [{"user_id": "<id>"}, {"metadata": {"project_id": "<your_project_id>"}}, {"metadata": {"type": "session_state"}}, {"created_at": {"gte": "<90 days ago, YYYY-MM-DD>"}}]}
|
||||
```
|
||||
|
||||
Skip the recency filter when the user is asking about durable facts ("what conventions does this project use", "have we hit this bug before") — those are timeless and recency would hide them.
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
---
|
||||
name: mem0-onboard
|
||||
description: >
|
||||
Post-install onboarding wizard for the mem0 plugin.
|
||||
Detects CLAUDE.md, AGENTS.md, .cursorrules, .windsurfrules, mem0.md
|
||||
and offers to import them. Installs coding categories. Shows active identity.
|
||||
TRIGGER: user runs /mem0:onboard, or mentions "setup mem0", "configure mem0 plugin".
|
||||
---
|
||||
|
||||
# Mem0 Onboarding Wizard
|
||||
|
||||
Run this wizard to set up the mem0 plugin for the current project. Complete in ~30 seconds.
|
||||
|
||||
## Step 1: Verify API key
|
||||
|
||||
Check if `MEM0_API_KEY` is set in the current environment:
|
||||
|
||||
```bash
|
||||
echo "${MEM0_API_KEY:+SET}" || echo "NOT_SET"
|
||||
```
|
||||
|
||||
- If **NOT set**:
|
||||
1. Ask the user: "No MEM0_API_KEY found. Do you have one, or need to create one?"
|
||||
2. If they need one, provide two options:
|
||||
- **Browser**: Go to https://app.mem0.ai/dashboard/api-keys and copy the key
|
||||
- **CLI**: Run `pip install mem0-cli && mem0 init --agent --json` to mint a key without email
|
||||
3. Once they have the key, tell them to run: `export MEM0_API_KEY="m0-..."` in their terminal, then restart this Claude Code session (the env var must be set before Claude Code starts).
|
||||
4. **STOP here.** Do not proceed until the key is confirmed set.
|
||||
- If **SET**: Proceed to Step 2.
|
||||
|
||||
## Step 2: Show identity
|
||||
|
||||
Report the active identity to the user:
|
||||
- Call `search_memories` with `query="project setup"`, `user_id=<active_user_id>`, `filters={"AND": [{"user_id": "<active_user_id>"}, {"metadata": {"project_id": "<active_project_id>"}}]}`, `limit=1` to verify connectivity.
|
||||
- Print: `Connected. user=<user_id>, project=<project_id>, branch=<branch>`
|
||||
- If the search fails, troubleshoot the API key.
|
||||
|
||||
## Step 3: Detect and import project files
|
||||
|
||||
Check for these files in the project root:
|
||||
1. `CLAUDE.md`
|
||||
2. `AGENTS.md`
|
||||
3. `.cursorrules`
|
||||
4. `.windsurfrules`
|
||||
5. `mem0.md`
|
||||
|
||||
For each file found, ask the user: "Found `<filename>` (<size> bytes). Import into mem0? [Y/n]"
|
||||
|
||||
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>`
|
||||
- `metadata={"type": "project_profile", "file": "<filename>", "project_id": "<active_project_id>", "source": "onboard"}`
|
||||
- `infer=False`
|
||||
|
||||
## Step 4: Install coding categories
|
||||
|
||||
Ask: "Install coding categories optimized for development workflows? [Y/n]"
|
||||
|
||||
If yes, run the script directly (no external dependencies required — uses stdlib only).
|
||||
|
||||
The script lives at `scripts/setup_coding_categories.py` relative to the plugin root. Use the appropriate plugin root variable for the current platform:
|
||||
- Claude Code: `${CLAUDE_PLUGIN_ROOT}`
|
||||
- Codex: `${CODEX_PLUGIN_ROOT}`
|
||||
- Cursor: `${CURSOR_PLUGIN_ROOT}`
|
||||
|
||||
```bash
|
||||
python3 "<PLUGIN_ROOT>/scripts/setup_coding_categories.py" --apply
|
||||
```
|
||||
|
||||
If the script reports an error, show the error message and suggest checking the API key.
|
||||
|
||||
## Step 5: Summary
|
||||
|
||||
Print a summary:
|
||||
```
|
||||
Onboarding complete.
|
||||
user_id: <user_id>
|
||||
project_id: <project_id>
|
||||
branch: <branch>
|
||||
imported: <N> files
|
||||
categories: <installed or skipped>
|
||||
|
||||
Memory is now active for this project. Start working — mem0 will
|
||||
automatically search relevant context and capture learnings.
|
||||
|
||||
Run /mem0:tour to see what mem0 already knows about this project.
|
||||
```
|
||||
@@ -0,0 +1,50 @@
|
||||
---
|
||||
name: mem0-switch-project
|
||||
description: >
|
||||
Manually override project_id for the current directory.
|
||||
Useful for monorepos, nested git dirs, or non-git directories.
|
||||
TRIGGER: user runs /mem0:switch-project <name>, or asks "switch mem0 project",
|
||||
"change project scope", "override project_id".
|
||||
---
|
||||
|
||||
# Mem0 Switch Project
|
||||
|
||||
Override the automatic project_id detection for the current directory.
|
||||
|
||||
## Usage
|
||||
|
||||
The user provides a project name as an argument: `/mem0:switch-project <project-name>`
|
||||
|
||||
## Execution
|
||||
|
||||
1. If no project name was given, ask: "What project_id should this directory use?"
|
||||
|
||||
2. Write the mapping to `~/.mem0/project_map.json` using the Bash tool:
|
||||
|
||||
```bash
|
||||
python3 -c "
|
||||
import json, os
|
||||
map_file = os.path.expanduser('~/.mem0/project_map.json')
|
||||
mapping = {}
|
||||
if os.path.isfile(map_file):
|
||||
with open(map_file) as f:
|
||||
mapping = json.load(f)
|
||||
mapping[os.getcwd()] = '<PROJECT_NAME>'
|
||||
os.makedirs(os.path.dirname(map_file), exist_ok=True)
|
||||
with open(map_file, 'w') as f:
|
||||
json.dump(mapping, f, indent=2)
|
||||
print(f'Mapped {os.getcwd()} -> <PROJECT_NAME>')
|
||||
"
|
||||
```
|
||||
|
||||
(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>"}, {"metadata": {"project_id": "<PROJECT_NAME>"}}]}`, `limit=1`
|
||||
|
||||
4. Print:
|
||||
```
|
||||
Switched to project <PROJECT_NAME>.
|
||||
<N> memories found for this project.
|
||||
Note: This override persists across sessions for this directory.
|
||||
```
|
||||
@@ -0,0 +1,46 @@
|
||||
---
|
||||
name: mem0-tour
|
||||
description: >
|
||||
Show what mem0 knows about the current project. Dumps top memories
|
||||
grouped by category. Power-user-friendly proof of value.
|
||||
TRIGGER: user runs /mem0:tour, or asks "what do you know about this project",
|
||||
"show me my memories", "what has mem0 stored".
|
||||
---
|
||||
|
||||
# Mem0 Project Tour
|
||||
|
||||
Show the user what mem0 has stored for the current project.
|
||||
|
||||
## Execution
|
||||
|
||||
1. Run the following `search_memories` calls in parallel (all with the active `user_id` and `metadata.project_id`):
|
||||
|
||||
- `query="architecture decisions"`, `filters={"AND": [{"user_id": "<id>"}, {"metadata": {"project_id": "<pid>"}}, {"metadata": {"type": "decision"}}]}`, `limit=5`
|
||||
- `query="anti patterns failures"`, `filters={"AND": [{"user_id": "<id>"}, {"metadata": {"project_id": "<pid>"}}, {"metadata": {"type": "anti_pattern"}}]}`, `limit=5`
|
||||
- `query="task learnings strategies"`, `filters={"AND": [{"user_id": "<id>"}, {"metadata": {"project_id": "<pid>"}}, {"metadata": {"type": "task_learning"}}]}`, `limit=5`
|
||||
- `query="coding conventions"`, `filters={"AND": [{"user_id": "<id>"}, {"metadata": {"project_id": "<pid>"}}, {"metadata": {"type": "convention"}}]}`, `limit=5`
|
||||
- `query="user preferences"`, `filters={"AND": [{"user_id": "<id>"}, {"metadata": {"project_id": "<pid>"}}, {"metadata": {"type": "user_preference"}}]}`, `limit=5`
|
||||
- `query="project profile"`, `filters={"AND": [{"user_id": "<id>"}, {"metadata": {"project_id": "<pid>"}}, {"metadata": {"type": "project_profile"}}]}`, `limit=5`
|
||||
- `query="tooling setup environment"`, `filters={"AND": [{"user_id": "<id>"}, {"metadata": {"project_id": "<pid>"}}, {"metadata": {"type": "environmental"}}]}`, `limit=5`
|
||||
|
||||
2. Group results by category. For each category with results, print:
|
||||
|
||||
```
|
||||
## <category_name> (<count> memories)
|
||||
- <memory_content_truncated_to_100_chars> (score: <similarity_score>)
|
||||
- ...
|
||||
```
|
||||
|
||||
3. For categories with zero results, print: `<category_name>: (empty)`
|
||||
|
||||
4. Print totals at the end:
|
||||
```
|
||||
---
|
||||
Total: <N> memories across <M> categories for project <project_id>
|
||||
```
|
||||
|
||||
5. If ALL categories are empty, print:
|
||||
```
|
||||
No memories stored yet for project <project_id>.
|
||||
Run /mem0:onboard to import project files, or start working — mem0 captures learnings automatically.
|
||||
```
|
||||
Reference in New Issue
Block a user