Wire fire-and-forget PostHog telemetry into every lifecycle hook
(session_start, stop, pre_compact, task_completed, user_prompt,
post_tool_use) matching the same project key, endpoint, and payload
structure used by the Python SDK, CLI, and OpenClaw.
- 10% sampling on ALL events to keep PostHog costs predictable
- Anonymous distinct_id: MD5(api_key) or SHA-256(username)
- Opt-out via MEM0_TELEMETRY=false
- Platform detection: Claude Code / Cursor / Codex
- Never sends user content, API keys, or raw identifiers
- 16 new tests (110 total passing)
- SessionStart shows "Mem0 Inactive" banner with identity info when no
API key set, instead of silently exiting with zero output
- on_user_prompt.sh fires error/file-path detection even without API key
(local pattern matching, no API needed). Search rubric still gated.
- parse_export_file.py supports '-' argument for stdin piping
Root cause: .mcp.json required ${MEM0_API_KEY} shell env var which
OAuth flow never populates — MCP server never started, only auth
stubs were exposed.
Fix: switch .mcp.json to ${user_config.MEM0_API_KEY} so Claude Code
reads the key from plugin userConfig (system keychain). Add
resolve_api_key() fallback chain (MEM0_API_KEY -> CLAUDE_PLUGIN_OPTION_MEM0_API_KEY)
to all hook scripts. Update onboard skill and setup_coding_categories.py
to handle keychain-only users. Add 3 tests for key resolution.
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.