Two changes to the compaction flow:
PreCompact: agent stores its summary with infer=False
on_pre_compact.sh now instructs the agent to call add_memory with
infer=False. The agent has full conversation context and writes a
structured summary; without infer=False the platform runs a second
LLM extraction pass over that summary, losing structure and
producing fragmented facts. With it, the structured text is
preserved verbatim. Same guidance added to mem0-mcp/SKILL.md so
the agent applies it to other already-extracted writes (decisions,
anti-patterns, conventions).
SessionStart-compact: capture the platform-generated summary
PreCompact fires BEFORE Claude Code generates its compact summary,
so the summary is unreachable from that hook. SessionStart-compact
fires AFTER, so a new background helper (capture_compact_summary.py)
reads the transcript at that point, finds the isCompactSummary=true
entry, and stores its content as a separate memory tagged
metadata.type=compact_summary. The post-compaction bootstrap text
now tells the agent to layer its recall queries across
session_state (its own pre-compact summary), compact_summary (the
platform's condensed view), and topical types like decision /
anti_pattern.
Net effect: three complementary memory types from one session
boundary, none of which used to be filterable or even captured
correctly.
Hooks previously fell back to $USER when MEM0_USER_ID wasn't set,
producing a different user_id on every machine for the same person.
Result: a single account with memories scattered across many user
buckets, none of which can see each other.
Resolution priority (same in bash and python):
1. MEM0_USER_ID env var (explicit override)
2. ~/.mem0/identity.json cache (pinned to MEM0_API_KEY fingerprint)
3. Derived: "mem0-" + sha256(MEM0_API_KEY)[:12]
4. Fallback: $USER, else "default"
Same MEM0_API_KEY across machines now yields the same user_id without
the user having to set MEM0_USER_ID by hand on every laptop.
Resolver shipped as two tiny files instead of a shared module:
_identity.sh -- sourced by bash hooks, exports MEM0_RESOLVED_USER_ID
_identity.py -- imported by on_pre_compact.py, exposes resolve_user_id()
Hook integration:
on_user_prompt.sh -- sources resolver, USER_ID interpolated into rubric
on_session_start.sh -- emits an "Active user_id: <X>" header before the
bootstrap text, so the agent's MCP search_memories/add_memory calls
use the same bucket the hooks write to (closes the agent-side half
of the symptom)
on_pre_compact.py -- replaces inline env lookup with resolve_user_id()
Existing memories under previous $USER values are not auto-migrated.
The cache file regenerates on key rotation (fingerprint mismatch).
Six independent fixes that make hook behaviour deterministic, debuggable,
and free of silent footguns.
Persist session_id in stored memories
on_pre_compact.py now extracts session_id from the hook input and writes
it under metadata.session_id, enabling search-by-session.
Skip SessionStart bootstrap when MEM0_API_KEY is missing
on_session_start.sh exits 0 early instead of emitting bootstrap text that
instructs the agent to call mem0 MCP tools that would all fail without
a key.
Tighten block_memory_write.sh regex
The old `*/memory/*.md` pattern blocked legitimate paths like
docs/memory/architecture.md. New pattern blocks `*/MEMORY.md` and
`*/.claude/memory/*` only -- the actual surfaces we want to protect.
Opt-in debug logging via MEM0_DEBUG=1
Each hook (bash + python) redirects stderr / adds a FileHandler to
~/.mem0/hooks.log when MEM0_DEBUG is set. No helper module, no
rotation -- KISS. Default behaviour is unchanged.
Drop the duplicate PreCompact registration
hooks.json and cursor-hooks.json had on_pre_compact.sh AND
on_pre_compact.py registered on PreCompact, producing duplicate
session-state writes. Drop the python entry. The python script stays
alive -- on_stop.sh still spawns it as a session-end safety net.
CI nudge
Adds a single comment line to pyproject.toml because the repo's
ci.yml path filters exclude mem0-plugin/-only PRs but the
build_mem0/build_embedchain status checks are required by branch
protection. Track the proper fix (path-conditional CI) as a
follow-up.