fix(mem0-plugin): use app_id entity scoping, fix tour, add branch tagging
Tour was filtering on metadata.type which missed platform-categorized memories. Rewritten to use get_memories (list all) + group by platform categories field. All write hooks now use app_id as top-level entity param instead of metadata.project_id. Branch stamped on every write.
This commit is contained in:
@@ -22,7 +22,7 @@ import urllib.request
|
||||
|
||||
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
|
||||
from _identity import resolve_user_id
|
||||
from _project import resolve_project_id
|
||||
from _project import resolve_branch, resolve_project_id
|
||||
|
||||
log = logging.getLogger("mem0-auto-import")
|
||||
log.setLevel(logging.DEBUG)
|
||||
@@ -77,8 +77,15 @@ def save_hashes(hashes: dict[str, str]) -> None:
|
||||
log.warning("Could not save hash store: %s", e)
|
||||
|
||||
|
||||
def post_memory(api_key: str, content: str, user_id: str, filename: str, project_id: str) -> bool:
|
||||
def post_memory(api_key: str, content: str, user_id: str, filename: str, project_id: str, branch: str = "") -> bool:
|
||||
"""POST a project profile memory to the Mem0 REST API."""
|
||||
metadata = {
|
||||
"type": "project_profile",
|
||||
"file": filename,
|
||||
"source": "auto-import",
|
||||
}
|
||||
if branch:
|
||||
metadata["branch"] = branch
|
||||
body = {
|
||||
"messages": [
|
||||
{
|
||||
@@ -87,12 +94,8 @@ def post_memory(api_key: str, content: str, user_id: str, filename: str, project
|
||||
}
|
||||
],
|
||||
"user_id": user_id,
|
||||
"metadata": {
|
||||
"type": "project_profile",
|
||||
"file": filename,
|
||||
"project_id": project_id,
|
||||
"source": "auto-import",
|
||||
},
|
||||
"app_id": project_id,
|
||||
"metadata": metadata,
|
||||
"infer": False,
|
||||
}
|
||||
|
||||
@@ -128,8 +131,9 @@ def main() -> None:
|
||||
cwd = os.environ.get("MEM0_CWD", "").strip() or os.getcwd()
|
||||
user_id = resolve_user_id()
|
||||
project_id = resolve_project_id(cwd)
|
||||
branch = resolve_branch(cwd)
|
||||
|
||||
log.debug("Auto-import started: cwd=%s project=%s user=%s", cwd, project_id, user_id)
|
||||
log.debug("Auto-import started: cwd=%s project=%s user=%s branch=%s", cwd, project_id, user_id, branch)
|
||||
|
||||
hashes = load_hashes()
|
||||
updated = False
|
||||
@@ -169,7 +173,7 @@ def main() -> None:
|
||||
log.debug("Cannot read %s: %s", filename, e)
|
||||
continue
|
||||
|
||||
if post_memory(api_key, content, user_id, filename, project_id):
|
||||
if post_memory(api_key, content, user_id, filename, project_id, branch):
|
||||
hashes[hash_key] = current_hash
|
||||
updated = True
|
||||
# on API failure we don't update the hash — retry next session
|
||||
|
||||
@@ -97,16 +97,18 @@ def find_compact_summary(lines: list[str]) -> str:
|
||||
|
||||
def store_summary(api_key: str, summary: str, user_id: str, session_id: str, project_id: str = "", branch: str = "") -> bool:
|
||||
expires = (date.today() + timedelta(days=COMPACT_SUMMARY_EXPIRY_DAYS)).isoformat()
|
||||
metadata = {
|
||||
"type": "compact_summary",
|
||||
"source": "session-start-compact",
|
||||
"session_id": session_id,
|
||||
}
|
||||
if branch:
|
||||
metadata["branch"] = branch
|
||||
body = {
|
||||
"messages": [{"role": "user", "content": summary}],
|
||||
"user_id": user_id,
|
||||
"metadata": {
|
||||
"type": "compact_summary",
|
||||
"source": "session-start-compact",
|
||||
"session_id": session_id,
|
||||
"project_id": project_id,
|
||||
"branch": branch,
|
||||
},
|
||||
"app_id": project_id,
|
||||
"metadata": metadata,
|
||||
"infer": False,
|
||||
"expiration_date": expires,
|
||||
}
|
||||
|
||||
@@ -171,18 +171,20 @@ def build_content(state: dict, source: str) -> str:
|
||||
def store_memory(api_key: str, content: str, user_id: str, source: str, session_id: str = "", project_id: str = "", branch: str = "") -> bool:
|
||||
"""Store session state as a memory via the Mem0 REST API."""
|
||||
expires = (date.today() + timedelta(days=SESSION_STATE_EXPIRY_DAYS)).isoformat()
|
||||
metadata = {
|
||||
"type": "session_state",
|
||||
"source": source,
|
||||
"session_id": session_id,
|
||||
}
|
||||
if branch:
|
||||
metadata["branch"] = branch
|
||||
body = {
|
||||
"messages": [
|
||||
{"role": "user", "content": content}
|
||||
],
|
||||
"user_id": user_id,
|
||||
"metadata": {
|
||||
"type": "session_state",
|
||||
"source": source,
|
||||
"session_id": session_id,
|
||||
"project_id": project_id,
|
||||
"branch": branch,
|
||||
},
|
||||
"app_id": project_id,
|
||||
"metadata": metadata,
|
||||
"expiration_date": expires,
|
||||
}
|
||||
|
||||
|
||||
@@ -55,7 +55,8 @@ Tool call shape:
|
||||
add_memory(
|
||||
messages=[{"role":"user","content":"<the summary above>"}],
|
||||
user_id="<the active user_id from the SessionStart bootstrap>",
|
||||
metadata={"type":"session_state","source":"pre-compaction","project_id":"<the active project_id>","branch":"<the active branch>"},
|
||||
app_id="<the active project_id / app_id from SessionStart>",
|
||||
metadata={"type":"session_state","source":"pre-compaction","branch":"<active branch>"},
|
||||
infer=False,
|
||||
)
|
||||
```
|
||||
|
||||
@@ -38,11 +38,11 @@ if command -v python3 >/dev/null 2>&1; then
|
||||
import json, os, urllib.request, urllib.error
|
||||
api_key = os.environ.get('MEM0_API_KEY', '')
|
||||
user_id = os.environ.get('MEM0_RESOLVED_USER_ID', 'default')
|
||||
project_id = os.environ.get('MEM0_PROJECT_ID', '')
|
||||
app_id = os.environ.get('MEM0_PROJECT_ID', '')
|
||||
body = json.dumps({
|
||||
'query': 'project context',
|
||||
'user_id': user_id,
|
||||
'filters': {'AND': [{'user_id': user_id}, {'metadata': {'project_id': project_id}}]},
|
||||
'filters': {'AND': [{'user_id': user_id}, {'app_id': app_id}]},
|
||||
'limit': 100,
|
||||
}).encode()
|
||||
req = urllib.request.Request(
|
||||
@@ -72,14 +72,30 @@ echo "## Mem0 Active"
|
||||
echo ""
|
||||
echo "\`user=$MEM0_RESOLVED_USER_ID | project=$MEM0_PROJECT_ID | branch=$MEM0_BRANCH | memories=$MEM0_COUNT\`"
|
||||
echo ""
|
||||
echo "Always include \`user_id\` + \`metadata.project_id\` in every \`search_memories\` filter and \`add_memory\` call:"
|
||||
echo "Always include \`user_id\` + \`app_id\` in every \`search_memories\` filter and \`add_memory\` call:"
|
||||
echo "- user_id: \`$MEM0_RESOLVED_USER_ID\`"
|
||||
echo "- project_id: \`$MEM0_PROJECT_ID\`"
|
||||
echo "- branch: \`$MEM0_BRANCH\` (include in session-state / compact-summary metadata)"
|
||||
echo "- app_id: \`$MEM0_PROJECT_ID\` (project scope — passed as top-level \`app_id\`, NOT in metadata)"
|
||||
echo ""
|
||||
|
||||
if [ "$SOURCE" = "startup" ]; then
|
||||
cat <<'EOF'
|
||||
# First-run detection: auto-trigger onboarding for new projects
|
||||
_ONBOARD_MARKER="$HOME/.mem0/.onboarded_${MEM0_PROJECT_ID}"
|
||||
if [ ! -f "$_ONBOARD_MARKER" ]; then
|
||||
cat <<'EOF'
|
||||
## Mem0 First Run — Automatic Onboarding
|
||||
|
||||
This is the first time mem0 is running for this project. You MUST run the onboarding wizard NOW before doing anything else.
|
||||
|
||||
Execute the `/mem0:onboard` skill immediately. This will:
|
||||
1. Verify the API key
|
||||
2. Detect and import project files (CLAUDE.md, AGENTS.md, .cursorrules, etc.)
|
||||
3. Install coding categories optimized for development
|
||||
4. Show a summary of what was set up
|
||||
|
||||
Do NOT skip this. Do NOT ask the user if they want to onboard. Just run `/mem0:onboard` now.
|
||||
EOF
|
||||
else
|
||||
cat <<'EOF'
|
||||
## Mem0 Session Bootstrap
|
||||
|
||||
You have access to persistent memory via the mem0 MCP tools. Before doing anything else:
|
||||
@@ -90,6 +106,7 @@ You have access to persistent memory via the mem0 MCP tools. Before doing anythi
|
||||
|
||||
IMPORTANT: Do NOT skip this step. Always bootstrap context first.
|
||||
EOF
|
||||
fi
|
||||
|
||||
# Auto-import declarative project files in background
|
||||
MEM0_CWD="$(echo "$INPUT" | jq -r '.cwd // "."' 2>/dev/null || echo ".")" \
|
||||
|
||||
@@ -54,7 +54,7 @@ Memories can be as detailed as needed — include full context, reasoning, code
|
||||
|
||||
If nothing notable happened in this interaction, it's fine to skip. Only store genuinely useful learnings.
|
||||
|
||||
Always include `"project_id"` in the metadata of any memory you store.
|
||||
Always include `app_id` (the active project_id from SessionStart) as a top-level parameter in every `add_memory` call.
|
||||
EOF
|
||||
|
||||
# Capture transcript state in the background via Mem0 REST API
|
||||
|
||||
@@ -51,7 +51,7 @@ ${REPORT_BLOCK}Before finishing, check if there are important learnings from thi
|
||||
|
||||
Memories can be as detailed as needed — include full context, reasoning, code snippets, file paths, and examples. Longer, searchable memories are more valuable than vague one-liners.
|
||||
|
||||
Always include \`"project_id"\` in the metadata of any memory you store.
|
||||
Always include \`app_id\` (the active project_id from SessionStart) as a top-level parameter in every \`add_memory\` call.
|
||||
|
||||
If nothing notable happened in this interaction, it's fine to skip. Only store genuinely useful learnings.
|
||||
EOF
|
||||
|
||||
@@ -35,7 +35,7 @@ ${REPORT_BLOCK}Before finishing, check if there are important learnings from thi
|
||||
4. Did you learn anything about the user's preferences? -> Store with metadata \`{"type": "user_preference"}\`
|
||||
5. Were there environment/setup discoveries? -> Store with metadata \`{"type": "environmental"}\`
|
||||
|
||||
Always include \`"project_id"\` in the metadata of any memory you store.
|
||||
Always include \`app_id\` (the active project_id from session start) as a top-level parameter in every \`add_memory\` call.
|
||||
|
||||
If nothing notable happened, it's fine to skip. Only store genuinely useful learnings.
|
||||
EOF
|
||||
|
||||
@@ -31,7 +31,7 @@ Extract key learnings from this completed task and store them using the mem0 \`a
|
||||
|
||||
Memories can be as detailed as needed — include full context, reasoning, code snippets, and examples.
|
||||
Only store genuinely useful learnings — skip if the task was trivial.
|
||||
Include \`"project_id": "$MEM0_PROJECT_ID"\` in metadata for all memories.
|
||||
Include \`app_id\` = \`"$MEM0_PROJECT_ID"\` as a top-level parameter in every \`add_memory\` call (not in metadata).
|
||||
EOF
|
||||
|
||||
exit 0
|
||||
|
||||
@@ -60,12 +60,12 @@ improve your answer. The agent -- not this hook -- owns this decision.
|
||||
- Phrase queries as **nouns** ("auth module decisions"), not full sentences.
|
||||
- Filter shape: the root must be a logical operator (\`AND\` / \`OR\` / \`NOT\`)
|
||||
with an array, and metadata uses a **nested** object (not dotted keys).
|
||||
Combine \`user_id\` with one \`metadata.type\` clause per call:
|
||||
- \`{"AND": [{"user_id": "$USER_ID"}, {"metadata": {"project_id": "$MEM0_PROJECT_ID"}}, {"metadata": {"type": "decision"}}]}\` -- design / architecture
|
||||
- \`{"AND": [{"user_id": "$USER_ID"}, {"metadata": {"project_id": "$MEM0_PROJECT_ID"}}, {"metadata": {"type": "anti_pattern"}}]}\` -- debugging, error handling
|
||||
- \`{"AND": [{"user_id": "$USER_ID"}, {"metadata": {"project_id": "$MEM0_PROJECT_ID"}}, {"metadata": {"type": "user_preference"}}]}\` -- tooling, stack, style
|
||||
- \`{"AND": [{"user_id": "$USER_ID"}, {"metadata": {"project_id": "$MEM0_PROJECT_ID"}}, {"metadata": {"type": "convention"}}]}\` -- established patterns
|
||||
- Or scope with just \`{"AND": [{"user_id": "$USER_ID"}, {"metadata": {"project_id": "$MEM0_PROJECT_ID"}}]}\` when no metadata filter fits.
|
||||
Combine \`user_id\` + \`app_id\` with one \`metadata.type\` clause per call:
|
||||
- \`{"AND": [{"user_id": "$USER_ID"}, {"app_id": "$MEM0_PROJECT_ID"}, {"metadata": {"type": "decision"}}]}\` -- design / architecture
|
||||
- \`{"AND": [{"user_id": "$USER_ID"}, {"app_id": "$MEM0_PROJECT_ID"}, {"metadata": {"type": "anti_pattern"}}]}\` -- debugging, error handling
|
||||
- \`{"AND": [{"user_id": "$USER_ID"}, {"app_id": "$MEM0_PROJECT_ID"}, {"metadata": {"type": "user_preference"}}]}\` -- tooling, stack, style
|
||||
- \`{"AND": [{"user_id": "$USER_ID"}, {"app_id": "$MEM0_PROJECT_ID"}, {"metadata": {"type": "convention"}}]}\` -- established patterns
|
||||
- Or scope with just \`{"AND": [{"user_id": "$USER_ID"}, {"app_id": "$MEM0_PROJECT_ID"}]}\` when no metadata filter fits.
|
||||
- Empty results are normal -- proceed without context.
|
||||
EOF
|
||||
|
||||
|
||||
@@ -18,17 +18,16 @@ Decide whether persistent memory context would improve your response, then act a
|
||||
|
||||
## Project scoping
|
||||
|
||||
Every memory operation MUST be scoped to the current project:
|
||||
Every memory operation MUST be scoped to the current project using `app_id` (entity-scoped memory):
|
||||
|
||||
- **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).
|
||||
- **On `add_memory`:** Always pass `app_id=<active_project_id>` as a **top-level parameter** (not in metadata).
|
||||
- **On `search_memories`:** Always include `{"app_id": "<your_project_id>"}` in the AND filter.
|
||||
|
||||
Full filter template:
|
||||
```python
|
||||
filters={"AND": [
|
||||
{"user_id": "<your_user_id>"},
|
||||
{"metadata": {"project_id": "<your_project_id>"}},
|
||||
{"app_id": "<your_project_id>"},
|
||||
{"metadata": {"type": "decision"}}
|
||||
]}
|
||||
```
|
||||
@@ -67,7 +66,7 @@ Two rules from the v2 filter spec:
|
||||
1. The root **must** be a logical operator (`AND` / `OR` / `NOT`) with an array. A bare `{"user_id": "..."}` won't work.
|
||||
2. Metadata uses a **nested** object, not a dotted key. `{"metadata": {"type": "decision"}}`, never `{"metadata.type": "decision"}`. Only top-level metadata keys are filterable.
|
||||
|
||||
Combine `user_id` with one metadata clause per call:
|
||||
Combine `user_id` + `app_id` with one metadata clause per call:
|
||||
|
||||
| `metadata.type` clause | Use for |
|
||||
|--------|---------|
|
||||
@@ -78,7 +77,7 @@ Combine `user_id` with one metadata clause per call:
|
||||
|
||||
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": {"project_id": "<your_project_id>"}}, {"metadata": {"type": "decision"}}]}
|
||||
filters={"AND": [{"user_id": "<your_user_id>"}, {"app_id": "<your_project_id>"}, {"metadata": {"type": "decision"}}]}
|
||||
```
|
||||
|
||||
### Worked example
|
||||
@@ -91,16 +90,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` and `project_id` for the placeholders):
|
||||
Do (parallel — substitute the active `user_id` and `app_id` for the placeholders):
|
||||
```python
|
||||
search_memories(query="auth module decisions",
|
||||
filters={"AND": [{"user_id": "<your_user_id>"}, {"metadata": {"project_id": "<your_project_id>"}}, {"metadata": {"type": "decision"}}]})
|
||||
filters={"AND": [{"user_id": "<your_user_id>"}, {"app_id": "<your_project_id>"}, {"metadata": {"type": "decision"}}]})
|
||||
search_memories(query="JWT",
|
||||
filters={"AND": [{"user_id": "<your_user_id>"}, {"metadata": {"project_id": "<your_project_id>"}}]})
|
||||
filters={"AND": [{"user_id": "<your_user_id>"}, {"app_id": "<your_project_id>"}]})
|
||||
search_memories(query="auth refactor failures",
|
||||
filters={"AND": [{"user_id": "<your_user_id>"}, {"metadata": {"project_id": "<your_project_id>"}}, {"metadata": {"type": "anti_pattern"}}]})
|
||||
filters={"AND": [{"user_id": "<your_user_id>"}, {"app_id": "<your_project_id>"}, {"metadata": {"type": "anti_pattern"}}]})
|
||||
search_memories(query="auth",
|
||||
filters={"AND": [{"user_id": "<your_user_id>"}, {"metadata": {"project_id": "<your_project_id>"}}, {"metadata": {"type": "user_preference"}}]})
|
||||
filters={"AND": [{"user_id": "<your_user_id>"}, {"app_id": "<your_project_id>"}, {"metadata": {"type": "user_preference"}}]})
|
||||
```
|
||||
|
||||
## After completing significant work
|
||||
@@ -114,6 +113,8 @@ Extract key learnings and store them using the `add_memory` tool:
|
||||
- **Environment/setup discoveries** -> Include metadata `{"type": "environmental"}`
|
||||
- **Conventions established** -> Include metadata `{"type": "convention"}`
|
||||
|
||||
Always include `"branch": "<active_branch>"` in the metadata object alongside `type`. The active branch is shown in the SessionStart banner. This enables branch-scoped filtering later (e.g., "what did we do on feature/auth-rewrite?").
|
||||
|
||||
> `metadata.type` (which you set explicitly) and `categories` (which the platform auto-tags after the project's custom-category list — see `scripts/setup_coding_categories.py`) are complementary. Always set `metadata.type` for explicit filtering; the platform fills in `categories` on its own. Don't try to set `categories` on `add_memory` calls — per-request overrides aren't supported on the managed API.
|
||||
|
||||
### Expiration: high-churn vs durable
|
||||
@@ -133,7 +134,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": {"project_id": "<your_project_id>"}}, {"metadata": {"type": "session_state"}}, {"created_at": {"gte": "<90 days ago, YYYY-MM-DD>"}}]}
|
||||
{"AND": [{"user_id": "<id>"}, {"app_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.
|
||||
@@ -148,7 +149,8 @@ When you've done the extraction work yourself — pre-compaction summaries, deci
|
||||
add_memory(
|
||||
messages=[{"role": "user", "content": "<your structured fact>"}],
|
||||
user_id="<active user_id>",
|
||||
metadata={"type": "decision"},
|
||||
app_id="<active project_id>",
|
||||
metadata={"type": "decision", "branch": "<active branch>"},
|
||||
infer=False,
|
||||
)
|
||||
```
|
||||
|
||||
@@ -31,7 +31,7 @@ echo "${MEM0_API_KEY:+SET}" || echo "NOT_SET"
|
||||
## 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.
|
||||
- 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.
|
||||
- Print: `Connected. user=<user_id>, project=<project_id>, branch=<branch>`
|
||||
- If the search fails, troubleshoot the API key.
|
||||
|
||||
@@ -51,7 +51,8 @@ If user says yes (or default):
|
||||
- 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"}`
|
||||
- `app_id=<active_project_id>`
|
||||
- `metadata={"type": "project_profile", "file": "<filename>", "source": "onboard", "branch": "<active_branch>"}`
|
||||
- `infer=False`
|
||||
|
||||
## Step 4: Install coding categories
|
||||
@@ -71,14 +72,23 @@ 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
|
||||
## Step 5: Mark project as onboarded
|
||||
|
||||
Create a marker file so SessionStart won't re-trigger onboarding next session:
|
||||
|
||||
```bash
|
||||
mkdir -p ~/.mem0 && touch ~/.mem0/.onboarded_<active_project_id>
|
||||
```
|
||||
|
||||
This is silent — no user-facing output needed.
|
||||
|
||||
## Step 6: Summary
|
||||
|
||||
Print a summary:
|
||||
```
|
||||
Onboarding complete.
|
||||
user_id: <user_id>
|
||||
project_id: <project_id>
|
||||
branch: <branch>
|
||||
project_id: <project_id> (app_id)
|
||||
imported: <N> files
|
||||
categories: <installed or skipped>
|
||||
|
||||
|
||||
@@ -40,7 +40,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>"}, {"metadata": {"project_id": "<PROJECT_NAME>"}}]}`, `limit=1`
|
||||
- Call `search_memories` with `query="project"`, `filters={"AND": [{"user_id": "<id>"}, {"app_id": "<PROJECT_NAME>"}]}`, `limit=1`
|
||||
|
||||
4. Print:
|
||||
```
|
||||
|
||||
@@ -13,34 +13,79 @@ 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`):
|
||||
### Step 1: Fetch ALL memories for this project
|
||||
|
||||
- `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`
|
||||
Call `get_memories` with:
|
||||
- `user_id=<active_user_id>`
|
||||
- `app_id=<active_project_id>`
|
||||
|
||||
2. Group results by category. For each category with results, print:
|
||||
This returns every memory scoped to the project — no semantic filtering, no missed results.
|
||||
|
||||
```
|
||||
## <category_name> (<count> memories)
|
||||
- <memory_content_truncated_to_100_chars> (score: <similarity_score>)
|
||||
- ...
|
||||
```
|
||||
If `get_memories` doesn't support `app_id` as a direct parameter, use:
|
||||
- `filters={"AND": [{"user_id": "<id>"}, {"app_id": "<pid>"}]}`
|
||||
|
||||
3. For categories with zero results, print: `<category_name>: (empty)`
|
||||
Pass `page_size=100` (or the maximum allowed) to get a full picture.
|
||||
|
||||
4. Print totals at the end:
|
||||
```
|
||||
---
|
||||
Total: <N> memories across <M> categories for project <project_id>
|
||||
```
|
||||
### Step 2: Run supplementary semantic searches
|
||||
|
||||
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.
|
||||
```
|
||||
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`
|
||||
- `query="bugs errors failures anti-patterns"`, `filters={"AND": [{"user_id": "<id>"}, {"app_id": "<pid>"}]}`, `limit=10`
|
||||
- `query="project setup tooling conventions preferences"`, `filters={"AND": [{"user_id": "<id>"}, {"app_id": "<pid>"}]}`, `limit=10`
|
||||
|
||||
**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`.
|
||||
|
||||
### Step 3: Merge and group
|
||||
|
||||
Merge all results by memory ID (deduplicate). For each memory, determine its group using this priority:
|
||||
|
||||
1. **Platform `categories` field** (array on each memory, auto-assigned by Mem0). Use the first category value.
|
||||
2. **`metadata.type` field** (if present, set explicitly by hooks/agent). Use as fallback if no `categories`.
|
||||
3. **"other"** bucket for memories with neither.
|
||||
|
||||
Map category names to display names:
|
||||
|
||||
| Platform category / metadata.type | Display name |
|
||||
|---|---|
|
||||
| `architecture decisions`, `architecture_decisions`, `decision` | Architecture Decisions |
|
||||
| `anti patterns`, `anti_patterns`, `anti_pattern` | Anti-Patterns |
|
||||
| `task learnings`, `task_learnings`, `task_learning` | Task Learnings |
|
||||
| `coding conventions`, `coding_conventions`, `convention` | Coding Conventions |
|
||||
| `user preferences`, `user_preferences`, `user_preference` | User Preferences |
|
||||
| `project profile`, `project_profile` | Project Profile |
|
||||
| `tooling setup`, `tooling_setup`, `environmental` | Tooling & Setup |
|
||||
| `technology`, `professional_details` | Tooling & Setup |
|
||||
| `session_state` | Session State |
|
||||
| `compact_summary` | Compact Summaries |
|
||||
| anything else | Other |
|
||||
|
||||
### Step 4: Display results
|
||||
|
||||
For each group that has results, print:
|
||||
|
||||
```
|
||||
## <display_name> (<count> memories)
|
||||
- <memory_content_truncated_to_120_chars> (score: <similarity_score_if_available>)
|
||||
- ...
|
||||
```
|
||||
|
||||
Show up to 5 memories per group. If a group has more than 5, show top 5 by recency (or similarity score if from a search call) and note `... and <N> more`.
|
||||
|
||||
For groups with zero results, skip them entirely — don't print empty groups.
|
||||
|
||||
### Step 5: Print totals
|
||||
|
||||
```
|
||||
---
|
||||
Total: <N> unique memories across <M> categories for project <project_id>
|
||||
Branch: <active_branch>
|
||||
```
|
||||
|
||||
### Step 6: Empty state
|
||||
|
||||
If zero memories found for this project, 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