Files
claude-mem/docs/public/docs.json
Alex Newman 2b223b7cd9 feat: Add dual-tag system for meta-observation control (#153)
* feat: Add dual-tag system for meta-observation control

Implements <private> and <claude-mem-context> tag stripping at hook layer
to give users fine-grained control over what gets persisted in observations
and enable future real-time context injection without recursive storage.

**Features:**
- stripMemoryTags() function in save-hook.ts
- Strips both <private> and <claude-mem-context> tags before sending to worker
- Always active (no configuration needed)
- Comprehensive test suite (19 tests, all passing)
- User documentation for <private> tag
- Technical architecture documentation

**Architecture:**
- Edge processing pattern (filter at hook, not worker)
- Defensive type handling with silentDebug
- Supports multiline, nested, and multiple tags
- Enables strategic orchestration for internal tools

**User-Facing:**
- <private> tag for manual privacy control (documented)
- Prevents sensitive data from persisting in observations

**Infrastructure:**
- <claude-mem-context> tag ready for real-time context feature
- Prevents recursive storage when context injection ships

**Files:**
- src/hooks/save-hook.ts: Core implementation
- tests/strip-memory-tags.test.ts: Test suite (19/19 passing)
- docs/public/usage/private-tags.mdx: User guide
- docs/public/docs.json: Navigation update
- docs/context/dual-tag-system-architecture.md: Technical docs
- plugin/scripts/save-hook.js: Built hook

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: Strip private tags from user prompts and skip memory ops for fully private prompts

Fixes critical privacy bug where <private> tags were not being stripped from
user prompts before storage in user_prompts table, making private content
searchable via mem-search.

Changes:

1. new-hook.ts: Skip memory operations for fully private prompts
   - If cleaned prompt is empty after stripping tags, skip saveUserPrompt
   - Skip worker init to avoid wasting resources on empty prompts
   - Logs: "(fully private - skipped)"

2. save-hook.ts: Skip observations for fully private prompts
   - Check if user prompt was entirely private before creating observations
   - Respects user intent: fully private prompt = no observations at all
   - Prevents "thoughts pop up" issue where private prompts create public observations

3. SessionStore.ts: Add getUserPrompt() method
   - Retrieves prompt text by session_id and prompt_number
   - Used by save-hook to check if prompt was private

4. Tests: Added 4 new tests for fully private prompt detection (16 total, all passing)

5. Docs: Updated private-tags.mdx to reflect correct behavior
   - User prompts ARE now filtered before storage
   - Private content never reaches database or search indices

Privacy Protection:
- Fully private prompts: No user_prompt saved, no worker init, no observations
- Partially private prompts: Tags stripped, content sanitized before storage
- Zero leaks: Private content never indexed or searchable

Addresses reviewer feedback on PR #153 about user prompt filtering.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* feat: Enhance memory tag handling and indexing in user prompts

- Added a new index `idx_user_prompts_lookup` on `user_prompts` for improved query performance based on `claude_session_id` and `prompt_number`.
- Refactored memory tag stripping functionality into dedicated utility functions: `stripMemoryTagsFromJson` and `stripMemoryTagsFromPrompt` for better separation of concerns and reusability.
- Updated hooks (`new-hook.ts` and `save-hook.ts`) to utilize the new tag stripping functions, ensuring private content is not stored or searchable.
- Removed redundant inline tag stripping functions from hooks to streamline code.
- Added tests for the new tag stripping utilities to ensure functionality and prevent regressions.

---------

Co-authored-by: Claude <noreply@anthropic.com>
2025-11-30 22:57:26 -05:00

128 lines
2.9 KiB
JSON

{
"$schema": "https://mintlify.com/schema.json",
"name": "Claude-Mem",
"description": "Persistent memory compression system that preserves context across Claude Code sessions",
"theme": "mint",
"favicon": "/claude-mem-logomark.webp",
"logo": {
"light": "/claude-mem-logo-for-light-mode.webp",
"dark": "/claude-mem-logo-for-dark-mode.webp",
"href": "https://github.com/thedotmack/claude-mem"
},
"colors": {
"primary": "#3B82F6",
"light": "#EFF6FF",
"dark": "#1E40AF"
},
"navbar": {
"links": [
{
"label": "GitHub",
"href": "https://github.com/thedotmack/claude-mem"
}
],
"primary": {
"type": "button",
"label": "Install",
"href": "https://github.com/thedotmack/claude-mem#quick-start"
}
},
"navigation": {
"groups": [
{
"group": "Get Started",
"icon": "rocket",
"pages": [
"introduction",
"installation",
"usage/getting-started",
"usage/search-tools",
"usage/private-tags",
"beta-features"
]
},
{
"group": "Best Practices",
"icon": "lightbulb",
"pages": [
"context-engineering",
"progressive-disclosure"
]
},
{
"group": "Configuration & Development",
"icon": "gear",
"pages": [
"configuration",
"development",
"troubleshooting"
]
},
{
"group": "Architecture",
"icon": "diagram-project",
"pages": [
"architecture/overview",
"architecture-evolution",
"hooks-architecture",
"architecture/hooks",
"architecture/worker-service",
"architecture/database",
"architecture/search-architecture"
]
}
]
},
"footer": {
"socials": {
"github": "https://github.com/thedotmack/claude-mem"
},
"links": [
{
"header": "Resources",
"items": [
{
"label": "Documentation",
"href": "https://github.com/thedotmack/claude-mem"
},
{
"label": "Issues",
"href": "https://github.com/thedotmack/claude-mem/issues"
}
]
},
{
"header": "Legal",
"items": [
{
"label": "License (AGPL-3.0)",
"href": "https://github.com/thedotmack/claude-mem/blob/main/LICENSE"
}
]
}
]
},
"seo": {
"indexing": "all",
"metatags": {
"og:type": "website",
"og:site_name": "Claude-Mem Documentation",
"og:description": "Persistent memory compression system that preserves context across Claude Code sessions"
}
},
"contextual": {
"options": [
"copy",
"view",
"chatgpt",
"claude",
"cursor"
]
},
"integrations": {
"telemetry": {
"enabled": false
}
}
}