db1b733c24
When a user installs mem0-plugin, mem0 starts empty even though Claude Code has been quietly accumulating their CLAUDE.md instructions, auto-memory, and subagent learnings on disk for months. The existing hooks capture live state going forward but cannot backfill what already exists. This commit adds a one-shot importer that walks every Claude state surface and backfills it into mem0: - `mem0-plugin/scripts/import_claude_state.py` (new, ~575 lines): discovers CLAUDE.md hierarchy (+ @imports), .claude/rules, ~/.claude/projects/*/memory, and ~/.claude/agent-memory; chunks each file at markdown headings (H2 default, H3 for oversize sections, small-sibling merge, code-fence safe); tags chunks with metadata matching the existing mem0-mcp skill vocabulary (convention / user_preference / task_learning / anti_pattern / decision); POSTs sequentially to /v1/memories/ with infer=True (server-side dedup). Marker file at ~/.mem0/imports/claude-state.json tracks content-hash per chunk for idempotent re-runs and crash-resume safety. Flags: --dry-run, --reset, --no-infer, --source <type>. - `mem0-plugin/scripts/on_session_start.sh`: adds a one-time nudge block after the existing bootstrap output. Emits the holistic-import prompt only when ~/.mem0/imports/claude-state.json doesn't exist and the SOURCE isn't "compact". Propagates to Cursor and Codex for free (shared bash entry point). - README, CHANGELOG, plugin.json bumped to 0.2.0. Patterned exactly on the existing on_pre_compact.py: stdlib only (urllib, hashlib, pathlib, argparse), reuses _identity.resolve_user_id, same logging setup, same ~/.mem0/ storage convention. Zero new packages, zero new deps. Smoke-tested locally: --help renders, missing MEM0_API_KEY exits 1 with helpful message, hook emits nudge when marker absent and stays silent when marker present. Research and design context: https://www.notion.so/Claude-State-Holistic-Import-Research-Findings-366f22c70c9081d7abdcc6b94a80e8d9
107 lines
4.2 KiB
Bash
Executable File
107 lines
4.2 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
# Hook: SessionStart (matcher: startup|resume|compact)
|
|
#
|
|
# Bootstraps mem0 context at the start of every session.
|
|
# Output becomes part of Claude's context so it calls mem0 MCP tools.
|
|
#
|
|
# Input: JSON on stdin with session_id, source, transcript_path, model, cwd
|
|
# Output: Text injected into Claude's context (exit 0)
|
|
|
|
# Intentionally omit -e so the script always outputs a bootstrap prompt
|
|
# even if jq is missing or stdin is malformed.
|
|
set -uo pipefail
|
|
|
|
if [ -n "${MEM0_DEBUG:-}" ]; then
|
|
mkdir -p "$HOME/.mem0" && exec 2>>"$HOME/.mem0/hooks.log"
|
|
fi
|
|
|
|
# Skip the bootstrap entirely if no API key is configured -- the agent
|
|
# would otherwise be told to call mem0 MCP tools that will all fail.
|
|
if [ -z "${MEM0_API_KEY:-}" ]; then
|
|
exit 0
|
|
fi
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
# shellcheck source=_identity.sh
|
|
. "$SCRIPT_DIR/_identity.sh"
|
|
|
|
INPUT=$(cat)
|
|
SOURCE=$(echo "$INPUT" | jq -r '.source // "startup"' 2>/dev/null || echo "startup")
|
|
|
|
# Identity line is emitted before every bootstrap variant so the agent
|
|
# uses the same user_id the hooks resolved. Without this, the agent's
|
|
# search_memories/add_memory MCP calls may bind to a different bucket
|
|
# than what the hooks write to.
|
|
echo "## Mem0 Identity"
|
|
echo ""
|
|
echo "Active user_id: \`$MEM0_RESOLVED_USER_ID\`"
|
|
echo ""
|
|
echo "Always include \`{\"user_id\": \"$MEM0_RESOLVED_USER_ID\"}\` (wrapped in an \`AND\` clause) in every \`search_memories\` filter and as \`user_id\` on every \`add_memory\` call. This keeps the agent's MCP calls aligned with the bucket the hooks write to."
|
|
echo ""
|
|
|
|
if [ "$SOURCE" = "startup" ]; then
|
|
cat <<'EOF'
|
|
## Mem0 Session Bootstrap
|
|
|
|
You have access to persistent memory via the mem0 MCP tools. Before doing anything else:
|
|
|
|
1. Call `search_memories` with a query related to the current project or user request to load relevant context.
|
|
2. Review the returned memories to understand what has been learned in prior sessions.
|
|
3. If appropriate, call `get_memories` to browse all stored memories for this user.
|
|
|
|
IMPORTANT: Do NOT skip this step. Always bootstrap context first.
|
|
EOF
|
|
|
|
elif [ "$SOURCE" = "resume" ]; then
|
|
cat <<'EOF'
|
|
## Mem0 Session Resumed
|
|
|
|
This is a resumed session. Your prior context is already loaded. Before continuing:
|
|
|
|
1. Call `search_memories` with a query related to the current task to refresh relevant memories.
|
|
2. If significant time has passed, search for recent project-wide updates.
|
|
|
|
Continue where you left off.
|
|
EOF
|
|
|
|
elif [ "$SOURCE" = "compact" ]; then
|
|
# Capture the just-generated compact summary in the background.
|
|
# PreCompact fires too early to see this entry; SessionStart-compact
|
|
# is the first place isCompactSummary=true is in the transcript.
|
|
echo "$INPUT" | python3 "$SCRIPT_DIR/capture_compact_summary.py" 2>/dev/null &
|
|
|
|
cat <<'EOF'
|
|
## Mem0 Post-Compaction Recovery
|
|
|
|
Context was just compacted. The Claude Code-generated compact summary
|
|
is being captured to mem0 in the background as `metadata.type=compact_summary`.
|
|
|
|
1. Call `search_memories` to reload context, layering up to three angles:
|
|
- `metadata.type=session_state` -- the rich pre-compaction summary you wrote
|
|
- `metadata.type=compact_summary` -- the platform-generated condensed summary just now
|
|
- `metadata.type=decision` / `anti_pattern` -- specific facts you stored during the session
|
|
2. Continue working from the recovered context.
|
|
EOF
|
|
fi
|
|
|
|
# ── Holistic import nudge ────────────────────────────────────────────────
|
|
# One-time nudge to backfill existing CLAUDE.md / MEMORY.md / agent-memory
|
|
# into mem0. Silent after the marker file appears (i.e., after first run).
|
|
# Only emit on startup or resume -- during compact the user is mid-conversation.
|
|
if [ "$SOURCE" != "compact" ] && [ ! -f "$HOME/.mem0/imports/claude-state.json" ]; then
|
|
cat <<EOF
|
|
|
|
## Holistic import available
|
|
|
|
On-disk Claude state (CLAUDE.md, ~/.claude/projects/*/memory, ~/.claude/agent-memory)
|
|
has never been imported into mem0. To preview what would be imported, run:
|
|
|
|
python3 "$SCRIPT_DIR/import_claude_state.py" --dry-run
|
|
|
|
Then drop \`--dry-run\` to import. This nudge disappears after the first
|
|
successful run. Pass \`--reset\` to re-import from scratch.
|
|
EOF
|
|
fi
|
|
|
|
exit 0
|